1use anyhow::Context;
5use eframe::{emath::Rect, epaint::Stroke, epaint::textures::TextureOptions};
6use egui::{
7 Color32, FontData, FontDefinitions, FontId, Frame, PointerButton, Pos2, Ui, Vec2, text::CCursor,
8};
9use json::JsonValue;
10use kira::{
11 AudioManager, AudioManagerSettings, DefaultBackend, sound::static_sound::StaticSoundData,
12};
13use std::{
14 collections::HashMap,
15 fs::{self, File},
16 io::Read,
17 path::{Path, PathBuf},
18 sync::Arc,
19 time::Instant,
20 vec::Vec,
21};
22use tray_icon::{Icon, TrayIconBuilder, menu::Menu};
23
24pub fn load_icon_from_file(path: &str) -> Result<Icon, Box<dyn std::error::Error>> {
26 let image = image::open(path)?.into_rgba8();
27 let (width, height) = image.dimensions();
28 let rgba = image.into_raw();
29 Ok(Icon::from_rgba(rgba, width, height)?)
30}
31
32pub fn create_json<P: AsRef<Path>>(path: P, data: JsonValue) -> anyhow::Result<()> {
34 let parent_dir = path
35 .as_ref()
36 .parent()
37 .ok_or_else(|| anyhow::anyhow!("Invalid file path."))?;
38
39 fs::create_dir_all(parent_dir)?;
41
42 let formatted = json::stringify_pretty(data, 4);
44
45 fs::write(path, formatted)?;
47 Ok(())
48}
49
50pub fn copy_and_reformat_json<P: AsRef<Path>>(src: P, dest: P) -> anyhow::Result<()> {
52 let content = fs::read_to_string(&src)?;
54
55 let parsed = json::parse(&content)?;
57
58 create_json(dest, parsed)?;
60
61 Ok(())
62}
63
64pub fn check_file_exists<P: AsRef<Path>>(path: P) -> bool {
66 let path_ref = path.as_ref();
67 if path_ref.exists() {
68 true } else {
70 false
72 }
73}
74
75pub fn write_to_json<P: AsRef<Path>>(path: P, data: JsonValue) -> anyhow::Result<()> {
77 let parent_dir = path
78 .as_ref()
79 .parent()
80 .ok_or_else(|| anyhow::anyhow!("Invalid file path."))?;
81
82 fs::create_dir_all(parent_dir)?;
83 let formatted = json::stringify_pretty(data, 4);
84 fs::write(path, formatted)?;
85 Ok(())
86}
87
88pub fn read_from_json<P: AsRef<Path>>(path: P) -> anyhow::Result<JsonValue> {
90 let content = fs::read_to_string(&path)
91 .with_context(|| format!("Cannot read the file: {}", path.as_ref().display()))?;
92 json::parse(&content)
93 .with_context(|| format!("Failed to parse JSON: {}", path.as_ref().display()))
94}
95
96pub fn play_wav(path: &str) -> anyhow::Result<f64> {
98 let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
99 let sound_data = StaticSoundData::from_file(path)?;
100 let duration = sound_data.duration().as_secs_f64();
101 manager.play(sound_data)?;
102 std::thread::sleep(std::time::Duration::from_secs_f64(duration));
103 Ok(duration)
104}
105
106pub fn general_click_feedback(sound_path: &str) {
108 let sound_path = sound_path.to_string();
109 std::thread::spawn(move || {
110 play_wav(&sound_path).unwrap_or(0_f64);
111 });
112}
113
114pub fn count_files_recursive(dir: &Path, target: &str) -> std::io::Result<usize> {
116 let mut count = 0;
117 if dir.is_dir() {
118 for entry in fs::read_dir(dir)? {
119 let entry = entry?;
120 let path = entry.path();
121 if path.is_dir() {
122 count += count_files_recursive(&path, target)?;
123 } else if path.file_name().unwrap().to_string_lossy().contains(target) {
124 count += 1;
125 }
126 }
127 }
128 Ok(count)
129}
130
131pub fn list_files_recursive(path: &Path, prefix: &str) -> Result<Vec<PathBuf>, std::io::Error> {
133 let mut matches = Vec::new();
134
135 for entry in std::fs::read_dir(path)? {
136 let entry = entry?;
138 let path = entry.path();
139
140 if path.is_dir() {
141 matches.extend(list_files_recursive(&path, prefix)?);
143 } else if let Some(file_name) = path.file_name() {
144 if file_name.to_string_lossy().contains(prefix) {
145 matches.push(path);
146 }
147 }
148 }
149
150 Ok(matches)
151}
152
153#[derive(Debug, Clone)]
155pub struct Config {
156 pub language: u8,
158 pub amount_languages: u8,
160 pub rc_strict_mode: bool,
162 pub problem_report_sound: String,
164}
165
166impl Config {
167 pub fn from_json_value(value: &JsonValue) -> Option<Config> {
168 Some(Config {
169 language: value["language"].as_u8()?,
170 amount_languages: value["amount_languages"].as_u8()?,
171 rc_strict_mode: value["rc_strict_mode"].as_bool()?,
172 problem_report_sound: value["problem_report_sound"].as_str()?.to_string(),
173 })
174 }
175
176 pub fn to_json_value(&self) -> JsonValue {
177 json::object! {
178 language: self.language,
179 amount_languages: self.amount_languages,
180 rc_strict_mode: self.rc_strict_mode,
181 }
182 }
183}
184
185#[derive(Debug, Clone)]
187pub struct GameText {
188 pub game_text: HashMap<String, Vec<String>>,
189}
190
191impl GameText {
192 pub fn from_json_value(value: &JsonValue) -> Option<GameText> {
193 if !value["game_text"].is_object() {
195 return None;
196 }
197
198 let mut parsed = HashMap::new();
200 for (key, val) in value["game_text"].entries() {
201 if let JsonValue::Array(arr) = val {
202 let str_vec: Vec<String> = arr
203 .iter()
204 .filter_map(|v| v.as_str().map(String::from))
205 .collect();
206 parsed.insert(key.to_string(), str_vec);
207 }
208 }
209
210 Some(GameText { game_text: parsed })
211 }
212}
213
214#[derive(Clone, Debug)]
216pub enum Value {
217 Bool(bool),
218 Int(i32),
219 UInt(u32),
220 Float(f32),
221 Vec(Vec<Value>),
222 String(String),
223}
224
225impl From<bool> for Value {
226 fn from(b: bool) -> Self {
227 Value::Bool(b)
228 }
229}
230
231impl From<i32> for Value {
232 fn from(i: i32) -> Self {
233 Value::Int(i)
234 }
235}
236
237impl From<u32> for Value {
238 fn from(u: u32) -> Self {
239 Value::UInt(u)
240 }
241}
242
243impl From<f32> for Value {
244 fn from(f: f32) -> Self {
245 Value::Float(f)
246 }
247}
248
249impl<T: Into<Value>> From<Vec<T>> for Value {
250 fn from(v: Vec<T>) -> Self {
251 Value::Vec(v.into_iter().map(|x| x.into()).collect())
252 }
253}
254
255impl From<String> for Value {
256 fn from(s: String) -> Self {
257 Value::String(s)
258 }
259}
260
261#[derive(Clone, Debug)]
263pub struct ReportState {
264 pub current_page: String,
266 pub current_total_runtime: f32,
268 pub current_page_runtime: f32,
270}
271
272#[derive(Clone, Debug)]
274pub struct Problem {
275 pub severity_level: SeverityLevel,
277 pub problem: String,
279 pub annotation: String,
281 pub report_state: ReportState,
283 pub problem_type: RustConstructorError,
285}
286
287#[derive(Clone, Debug)]
289pub enum SeverityLevel {
290 MildWarning,
292 SevereWarning,
294 Error,
296}
297
298pub trait RustConstructorResource {
300 fn name(&self) -> &str;
302
303 fn expose_type(&self) -> &str;
305
306 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>);
308
309 fn match_resource(&self, resource_name: &str, resource_type: &str) -> bool {
311 resource_name == self.name() && resource_type == self.expose_type()
312 }
313}
314
315impl RustConstructorResource for PageData {
316 fn name(&self) -> &str {
317 &self.name
318 }
319
320 fn expose_type(&self) -> &str {
321 &self.discern_type
322 }
323
324 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
325 render_list.push(RenderResource {
326 discern_type: self.expose_type().to_string(),
327 name: self.name.to_string(),
328 });
329 }
330}
331
332#[derive(Clone, Debug)]
334pub struct PageData {
335 pub discern_type: String,
336 pub name: String,
337 pub forced_update: bool,
339 pub change_page_updated: bool,
341 pub enter_page_updated: bool,
343}
344
345#[derive(Clone, Debug)]
347pub struct Timer {
348 pub start_time: f32,
350 pub total_time: f32,
352 pub timer: Instant,
354 pub now_time: f32,
356}
357
358impl RustConstructorResource for ImageTexture {
359 fn name(&self) -> &str {
360 &self.name
361 }
362
363 fn expose_type(&self) -> &str {
364 &self.discern_type
365 }
366
367 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
368 render_list.push(RenderResource {
369 discern_type: self.expose_type().to_string(),
370 name: self.name.to_string(),
371 });
372 }
373}
374
375#[derive(Clone)]
377pub struct ImageTexture {
378 pub discern_type: String,
379 pub name: String,
380 pub texture: Option<egui::TextureHandle>,
382 pub cite_path: String,
384}
385
386impl RustConstructorResource for CustomRect {
387 fn name(&self) -> &str {
388 &self.name
389 }
390
391 fn expose_type(&self) -> &str {
392 &self.discern_type
393 }
394
395 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
396 render_list.push(RenderResource {
397 discern_type: self.expose_type().to_string(),
398 name: self.name.to_string(),
399 });
400 }
401}
402
403#[derive(Clone, Debug)]
405pub struct CustomRect {
406 pub discern_type: String,
407 pub name: String,
408 pub position: [f32; 2],
410 pub size: [f32; 2],
412 pub rounding: f32,
414 pub x_grid: [u32; 2],
416 pub y_grid: [u32; 2],
418 pub center_display: (HorizontalAlign, VerticalAlign),
420 pub color: [u8; 4],
422 pub border_width: f32,
424 pub border_color: [u8; 4],
426 pub origin_position: [f32; 2],
428}
429
430impl RustConstructorResource for Image {
431 fn name(&self) -> &str {
432 &self.name
433 }
434
435 fn expose_type(&self) -> &str {
436 &self.discern_type
437 }
438
439 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
440 render_list.push(RenderResource {
441 discern_type: self.expose_type().to_string(),
442 name: self.name.to_string(),
443 });
444 }
445}
446
447#[derive(Clone)]
449pub struct Image {
450 pub discern_type: String,
451 pub name: String,
452 pub image_texture: Option<egui::TextureHandle>,
454 pub image_position: [f32; 2],
456 pub image_size: [f32; 2],
458 pub x_grid: [u32; 2],
460 pub y_grid: [u32; 2],
462 pub center_display: (HorizontalAlign, VerticalAlign),
464 pub alpha: u8,
466 pub overlay_color: [u8; 4],
468 pub use_overlay_color: bool,
470 pub origin_position: [f32; 2],
472 pub cite_texture: String,
474 pub last_frame_cite_texture: String,
476}
477
478impl RustConstructorResource for Text {
479 fn name(&self) -> &str {
480 &self.name
481 }
482
483 fn expose_type(&self) -> &str {
484 &self.discern_type
485 }
486
487 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
488 render_list.push(RenderResource {
489 discern_type: self.expose_type().to_string(),
490 name: self.name.to_string(),
491 });
492 }
493}
494
495#[derive(Clone, Debug)]
497pub struct Text {
498 pub discern_type: String,
499 pub name: String,
500 pub text_content: String,
502 pub font_size: f32,
504 pub rgba: [u8; 4],
506 pub position: [f32; 2],
508 pub center_display: (HorizontalAlign, VerticalAlign),
510 pub wrap_width: f32,
512 pub write_background: bool,
514 pub background_rgb: [u8; 4],
516 pub rounding: f32,
518 pub x_grid: [u32; 2],
520 pub y_grid: [u32; 2],
522 pub origin_position: [f32; 2],
524 pub font: String,
526 pub selection: Option<(usize, usize)>,
528 pub selectable: bool,
530 pub hyperlink_text: Vec<(usize, usize, String)>,
532}
533
534impl RustConstructorResource for ScrollBackground {
535 fn name(&self) -> &str {
536 &self.name
537 }
538
539 fn expose_type(&self) -> &str {
540 &self.discern_type
541 }
542
543 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
544 render_list.push(RenderResource {
545 discern_type: self.expose_type().to_string(),
546 name: self.name.to_string(),
547 });
548 }
549}
550
551#[derive(Clone, Debug)]
553pub struct ScrollBackground {
554 pub discern_type: String,
555 pub name: String,
556 pub image_name: Vec<String>,
558 pub horizontal_or_vertical: bool,
560 pub left_and_top_or_right_and_bottom: bool,
563 pub scroll_speed: u32,
565 pub boundary: f32,
567 pub resume_point: f32,
569}
570
571impl RustConstructorResource for Variable {
572 fn name(&self) -> &str {
573 &self.name
574 }
575
576 fn expose_type(&self) -> &str {
577 &self.discern_type
578 }
579
580 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
581 render_list.push(RenderResource {
582 discern_type: self.expose_type().to_string(),
583 name: self.name.to_string(),
584 });
585 }
586}
587
588#[derive(Clone, Debug)]
590pub struct Variable {
591 pub discern_type: String,
592 pub name: String,
593 pub value: Value,
595}
596
597#[derive(Clone, Debug)]
599pub struct Font {
600 pub name: String,
601 pub discern_type: String,
602 pub font_definitions: FontDefinitions,
604 pub path: String,
606}
607
608impl RustConstructorResource for Font {
609 fn name(&self) -> &str {
610 &self.name
611 }
612
613 fn expose_type(&self) -> &str {
614 &self.discern_type
615 }
616
617 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
618 render_list.push(RenderResource {
619 discern_type: self.expose_type().to_string(),
620 name: self.name.to_string(),
621 });
622 }
623}
624
625impl RustConstructorResource for SplitTime {
626 fn name(&self) -> &str {
627 &self.name
628 }
629
630 fn expose_type(&self) -> &str {
631 &self.discern_type
632 }
633
634 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
635 render_list.push(RenderResource {
636 discern_type: self.expose_type().to_string(),
637 name: self.name.to_string(),
638 });
639 }
640}
641
642#[derive(Clone, Debug)]
644pub struct SplitTime {
645 pub discern_type: String,
646 pub name: String,
647 pub time: [f32; 2],
649}
650
651impl RustConstructorResource for Switch {
652 fn name(&self) -> &str {
653 &self.name
654 }
655
656 fn expose_type(&self) -> &str {
657 &self.discern_type
658 }
659
660 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
661 render_list.push(RenderResource {
662 discern_type: self.expose_type().to_string(),
663 name: self.name.to_string(),
664 });
665 }
666}
667
668#[derive(Clone, Debug)]
670pub struct Switch {
671 pub discern_type: String,
672 pub name: String,
673 pub appearance: Vec<SwitchData>,
675 pub switch_image_name: String,
677 pub enable_hover_click_image: [bool; 2],
679 pub state: u32,
681 pub click_method: Vec<SwitchClickAction>,
683 pub last_time_hovered: bool,
685 pub last_time_clicked: bool,
687 pub last_time_clicked_index: usize,
689 pub animation_count: u32,
691 pub hint_text_name: String,
693 pub text_name: String,
695 pub text_origin_position: [f32; 2],
697 pub sound_path: String,
699}
700
701#[derive(Clone, Debug)]
703pub struct RenderResource {
704 pub discern_type: String,
705 pub name: String,
706}
707
708#[derive(Clone, Debug)]
710pub struct SwitchData {
711 pub texture: String,
713 pub color: [u8; 4],
715 pub text: String,
717 pub hint_text: String,
719}
720
721#[derive(Clone, Debug)]
723pub struct SwitchClickAction {
724 pub click_method: PointerButton,
726 pub action: bool,
728}
729
730#[derive(Clone, Debug)]
732pub struct MessageBox {
733 pub discern_type: String,
734 pub name: String,
735 pub box_size: [f32; 2],
737 pub box_content_name: String,
739 pub box_title_name: String,
741 pub box_image_name: String,
743 pub box_keep_existing: bool,
745 pub box_existing_time: f32,
747 pub box_exist: bool,
749 pub box_speed: f32,
751 pub box_restore_speed: f32,
753 pub box_memory_offset: f32,
755}
756
757impl RustConstructorResource for MessageBox {
758 fn name(&self) -> &str {
759 &self.name
760 }
761
762 fn expose_type(&self) -> &str {
763 &self.discern_type
764 }
765
766 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
767 render_list.push(RenderResource {
768 discern_type: self.expose_type().to_string(),
769 name: self.name.to_string(),
770 });
771 }
772}
773
774#[derive(Clone)]
776pub enum RCR {
777 Image(Image),
778 Text(Text),
779 CustomRect(CustomRect),
780 ScrollBackground(ScrollBackground),
781 Variable(Variable),
782 Font(Font),
783 SplitTime(SplitTime),
784 Switch(Switch),
785 MessageBox(MessageBox),
786 ImageTexture(ImageTexture),
787 PageData(PageData),
788}
789
790#[derive(Clone, Debug)]
792pub enum RustConstructorError {
793 ImageGetFailed { image_path: String },
795 ImageNotFound { image_name: String },
797 TextNotFound { text_name: String },
799 VariableNotFound { variable_name: String },
801 VariableNotInt { variable_name: String },
803 VariableNotUInt { variable_name: String },
805 VariableNotFloat { variable_name: String },
807 VariableNotVec { variable_name: String },
809 VariableNotBool { variable_name: String },
811 VariableNotString { variable_name: String },
813 SplitTimeNotFound { split_time_name: String },
815 SwitchAppearanceMismatch { switch_name: String, differ: u32 },
817 SwitchNotFound { switch_name: String },
819 MessageBoxAlreadyExists { message_box_name: String },
821 FontGetFailed { font_path: String },
823 FontNotFound { font_name: String },
825 ResourceNotFound {
827 resource_name: String,
828 resource_type: String,
829 },
830 PageNotFound { page_name: String },
832}
833
834#[derive(Debug, Clone, Copy)]
836pub enum HorizontalAlign {
837 Left,
838 Center,
839 Right,
840}
841
842#[derive(Debug, Clone, Copy)]
844pub enum VerticalAlign {
845 Top,
846 Center,
847 Bottom,
848}
849
850#[derive(Clone)]
852pub struct App {
853 pub config: Config,
855 pub game_text: GameText,
857 pub rust_constructor_resource: Vec<RCR>,
859 pub render_resource_list: Vec<RenderResource>,
861 pub problem_list: Vec<Problem>,
863 pub frame: Frame,
865 pub vertrefresh: f32,
867 pub page: String,
869 pub timer: Timer,
871 pub frame_times: Vec<f32>,
873 pub last_frame_time: Option<f64>,
875 pub tray_icon: Option<tray_icon::TrayIcon>,
877 pub tray_icon_created: bool,
879}
880
881impl App {
882 pub fn new(config_path: &str, game_text_path: &str) -> Self {
884 let mut config = Config {
885 language: 0,
886 amount_languages: 0,
887 rc_strict_mode: false,
888 problem_report_sound: String::new(),
889 };
890 let mut game_text = GameText {
891 game_text: HashMap::new(),
892 };
893 if let Ok(json_value) = read_from_json(config_path) {
894 if let Some(read_config) = Config::from_json_value(&json_value) {
895 config = read_config;
896 }
897 }
898 if let Ok(json_value) = read_from_json(game_text_path) {
899 if let Some(read_game_text) = GameText::from_json_value(&json_value) {
900 game_text = read_game_text;
901 }
902 }
903 Self {
904 config,
905 game_text,
906 rust_constructor_resource: vec![],
907 render_resource_list: Vec::new(),
908 problem_list: Vec::new(),
909 frame: Frame {
910 ..Default::default()
911 },
912 vertrefresh: 0.01,
913 page: "Launch".to_string(),
914 timer: Timer {
915 start_time: 0.0,
916 total_time: 0.0,
917 timer: Instant::now(),
918 now_time: 0.0,
919 },
920 frame_times: Vec::new(),
921 last_frame_time: None,
922 tray_icon: None,
923 tray_icon_created: false,
924 }
925 }
926
927 pub fn add_page(&mut self, name: &str, forced_update: bool) {
929 self.rust_constructor_resource.push(RCR::PageData(PageData {
930 discern_type: "PageData".to_string(),
931 name: name.to_string(),
932 forced_update,
933 change_page_updated: false,
934 enter_page_updated: false,
935 }));
936 }
937
938 pub fn switch_page(&mut self, page: &str) {
940 if let Ok(id) = self.get_resource_index("PageData", page) {
941 self.page = page.to_string();
942 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
943 pd.enter_page_updated = false;
944 self.timer.start_time = self.timer.total_time;
945 self.update_timer();
946 };
947 };
948 }
949
950 pub fn tray_icon_init(&mut self, icon_path: &str, tooltip: &str, menu: Box<Menu>) {
952 let icon = load_icon_from_file(icon_path).unwrap();
953 if let Ok(tray_icon) = TrayIconBuilder::new()
954 .with_menu(menu)
955 .with_tooltip(tooltip)
956 .with_icon(icon)
957 .with_icon_as_template(true)
958 .build()
959 {
960 self.tray_icon = Some(tray_icon);
961 self.tray_icon_created = true;
962 };
963 }
964
965 pub fn check_resource_exists(&mut self, resource_type: &str, resource_name: &str) -> bool {
967 for i in 0..self.rust_constructor_resource.len() {
968 match self.rust_constructor_resource[i].clone() {
969 RCR::Image(im) => {
970 if im.match_resource(resource_name, resource_type) {
971 return true;
972 }
973 }
974 RCR::Text(t) => {
975 if t.match_resource(resource_name, resource_type) {
976 return true;
977 }
978 }
979 RCR::CustomRect(cr) => {
980 if cr.match_resource(resource_name, resource_type) {
981 return true;
982 }
983 }
984 RCR::ScrollBackground(sb) => {
985 if sb.match_resource(resource_name, resource_type) {
986 return true;
987 }
988 }
989 RCR::Variable(v) => {
990 if v.match_resource(resource_name, resource_type) {
991 return true;
992 }
993 }
994 RCR::Font(f) => {
995 if f.match_resource(resource_name, resource_type) {
996 return true;
997 }
998 }
999 RCR::SplitTime(st) => {
1000 if st.match_resource(resource_name, resource_type) {
1001 return true;
1002 }
1003 }
1004 RCR::Switch(s) => {
1005 if s.match_resource(resource_name, resource_type) {
1006 return true;
1007 }
1008 }
1009 RCR::MessageBox(mb) => {
1010 if mb.match_resource(resource_name, resource_type) {
1011 return true;
1012 }
1013 }
1014 RCR::ImageTexture(it) => {
1015 if it.match_resource(resource_name, resource_type) {
1016 return true;
1017 }
1018 }
1019 RCR::PageData(pd) => {
1020 if pd.match_resource(resource_name, resource_type) {
1021 return true;
1022 }
1023 }
1024 }
1025 }
1026 false
1027 }
1028
1029 pub fn get_resource_index(
1031 &mut self,
1032 resource_type: &str,
1033 resource_name: &str,
1034 ) -> Result<usize, RustConstructorError> {
1035 for i in 0..self.rust_constructor_resource.len() {
1036 match self.rust_constructor_resource[i].clone() {
1037 RCR::Image(im) => {
1038 if im.match_resource(resource_name, resource_type) {
1039 return Ok(i);
1040 }
1041 }
1042 RCR::Text(t) => {
1043 if t.match_resource(resource_name, resource_type) {
1044 return Ok(i);
1045 }
1046 }
1047 RCR::CustomRect(cr) => {
1048 if cr.match_resource(resource_name, resource_type) {
1049 return Ok(i);
1050 }
1051 }
1052 RCR::ScrollBackground(sb) => {
1053 if sb.match_resource(resource_name, resource_type) {
1054 return Ok(i);
1055 }
1056 }
1057 RCR::Variable(v) => {
1058 if v.match_resource(resource_name, resource_type) {
1059 return Ok(i);
1060 }
1061 }
1062 RCR::Font(f) => {
1063 if f.match_resource(resource_name, resource_type) {
1064 return Ok(i);
1065 }
1066 }
1067 RCR::SplitTime(st) => {
1068 if st.match_resource(resource_name, resource_type) {
1069 return Ok(i);
1070 }
1071 }
1072 RCR::Switch(s) => {
1073 if s.match_resource(resource_name, resource_type) {
1074 return Ok(i);
1075 }
1076 }
1077 RCR::MessageBox(mb) => {
1078 if mb.match_resource(resource_name, resource_type) {
1079 return Ok(i);
1080 }
1081 }
1082 RCR::ImageTexture(it) => {
1083 if it.match_resource(resource_name, resource_type) {
1084 return Ok(i);
1085 }
1086 }
1087 RCR::PageData(pd) => {
1088 if pd.match_resource(resource_name, resource_type) {
1089 return Ok(i);
1090 }
1091 }
1092 };
1093 }
1094 self.problem_report(
1095 RustConstructorError::ResourceNotFound {
1096 resource_name: resource_name.to_string(),
1097 resource_type: resource_type.to_string(),
1098 },
1099 SeverityLevel::SevereWarning,
1100 );
1101 Err(RustConstructorError::ResourceNotFound {
1102 resource_name: resource_name.to_string(),
1103 resource_type: resource_type.to_string(),
1104 })
1105 }
1106
1107 pub fn add_fonts(&mut self, font_name: &str, font_path: &str) {
1109 let mut fonts = FontDefinitions::default();
1110 if let Ok(font_read_data) = std::fs::read(font_path) {
1111 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
1112 fonts.font_data.insert(
1113 font_name.to_owned(),
1114 Arc::new(FontData::from_owned(
1115 Arc::try_unwrap(font_data).ok().unwrap(),
1116 )),
1117 );
1118
1119 fonts
1121 .families
1122 .entry(egui::FontFamily::Proportional)
1123 .or_default()
1124 .insert(0, font_name.to_owned());
1125
1126 fonts
1127 .families
1128 .entry(egui::FontFamily::Monospace)
1129 .or_default()
1130 .insert(0, font_name.to_owned());
1131
1132 self.rust_constructor_resource.push(RCR::Font(Font {
1133 name: font_name.to_string(),
1134 discern_type: "Font".to_string(),
1135 font_definitions: fonts,
1136 path: font_path.to_string(),
1137 }));
1138 } else {
1139 self.problem_report(
1140 RustConstructorError::FontGetFailed {
1141 font_path: font_path.to_string(),
1142 },
1143 SeverityLevel::SevereWarning,
1144 );
1145 };
1146 }
1149
1150 pub fn font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
1152 if let Ok(id) = self.get_resource_index("Font", name) {
1153 if let RCR::Font(f) = &mut self.rust_constructor_resource[id] {
1154 return Ok(f.font_definitions.clone());
1155 }
1156 }
1157 self.problem_report(
1158 RustConstructorError::FontNotFound {
1159 font_name: name.to_string(),
1160 },
1161 SeverityLevel::SevereWarning,
1162 );
1163 Err(RustConstructorError::FontNotFound {
1164 font_name: name.to_string(),
1165 })
1166 }
1167
1168 pub fn register_all_fonts(&mut self, ctx: &egui::Context) {
1170 let mut font_definitions = egui::FontDefinitions::default();
1171 let mut font_resources = Vec::new();
1172 for i in 0..self.rust_constructor_resource.len() {
1173 if let RCR::Font(f) = &self.rust_constructor_resource[i] {
1174 font_resources.push(f.clone());
1175 };
1176 }
1177 for i in &font_resources {
1178 let font_name = i.name.clone();
1179 if let Ok(font_def) = self.font(&font_name) {
1181 if let Some(font_data) = font_def.font_data.get(&font_name) {
1183 font_definitions
1184 .font_data
1185 .insert(font_name.clone(), Arc::clone(font_data));
1186 font_definitions
1187 .families
1188 .entry(egui::FontFamily::Name(font_name.clone().into()))
1189 .or_default()
1190 .push(font_name.clone());
1191 };
1192
1193 font_definitions
1195 .families
1196 .entry(egui::FontFamily::Proportional)
1197 .or_default()
1198 .insert(0, font_name.to_owned());
1199
1200 font_definitions
1201 .families
1202 .entry(egui::FontFamily::Monospace)
1203 .or_default()
1204 .insert(0, font_name.to_owned());
1205 };
1206 }
1207 ctx.set_fonts(font_definitions);
1208 }
1209
1210 pub fn problem_report(
1212 &mut self,
1213 problem_type: RustConstructorError,
1214 severity_level: SeverityLevel,
1215 ) {
1216 let (problem, annotation) = match problem_type.clone() {
1217 RustConstructorError::FontGetFailed { font_path } => (
1218 format!("Font get failed: {}", font_path,),
1219 "Please check if the font file exists and the path is correct.",
1220 ),
1221 RustConstructorError::FontNotFound { font_name } => (
1222 format!("Font not found: {}", font_name,),
1223 "Please check whether the font has been added.",
1224 ),
1225 RustConstructorError::ImageGetFailed { image_path } => (
1226 format!("Image get failed: {}", image_path,),
1227 "Please check whether the image path is correct and whether the image has been added.",
1228 ),
1229 RustConstructorError::ImageNotFound { image_name } => (
1230 format!("Image not found: {}", image_name,),
1231 "Please check whether the image has been added.",
1232 ),
1233 RustConstructorError::TextNotFound { text_name } => (
1234 format!("Text not found: {}", text_name,),
1235 "Please check whether the text has been added.",
1236 ),
1237 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
1238 format!("Message box already exists: {}", message_box_name),
1239 "Please check whether the code for generating the message box has been accidentally called multiple times.",
1240 ),
1241 RustConstructorError::SplitTimeNotFound { split_time_name } => (
1242 format!("Split time not found: {}", split_time_name,),
1243 "Please check whether the split time has been added.",
1244 ),
1245 RustConstructorError::SwitchAppearanceMismatch {
1246 switch_name,
1247 differ,
1248 } => (
1249 format!(
1250 "Switch appearance list's number of items is large / small {} more: {}",
1251 differ, switch_name
1252 ),
1253 "Please check whether the number of appearance list items matches the number of enabled animations.",
1254 ),
1255 RustConstructorError::SwitchNotFound { switch_name } => (
1256 format!("Switch not found: {}", switch_name,),
1257 "Please check whether the switch has been added.",
1258 ),
1259 RustConstructorError::PageNotFound { page_name } => (
1260 format!("Page not found: {}", page_name,),
1261 "Please check whether the page has been added.",
1262 ),
1263 RustConstructorError::VariableNotFound { variable_name } => (
1264 format!("Variable not found: {}", variable_name,),
1265 "Please check whether the variable has been added.",
1266 ),
1267 RustConstructorError::VariableNotBool { variable_name } => (
1268 format!("Variable is not bool: {}", variable_name,),
1269 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1270 ),
1271 RustConstructorError::VariableNotFloat { variable_name } => (
1272 format!("Variable is not f32: {}", variable_name,),
1273 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1274 ),
1275 RustConstructorError::VariableNotInt { variable_name } => (
1276 format!("Variable is not int: {}", variable_name,),
1277 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1278 ),
1279 RustConstructorError::VariableNotString { variable_name } => (
1280 format!("Variable is not string: {}", variable_name,),
1281 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1282 ),
1283 RustConstructorError::VariableNotUInt { variable_name } => (
1284 format!("Variable is not uint: {}", variable_name,),
1285 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1286 ),
1287 RustConstructorError::VariableNotVec { variable_name } => (
1288 format!("Variable is not vec: {}", variable_name,),
1289 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1290 ),
1291 RustConstructorError::ResourceNotFound {
1292 resource_name,
1293 resource_type,
1294 } => (
1295 format!(
1296 "Resource not found: {}(\"{}\")",
1297 resource_type, resource_name,
1298 ),
1299 "Please check whether the resource has been added.",
1300 ),
1301 };
1302 if self.config.rc_strict_mode {
1304 panic!("{}", problem);
1305 } else {
1306 eprintln!("something goes wrong.");
1307 let sound = self.config.problem_report_sound.clone();
1308 std::thread::spawn(move || {
1309 play_wav(&sound).unwrap_or(0_f64);
1310 });
1311 self.problem_list.push(Problem {
1312 severity_level,
1313 problem,
1314 annotation: annotation.to_string(),
1315 report_state: ReportState {
1316 current_page: self.page.clone(),
1317 current_total_runtime: self.timer.total_time,
1318 current_page_runtime: self.timer.now_time,
1319 },
1320 problem_type: problem_type.clone(),
1321 });
1322 };
1323 }
1324
1325 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
1327 if let Ok(id) = self.get_resource_index("PageData", name) {
1328 if let RCR::PageData(pd) = self.rust_constructor_resource[id].clone() {
1329 if !pd.change_page_updated {
1330 self.new_page_update(name);
1331 };
1332 return Ok(pd.change_page_updated);
1333 };
1334 };
1335 self.problem_report(
1336 RustConstructorError::PageNotFound {
1337 page_name: name.to_string(),
1338 },
1339 SeverityLevel::SevereWarning,
1340 );
1341 Err(RustConstructorError::PageNotFound {
1342 page_name: name.to_string(),
1343 })
1344 }
1345
1346 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
1348 if let Ok(id) = self.get_resource_index("PageData", name) {
1349 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1350 let return_value = pd.enter_page_updated;
1351 pd.enter_page_updated = true;
1352 return Ok(return_value);
1353 };
1354 };
1355 self.problem_report(
1356 RustConstructorError::PageNotFound {
1357 page_name: name.to_string(),
1358 },
1359 SeverityLevel::SevereWarning,
1360 );
1361 Err(RustConstructorError::PageNotFound {
1362 page_name: name.to_string(),
1363 })
1364 }
1365
1366 pub fn new_page_update(&mut self, name: &str) {
1368 if let Ok(id) = self.get_resource_index("PageData", name) {
1369 self.timer.start_time = self.timer.total_time;
1370 self.update_timer();
1371 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1372 pd.change_page_updated = true;
1373 };
1374 };
1375 }
1376
1377 pub fn update_frame_stats(&mut self, ctx: &egui::Context) {
1379 let current_time = ctx.input(|i| i.time);
1380 if let Some(last) = self.last_frame_time {
1381 let delta = (current_time - last) as f32;
1382 self.frame_times.push(delta);
1383 const MAX_SAMPLES: usize = 120;
1384 if self.frame_times.len() > MAX_SAMPLES {
1385 let remove_count = self.frame_times.len() - MAX_SAMPLES;
1386 self.frame_times.drain(0..remove_count);
1387 }
1388 }
1389 self.last_frame_time = Some(current_time);
1390 }
1391
1392 pub fn current_fps(&self) -> f32 {
1394 if self.frame_times.is_empty() {
1395 0.0
1396 } else {
1397 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
1398 }
1399 }
1400
1401 pub fn add_split_time(&mut self, name: &str, reset: bool) {
1403 if reset {
1404 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1405 if let RCR::SplitTime(st) = &mut self.rust_constructor_resource[id] {
1406 st.time = [self.timer.now_time, self.timer.total_time];
1407 };
1408 };
1409 } else {
1410 self.rust_constructor_resource
1411 .push(RCR::SplitTime(SplitTime {
1412 discern_type: "SplitTime".to_string(),
1413 name: name.to_string(),
1414 time: [self.timer.now_time, self.timer.total_time],
1415 }));
1416 };
1417 }
1418
1419 pub fn split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
1421 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1422 if let RCR::SplitTime(st) = self.rust_constructor_resource[id].clone() {
1423 return Ok(st.time);
1424 };
1425 };
1426 self.problem_report(
1427 RustConstructorError::SplitTimeNotFound {
1428 split_time_name: name.to_string(),
1429 },
1430 SeverityLevel::SevereWarning,
1431 );
1432 Err(RustConstructorError::SplitTimeNotFound {
1433 split_time_name: name.to_string(),
1434 })
1435 }
1436
1437 pub fn update_timer(&mut self) {
1439 let elapsed = self.timer.timer.elapsed();
1440 let seconds = elapsed.as_secs();
1441 let milliseconds = elapsed.subsec_millis();
1442 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
1443 self.timer.now_time = self.timer.total_time - self.timer.start_time
1444 }
1445
1446 pub fn add_rect(
1448 &mut self,
1449 name: &str,
1450 position_size_and_rounding: [f32; 5],
1451 grid: [u32; 4],
1452 center_display: (HorizontalAlign, VerticalAlign),
1453 color: [u8; 8],
1454 border_width: f32,
1455 ) {
1456 self.rust_constructor_resource
1457 .push(RCR::CustomRect(CustomRect {
1458 discern_type: "CustomRect".to_string(),
1459 name: name.to_string(),
1460 position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1461 size: [position_size_and_rounding[2], position_size_and_rounding[3]],
1462 rounding: position_size_and_rounding[4],
1463 x_grid: [grid[0], grid[1]],
1464 y_grid: [grid[2], grid[3]],
1465 center_display,
1466 color: [color[0], color[1], color[2], color[3]],
1467 border_width,
1468 border_color: [color[4], color[5], color[6], color[7]],
1469 origin_position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1470 }));
1471 }
1472
1473 pub fn rect(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1475 if let Ok(id) = self.get_resource_index("CustomRect", name) {
1476 if let RCR::CustomRect(cr) = &mut self.rust_constructor_resource[id] {
1477 cr.reg_render_resource(&mut self.render_resource_list);
1478 cr.position[0] = match cr.x_grid[1] {
1479 0 => cr.origin_position[0],
1480 _ => {
1481 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64
1482 * cr.x_grid[0] as f64) as f32
1483 + cr.origin_position[0]
1484 }
1485 };
1486 cr.position[1] = match cr.y_grid[1] {
1487 0 => cr.origin_position[1],
1488 _ => {
1489 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64
1490 * cr.y_grid[0] as f64) as f32
1491 + cr.origin_position[1]
1492 }
1493 };
1494 let pos_x = match cr.center_display.0 {
1495 HorizontalAlign::Left => cr.position[0],
1496 HorizontalAlign::Center => cr.position[0] - cr.size[0] / 2.0,
1497 HorizontalAlign::Right => cr.position[0] - cr.size[0],
1498 };
1499 let pos_y = match cr.center_display.1 {
1500 VerticalAlign::Top => cr.position[1],
1501 VerticalAlign::Center => cr.position[1] - cr.size[1] / 2.0,
1502 VerticalAlign::Bottom => cr.position[1] - cr.size[1],
1503 };
1504 ui.painter().rect(
1505 Rect::from_min_max(
1506 Pos2::new(pos_x, pos_y),
1507 Pos2::new(pos_x + cr.size[0], pos_y + cr.size[1]),
1508 ),
1509 cr.rounding,
1510 Color32::from_rgba_unmultiplied(
1511 cr.color[0],
1512 cr.color[1],
1513 cr.color[2],
1514 cr.color[3],
1515 ),
1516 Stroke {
1517 width: cr.border_width,
1518 color: Color32::from_rgba_unmultiplied(
1519 cr.border_color[0],
1520 cr.border_color[1],
1521 cr.border_color[2],
1522 cr.border_color[3],
1523 ),
1524 },
1525 egui::StrokeKind::Inside,
1526 );
1527 };
1528 };
1529 }
1530
1531 pub fn add_text(
1533 &mut self,
1534 name_content_and_font: [&str; 3],
1535 position_font_size_wrap_width_rounding: [f32; 5],
1536 color: [u8; 8],
1537 center_display_write_background_and_enable_copy: (
1538 HorizontalAlign,
1539 VerticalAlign,
1540 bool,
1541 bool,
1542 ),
1543 grid: [u32; 4],
1544 hyperlink_text: Vec<(usize, usize, &str)>,
1545 ) {
1546 self.rust_constructor_resource.push(RCR::Text(Text {
1547 discern_type: "Text".to_string(),
1548 name: name_content_and_font[0].to_string(),
1549 text_content: name_content_and_font[1].to_string(),
1550 font_size: position_font_size_wrap_width_rounding[2],
1551 rgba: [color[0], color[1], color[2], color[3]],
1552 position: [
1553 position_font_size_wrap_width_rounding[0],
1554 position_font_size_wrap_width_rounding[1],
1555 ],
1556 center_display: (
1557 center_display_write_background_and_enable_copy.0,
1558 center_display_write_background_and_enable_copy.1,
1559 ),
1560 wrap_width: position_font_size_wrap_width_rounding[3],
1561 write_background: center_display_write_background_and_enable_copy.2,
1562 background_rgb: [color[4], color[5], color[6], color[7]],
1563 rounding: position_font_size_wrap_width_rounding[4],
1564 x_grid: [grid[0], grid[1]],
1565 y_grid: [grid[2], grid[3]],
1566 origin_position: [
1567 position_font_size_wrap_width_rounding[0],
1568 position_font_size_wrap_width_rounding[1],
1569 ],
1570 font: name_content_and_font[2].to_string(),
1571 selection: None,
1572 selectable: center_display_write_background_and_enable_copy.3,
1573 hyperlink_text: hyperlink_text
1574 .into_iter()
1575 .map(|(a, b, c)| {
1576 (
1577 a,
1578 if b > name_content_and_font[1].len() {
1579 name_content_and_font[1].len()
1580 } else {
1581 b
1582 },
1583 c.to_string(),
1584 )
1585 })
1586 .collect(),
1587 }));
1588 }
1589
1590 pub fn text(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1592 if let Ok(id) = self.get_resource_index("Text", name) {
1593 if let RCR::Text(mut t) = self.rust_constructor_resource[id].clone() {
1594 t.reg_render_resource(&mut self.render_resource_list);
1595 let galley = ui.fonts(|f| {
1597 f.layout(
1598 t.text_content.to_string(),
1599 if self.check_resource_exists("Font", &t.font.clone()) {
1600 FontId::new(t.font_size, egui::FontFamily::Name(t.font.clone().into()))
1601 } else {
1602 FontId::proportional(t.font_size)
1603 },
1604 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
1605 t.wrap_width,
1606 )
1607 });
1608 let text_size = galley.size();
1609 t.position[0] = match t.x_grid[1] {
1610 0 => t.origin_position[0],
1611 _ => {
1612 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64
1613 * t.x_grid[0] as f64) as f32
1614 + t.origin_position[0]
1615 }
1616 };
1617 t.position[1] = match t.y_grid[1] {
1618 0 => t.origin_position[1],
1619 _ => {
1620 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64
1621 * t.y_grid[0] as f64) as f32
1622 + t.origin_position[1]
1623 }
1624 };
1625 let pos_x = match t.center_display.0 {
1626 HorizontalAlign::Left => t.position[0],
1627 HorizontalAlign::Center => t.position[0] - text_size.x / 2.0,
1628 HorizontalAlign::Right => t.position[0] - text_size.x,
1629 };
1630 let pos_y = match t.center_display.1 {
1631 VerticalAlign::Top => t.position[1],
1632 VerticalAlign::Center => t.position[1] - text_size.y / 2.0,
1633 VerticalAlign::Bottom => t.position[1] - text_size.y,
1634 };
1635 let position = Pos2::new(pos_x, pos_y);
1637
1638 if t.write_background {
1639 let rect = Rect::from_min_size(position, text_size);
1640 ui.painter().rect_filled(
1642 rect,
1643 t.rounding,
1644 Color32::from_rgba_unmultiplied(
1645 t.background_rgb[0],
1646 t.background_rgb[1],
1647 t.background_rgb[2],
1648 t.background_rgb[3],
1649 ),
1650 ); };
1652 ui.painter().galley(
1654 position,
1655 galley.clone(),
1656 Color32::from_rgba_unmultiplied(
1657 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3], ),
1659 );
1660
1661 if t.selectable {
1662 let rect = Rect::from_min_size(
1663 [position[0] - 20_f32, position[1] - 5_f32].into(),
1664 [text_size[0] + 40_f32, text_size[1] + 10_f32].into(),
1665 );
1666
1667 let rect2 = Rect::from_min_size(
1668 [0_f32, 0_f32].into(),
1669 [ctx.available_rect().width(), ctx.available_rect().height()].into(),
1670 );
1671
1672 let response = ui.interact(
1674 rect,
1675 egui::Id::new(format!("text_{}_click_and_drag", t.name)),
1676 egui::Sense::click_and_drag(),
1677 );
1678
1679 let response2 = ui.interact(
1680 rect2,
1681 egui::Id::new(format!("text_{}_total", t.name)),
1682 egui::Sense::click(),
1683 );
1684
1685 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
1687 let relative_pos = pointer_pos - position.to_vec2();
1688 let cursor = galley.cursor_from_pos(relative_pos);
1689 cursor.index
1690 };
1691
1692 if !response.clicked() && response2.clicked() {
1693 t.selection = None;
1694 };
1695
1696 if response.clicked() || response.drag_started() {
1697 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1698 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1699 t.selection = Some((cursor, cursor));
1700 };
1701 response.request_focus();
1702 };
1703
1704 if response.dragged() && t.selection.is_some() {
1705 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1706 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1707 if let Some((start, _)) = t.selection {
1708 t.selection = Some((start, cursor));
1709 };
1710 };
1711 };
1712
1713 if response.has_focus() {
1715 let copy_triggered = ui.input(|input| {
1717 let c_released = input.key_released(egui::Key::C);
1718 let cmd_pressed = input.modifiers.command || input.modifiers.mac_cmd;
1719 let ctrl_pressed = input.modifiers.ctrl;
1720 c_released && (cmd_pressed || ctrl_pressed)
1721 });
1722 if copy_triggered {
1723 if let Some((start, end)) = t.selection {
1724 let (start, end) = (start.min(end), start.max(end));
1725 let chars: Vec<char> = t.text_content.chars().collect();
1726 if start <= chars.len() && end <= chars.len() && start < end {
1727 let selected_text: String = chars[start..end].iter().collect();
1728 ui.ctx().copy_text(selected_text);
1729 };
1730 };
1731 };
1732 };
1733
1734 if let Some((start, end)) = t.selection {
1736 let (start, end) = (start.min(end), start.max(end));
1737 if start != end {
1738 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
1740 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
1741
1742 let start_pos = start_cursor.left_top();
1743 let end_pos = end_cursor.right_top();
1744 if start_pos.y == end_pos.y {
1746 let rows = &galley.rows;
1749 let row_height = if !rows.is_empty() {
1750 if let Some(row) = rows.first() {
1752 row.height()
1753 } else {
1754 text_size.y / t.text_content.lines().count() as f32
1755 }
1756 } else {
1757 text_size.y / t.text_content.lines().count() as f32
1758 };
1759
1760 let selection_rect = Rect::from_min_max(
1761 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1762 Pos2::new(
1763 position.x + end_pos.x,
1764 position.y + start_pos.y + row_height,
1765 ),
1766 );
1767 ui.painter().rect_filled(
1768 selection_rect,
1769 0.0,
1770 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1771 );
1772 } else {
1773 let rows = &galley.rows;
1775 let row_height = if !rows.is_empty() {
1776 rows[0].height()
1777 } else {
1778 text_size.y / t.text_content.lines().count() as f32
1779 };
1780
1781 let selection_top = position.y + start_pos.y.min(end_pos.y);
1783 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
1784
1785 let start_row_index = (start_pos.y / row_height).floor() as usize;
1787 let end_row_index = (end_pos.y / row_height).floor() as usize;
1788 let (first_row_index, last_row_index) =
1789 if start_row_index <= end_row_index {
1790 (start_row_index, end_row_index)
1791 } else {
1792 (end_row_index, start_row_index)
1793 };
1794
1795 for (i, row) in rows.iter().enumerate() {
1796 let row_y = position.y + row_height * i as f32;
1797 let row_bottom = row_y + row_height;
1798 if row_bottom > selection_top && row_y <= selection_bottom {
1800 let left = if i == first_row_index {
1801 position.x + start_pos.x
1803 } else {
1804 position.x + row.rect().min.x
1806 };
1807
1808 let right = if i == last_row_index {
1809 position.x + end_pos.x
1811 } else {
1812 position.x + row.rect().max.x
1814 };
1815
1816 let selection_rect = Rect::from_min_max(
1817 Pos2::new(left, row_y),
1818 Pos2::new(right, row_bottom),
1819 );
1820
1821 if selection_rect.width() > 0.0
1823 && selection_rect.height() > 0.0
1824 {
1825 ui.painter().rect_filled(
1826 selection_rect,
1827 0.0,
1828 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1829 );
1830 };
1831 };
1832 }
1833 };
1834 };
1835 };
1836 };
1837
1838 for (start, end, url) in &t.hyperlink_text {
1840 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
1842 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
1843
1844 let start_pos = start_cursor.left_top();
1845 let end_pos = end_cursor.right_top();
1846
1847 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1848
1849 let link_responses = if start_cursor.min.y == end_cursor.min.y {
1851 let link_rect = Rect::from_min_max(
1853 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1854 Pos2::new(
1855 position.x + end_pos.x,
1856 position.y + start_pos.y + row_height,
1857 ),
1858 );
1859 vec![ui.interact(
1860 link_rect,
1861 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
1862 egui::Sense::click(),
1863 )]
1864 } else {
1865 let start_row = (start_pos.y / row_height).round() as usize;
1867 let end_row = (end_pos.y / row_height).round() as usize;
1868 let mut responses = Vec::new();
1869
1870 for row in start_row..=end_row {
1871 if let Some(current_row) = galley.rows.get(row) {
1872 let row_rect = current_row.rect();
1873 let row_y = position.y + row as f32 * row_height;
1874
1875 let link_rect = if row == start_row {
1876 Rect::from_min_max(
1878 Pos2::new(position.x + start_pos.x, row_y),
1879 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1880 )
1881 } else if row == end_row {
1882 Rect::from_min_max(
1884 Pos2::new(position.x + row_rect.min.x, row_y),
1885 Pos2::new(position.x + end_pos.x, row_y + row_height),
1886 )
1887 } else {
1888 Rect::from_min_max(
1890 Pos2::new(position.x + row_rect.min.x, row_y),
1891 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1892 )
1893 };
1894
1895 responses.push(ui.interact(
1896 link_rect,
1897 egui::Id::new(format!(
1898 "link_{}_{}_{}_row_{}",
1899 t.name, start, end, row
1900 )),
1901 egui::Sense::click(),
1902 ));
1903 };
1904 }
1905 responses
1906 };
1907
1908 let mut is_pressing_link = false;
1910 for link_response in &link_responses {
1911 if link_response.is_pointer_button_down_on()
1912 && !link_response.drag_started()
1913 {
1914 t.selection = None;
1915 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1916 let relative_pos = pointer_pos - position.to_vec2();
1917 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1918 if cursor.index >= *start && cursor.index <= *end {
1919 is_pressing_link = true;
1920 break;
1921 };
1922 };
1923 };
1924 }
1925
1926 let mut clicked_on_link = false;
1928 for link_response in &link_responses {
1929 if link_response.clicked() {
1930 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1931 let relative_pos = pointer_pos - position.to_vec2();
1932 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1933 if cursor.index >= *start && cursor.index <= *end {
1934 clicked_on_link = true;
1935 break;
1936 };
1937 };
1938 };
1939 }
1940
1941 if clicked_on_link {
1942 if !url.is_empty() {
1944 ui.ctx().open_url(egui::OpenUrl::new_tab(url));
1945 };
1946 };
1947
1948 if is_pressing_link {
1950 if start_cursor.min.y == end_cursor.min.y {
1951 let selection_rect = Rect::from_min_max(
1953 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1954 Pos2::new(
1955 position.x + end_pos.x,
1956 position.y
1957 + start_pos.y
1958 + galley.rows.first().map_or(14.0, |row| row.height()),
1959 ),
1960 );
1961 ui.painter().rect_filled(
1962 selection_rect,
1963 0.0,
1964 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1965 );
1966 } else {
1967 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1969 let start_row = (start_pos.y / row_height).round() as usize;
1970 let end_row = (end_pos.y / row_height).round() as usize;
1971
1972 for row in start_row..=end_row {
1973 if let Some(current_row) = galley.rows.get(row) {
1974 let row_rect = current_row.rect();
1975
1976 if row == start_row {
1977 let selection_rect = Rect::from_min_max(
1979 Pos2::new(
1980 position.x + start_pos.x,
1981 position.y + row as f32 * row_height,
1982 ),
1983 Pos2::new(
1984 position.x + row_rect.max.x,
1985 position.y + row as f32 * row_height + row_height,
1986 ),
1987 );
1988 ui.painter().rect_filled(
1989 selection_rect,
1990 0.0,
1991 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1992 );
1993 } else if row == end_row {
1994 let selection_rect = Rect::from_min_max(
1996 Pos2::new(
1997 position.x + row_rect.min.x,
1998 position.y + row as f32 * row_height,
1999 ),
2000 Pos2::new(
2001 position.x + end_pos.x,
2002 position.y + row as f32 * row_height + row_height,
2003 ),
2004 );
2005 ui.painter().rect_filled(
2006 selection_rect,
2007 0.0,
2008 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2009 );
2010 } else {
2011 let selection_rect = Rect::from_min_max(
2013 Pos2::new(
2014 position.x + row_rect.min.x,
2015 position.y + row as f32 * row_height,
2016 ),
2017 Pos2::new(
2018 position.x + row_rect.max.x,
2019 position.y + row as f32 * row_height + row_height,
2020 ),
2021 );
2022 ui.painter().rect_filled(
2023 selection_rect,
2024 0.0,
2025 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2026 );
2027 };
2028 };
2029 }
2030 };
2031 };
2032
2033 if start_cursor.min.y == end_cursor.min.y {
2036 let underline_y = position.y
2038 + start_pos.y
2039 + galley.rows.first().map_or(14.0, |row| row.height())
2040 - 2.0;
2041
2042 let color = Color32::from_rgba_unmultiplied(
2044 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2045 );
2046
2047 ui.painter().line_segment(
2048 [
2049 Pos2::new(position.x + start_pos.x, underline_y),
2050 Pos2::new(position.x + end_pos.x, underline_y),
2051 ],
2052 Stroke::new(t.font_size / 10_f32, color),
2053 );
2054 } else {
2055 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2060 let end_row = (end_pos.y / row_height).round() as usize;
2061
2062 for row in start_row..=end_row {
2063 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
2067 let row_rect = current_row.rect();
2068
2069 let color = Color32::from_rgba_unmultiplied(
2070 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2071 );
2072
2073 if row == start_row {
2074 ui.painter().line_segment(
2076 [
2077 Pos2::new(position.x + start_pos.x, row_y),
2078 Pos2::new(position.x + row_rect.max.x, row_y),
2079 ],
2080 Stroke::new(t.font_size / 10_f32, color),
2081 );
2082 } else if row == end_row {
2083 ui.painter().line_segment(
2085 [
2086 Pos2::new(position.x + row_rect.min.x, row_y),
2087 Pos2::new(position.x + end_pos.x, row_y),
2088 ],
2089 Stroke::new(t.font_size / 10_f32, color),
2090 );
2091 } else {
2092 ui.painter().line_segment(
2094 [
2095 Pos2::new(position.x + row_rect.min.x, row_y),
2096 Pos2::new(position.x + row_rect.max.x, row_y),
2097 ],
2098 Stroke::new(t.font_size / 10_f32, color),
2099 );
2100 };
2101 };
2102 }
2103 };
2104 }
2105 self.rust_constructor_resource[id] = RCR::Text(t);
2106 };
2107 };
2108 }
2109
2110 pub fn get_text_size(
2112 &mut self,
2113 resource_name: &str,
2114 ui: &mut Ui,
2115 ) -> Result<[f32; 2], RustConstructorError> {
2116 if let Ok(id) = self.get_resource_index("Text", resource_name) {
2117 if let RCR::Text(t) = self.rust_constructor_resource[id].clone() {
2118 let galley = ui.fonts(|f| {
2119 f.layout(
2120 t.text_content.to_string(),
2121 FontId::proportional(t.font_size),
2122 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
2123 t.wrap_width,
2124 )
2125 });
2126 return Ok([galley.size().x, galley.size().y]);
2127 };
2128 };
2129 self.problem_report(
2130 RustConstructorError::TextNotFound {
2131 text_name: resource_name.to_string(),
2132 },
2133 SeverityLevel::SevereWarning,
2134 );
2135 Err(RustConstructorError::TextNotFound {
2136 text_name: resource_name.to_string(),
2137 })
2138 }
2139
2140 pub fn add_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2142 self.rust_constructor_resource.push(RCR::Variable(Variable {
2143 discern_type: "Variable".to_string(),
2144 name: name.to_string(),
2145 value: value.into(),
2146 }));
2147 }
2148
2149 pub fn modify_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2151 if let Ok(id) = self.get_resource_index("Variable", name) {
2152 if let RCR::Variable(v) = &mut self.rust_constructor_resource[id] {
2153 v.value = value.into();
2154 };
2155 };
2156 }
2157
2158 pub fn var(&mut self, name: &str) -> Result<Value, RustConstructorError> {
2160 if let Ok(id) = self.get_resource_index("Variable", name) {
2161 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2162 return Ok(v.clone().value);
2163 };
2164 };
2165 self.problem_report(
2166 RustConstructorError::VariableNotFound {
2167 variable_name: name.to_string(),
2168 },
2169 SeverityLevel::SevereWarning,
2170 );
2171 Err(RustConstructorError::VariableNotFound {
2172 variable_name: name.to_string(),
2173 })
2174 }
2175
2176 pub fn var_i(&mut self, name: &str) -> Result<i32, RustConstructorError> {
2178 if let Ok(id) = self.get_resource_index("Variable", name) {
2179 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2180 match &v.value {
2181 Value::Int(i) => Ok(*i),
2183 _ => {
2184 self.problem_report(
2185 RustConstructorError::VariableNotInt {
2186 variable_name: name.to_string(),
2187 },
2188 SeverityLevel::SevereWarning,
2189 );
2190 Err(RustConstructorError::VariableNotInt {
2191 variable_name: name.to_string(),
2192 })
2193 }
2194 }
2195 } else {
2196 Err(RustConstructorError::VariableNotFound {
2198 variable_name: name.to_string(),
2199 })
2200 }
2201 } else {
2202 self.problem_report(
2203 RustConstructorError::VariableNotFound {
2204 variable_name: name.to_string(),
2205 },
2206 SeverityLevel::SevereWarning,
2207 );
2208 Err(RustConstructorError::VariableNotFound {
2209 variable_name: name.to_string(),
2210 })
2211 }
2212 }
2213
2214 pub fn var_u(&mut self, name: &str) -> Result<u32, RustConstructorError> {
2216 if let Ok(id) = self.get_resource_index("Variable", name) {
2217 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2218 match &v.value {
2219 Value::UInt(u) => Ok(*u),
2221 _ => {
2222 self.problem_report(
2223 RustConstructorError::VariableNotUInt {
2224 variable_name: name.to_string(),
2225 },
2226 SeverityLevel::SevereWarning,
2227 );
2228 Err(RustConstructorError::VariableNotUInt {
2229 variable_name: name.to_string(),
2230 })
2231 }
2232 }
2233 } else {
2234 Err(RustConstructorError::VariableNotFound {
2236 variable_name: name.to_string(),
2237 })
2238 }
2239 } else {
2240 self.problem_report(
2241 RustConstructorError::VariableNotFound {
2242 variable_name: name.to_string(),
2243 },
2244 SeverityLevel::SevereWarning,
2245 );
2246 Err(RustConstructorError::VariableNotFound {
2247 variable_name: name.to_string(),
2248 })
2249 }
2250 }
2251
2252 pub fn var_f(&mut self, name: &str) -> Result<f32, RustConstructorError> {
2254 if let Ok(id) = self.get_resource_index("Variable", name) {
2255 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2256 match &v.value {
2257 Value::Float(f) => Ok(*f),
2259 _ => {
2260 self.problem_report(
2261 RustConstructorError::VariableNotFloat {
2262 variable_name: name.to_string(),
2263 },
2264 SeverityLevel::SevereWarning,
2265 );
2266 Err(RustConstructorError::VariableNotFloat {
2267 variable_name: name.to_string(),
2268 })
2269 }
2270 }
2271 } else {
2272 Err(RustConstructorError::VariableNotFound {
2274 variable_name: name.to_string(),
2275 })
2276 }
2277 } else {
2278 self.problem_report(
2279 RustConstructorError::VariableNotFound {
2280 variable_name: name.to_string(),
2281 },
2282 SeverityLevel::SevereWarning,
2283 );
2284 Err(RustConstructorError::VariableNotFound {
2285 variable_name: name.to_string(),
2286 })
2287 }
2288 }
2289
2290 pub fn var_b(&mut self, name: &str) -> Result<bool, RustConstructorError> {
2292 if let Ok(id) = self.get_resource_index("Variable", name) {
2293 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2294 match &v.value {
2295 Value::Bool(b) => Ok(*b),
2297 _ => {
2298 self.problem_report(
2299 RustConstructorError::VariableNotBool {
2300 variable_name: name.to_string(),
2301 },
2302 SeverityLevel::SevereWarning,
2303 );
2304 Err(RustConstructorError::VariableNotBool {
2305 variable_name: name.to_string(),
2306 })
2307 }
2308 }
2309 } else {
2310 Err(RustConstructorError::VariableNotFound {
2312 variable_name: name.to_string(),
2313 })
2314 }
2315 } else {
2316 self.problem_report(
2317 RustConstructorError::VariableNotFound {
2318 variable_name: name.to_string(),
2319 },
2320 SeverityLevel::SevereWarning,
2321 );
2322 Err(RustConstructorError::VariableNotFound {
2323 variable_name: name.to_string(),
2324 })
2325 }
2326 }
2327
2328 pub fn var_v(&mut self, name: &str) -> Result<Vec<Value>, RustConstructorError> {
2330 if let Ok(id) = self.get_resource_index("Variable", name) {
2331 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2332 match &v.value {
2333 Value::Vec(v) => Ok(v.clone()),
2335 _ => {
2336 self.problem_report(
2337 RustConstructorError::VariableNotVec {
2338 variable_name: name.to_string(),
2339 },
2340 SeverityLevel::SevereWarning,
2341 );
2342 Err(RustConstructorError::VariableNotVec {
2343 variable_name: name.to_string(),
2344 })
2345 }
2346 }
2347 } else {
2348 Err(RustConstructorError::VariableNotFound {
2350 variable_name: name.to_string(),
2351 })
2352 }
2353 } else {
2354 self.problem_report(
2355 RustConstructorError::VariableNotFound {
2356 variable_name: name.to_string(),
2357 },
2358 SeverityLevel::SevereWarning,
2359 );
2360 Err(RustConstructorError::VariableNotFound {
2361 variable_name: name.to_string(),
2362 })
2363 }
2364 }
2365
2366 pub fn var_s(&mut self, name: &str) -> Result<String, RustConstructorError> {
2368 if let Ok(id) = self.get_resource_index("Variable", name) {
2369 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2370 match &v.value {
2371 Value::String(s) => Ok(s.clone()),
2373 _ => {
2374 self.problem_report(
2375 RustConstructorError::VariableNotString {
2376 variable_name: name.to_string(),
2377 },
2378 SeverityLevel::SevereWarning,
2379 );
2380 Err(RustConstructorError::VariableNotString {
2381 variable_name: name.to_string(),
2382 })
2383 }
2384 }
2385 } else {
2386 Err(RustConstructorError::VariableNotFound {
2388 variable_name: name.to_string(),
2389 })
2390 }
2391 } else {
2392 self.problem_report(
2393 RustConstructorError::VariableNotFound {
2394 variable_name: name.to_string(),
2395 },
2396 SeverityLevel::SevereWarning,
2397 );
2398 Err(RustConstructorError::VariableNotFound {
2399 variable_name: name.to_string(),
2400 })
2401 }
2402 }
2403
2404 pub fn var_decode_b(&mut self, target: Value) -> Result<bool, RustConstructorError> {
2406 match target {
2407 Value::Bool(b) => {
2408 Ok(b)
2410 }
2411 _ => {
2412 self.problem_report(
2413 RustConstructorError::VariableNotBool {
2414 variable_name: format!("{:?}", target),
2415 },
2416 SeverityLevel::SevereWarning,
2417 );
2418 Err(RustConstructorError::VariableNotBool {
2419 variable_name: format!("{:?}", target),
2420 })
2421 }
2422 }
2423 }
2424
2425 pub fn var_decode_i(&mut self, target: Value) -> Result<i32, RustConstructorError> {
2427 match target {
2428 Value::Int(i) => {
2429 Ok(i)
2431 }
2432 _ => {
2433 self.problem_report(
2434 RustConstructorError::VariableNotInt {
2435 variable_name: format!("{:?}", target),
2436 },
2437 SeverityLevel::SevereWarning,
2438 );
2439 Err(RustConstructorError::VariableNotInt {
2440 variable_name: format!("{:?}", target),
2441 })
2442 }
2443 }
2444 }
2445
2446 pub fn var_decode_u(&mut self, target: Value) -> Result<u32, RustConstructorError> {
2448 match target {
2449 Value::UInt(u) => {
2450 Ok(u)
2452 }
2453 _ => {
2454 self.problem_report(
2455 RustConstructorError::VariableNotUInt {
2456 variable_name: format!("{:?}", target),
2457 },
2458 SeverityLevel::SevereWarning,
2459 );
2460 Err(RustConstructorError::VariableNotUInt {
2461 variable_name: format!("{:?}", target),
2462 })
2463 }
2464 }
2465 }
2466
2467 pub fn var_decode_f(&mut self, target: Value) -> Result<f32, RustConstructorError> {
2469 match target {
2470 Value::Float(f) => {
2471 Ok(f)
2473 }
2474 _ => {
2475 self.problem_report(
2476 RustConstructorError::VariableNotFloat {
2477 variable_name: format!("{:?}", target),
2478 },
2479 SeverityLevel::SevereWarning,
2480 );
2481 Err(RustConstructorError::VariableNotFloat {
2482 variable_name: format!("{:?}", target),
2483 })
2484 }
2485 }
2486 }
2487
2488 pub fn var_decode_s(&mut self, target: Value) -> Result<String, RustConstructorError> {
2490 match target {
2491 Value::String(s) => {
2492 Ok(s)
2494 }
2495 _ => {
2496 self.problem_report(
2497 RustConstructorError::VariableNotString {
2498 variable_name: format!("{:?}", target),
2499 },
2500 SeverityLevel::SevereWarning,
2501 );
2502 Err(RustConstructorError::VariableNotString {
2503 variable_name: format!("{:?}", target),
2504 })
2505 }
2506 }
2507 }
2508
2509 pub fn var_decode_v(&mut self, target: Value) -> Result<Vec<Value>, RustConstructorError> {
2511 match target {
2512 Value::Vec(v) => {
2513 Ok(v)
2515 }
2516 _ => {
2517 self.problem_report(
2518 RustConstructorError::VariableNotVec {
2519 variable_name: format!("{:?}", target),
2520 },
2521 SeverityLevel::SevereWarning,
2522 );
2523 Err(RustConstructorError::VariableNotVec {
2524 variable_name: format!("{:?}", target),
2525 })
2526 }
2527 }
2528 }
2529
2530 pub fn add_scroll_background(
2532 &mut self,
2533 name: &str,
2534 image_name: Vec<String>,
2535 horizontal_or_vertical: bool,
2536 left_and_top_or_right_and_bottom: bool,
2537 scroll_speed: u32,
2538 size_position_boundary: [f32; 5],
2539 ) {
2540 let mut image_id = vec![];
2541 for i in image_name.clone() {
2542 for u in 0..self.rust_constructor_resource.len() {
2543 if let RCR::Image(im) = self.rust_constructor_resource[u].clone() {
2544 if im.name == i {
2545 image_id.push(u);
2546 };
2547 };
2548 }
2549 }
2550 for (count, _) in image_id.clone().into_iter().enumerate() {
2551 if let RCR::Image(im) = &mut self.rust_constructor_resource[image_id[count]] {
2552 im.x_grid = [0, 0];
2553 im.y_grid = [0, 0];
2554 im.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2555 im.image_size = [size_position_boundary[0], size_position_boundary[1]];
2556 let mut temp_position;
2557 if horizontal_or_vertical {
2558 temp_position = size_position_boundary[2];
2559 } else {
2560 temp_position = size_position_boundary[3];
2561 };
2562 if horizontal_or_vertical {
2563 for _ in 0..count {
2564 if left_and_top_or_right_and_bottom {
2565 temp_position += size_position_boundary[0];
2566 } else {
2567 temp_position -= size_position_boundary[0];
2568 };
2569 }
2570 im.origin_position = [temp_position, size_position_boundary[3]];
2571 } else {
2572 for _ in 0..count {
2573 if left_and_top_or_right_and_bottom {
2574 temp_position += size_position_boundary[1];
2575 } else {
2576 temp_position -= size_position_boundary[1];
2577 };
2578 }
2579 im.origin_position = [size_position_boundary[2], temp_position];
2580 };
2581 };
2582 }
2583 if let RCR::Image(im) = self.rust_constructor_resource[image_id[image_id.len() - 1]].clone()
2584 {
2585 let resume_point = if horizontal_or_vertical {
2586 im.origin_position[0]
2587 } else {
2588 im.origin_position[1]
2589 };
2590 self.rust_constructor_resource
2591 .push(RCR::ScrollBackground(ScrollBackground {
2592 discern_type: "ScrollBackground".to_string(),
2593 name: name.to_string(),
2594 image_name,
2595 horizontal_or_vertical,
2596 left_and_top_or_right_and_bottom,
2597 scroll_speed,
2598 boundary: size_position_boundary[4],
2599 resume_point,
2600 }));
2601 };
2602 }
2603
2604 pub fn scroll_background(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2606 if let Ok(id) = self.get_resource_index("ScrollBackground", name) {
2607 if let RCR::ScrollBackground(sb) = self.rust_constructor_resource[id].clone() {
2608 sb.reg_render_resource(&mut self.render_resource_list);
2609 if self.get_resource_index("SplitTime", name).is_err() {
2610 self.add_split_time(name, false);
2611 };
2612 for i in 0..sb.image_name.len() {
2613 self.image(ui, &sb.image_name[i].clone(), ctx);
2614 }
2615 if self.timer.now_time - self.split_time(name).unwrap()[0] >= self.vertrefresh {
2616 self.add_split_time(name, true);
2617 for i in 0..sb.image_name.len() {
2618 if let Ok(id2) = self.get_resource_index("Image", &sb.image_name[i].clone())
2619 {
2620 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone()
2621 {
2622 if sb.horizontal_or_vertical {
2623 if sb.left_and_top_or_right_and_bottom {
2624 for _ in 0..sb.scroll_speed {
2625 im.origin_position[0] -= 1_f32;
2626 if im.origin_position[0] <= sb.boundary {
2627 im.origin_position[0] = sb.resume_point;
2628 };
2629 }
2630 self.rust_constructor_resource[id2] =
2631 RCR::Image(im.clone());
2632 } else {
2633 for _ in 0..sb.scroll_speed {
2634 im.origin_position[0] += 1_f32;
2635 if im.origin_position[0] >= sb.boundary {
2636 im.origin_position[0] = sb.resume_point;
2637 };
2638 }
2639 self.rust_constructor_resource[id2] =
2640 RCR::Image(im.clone());
2641 };
2642 } else if sb.left_and_top_or_right_and_bottom {
2643 for _ in 0..sb.scroll_speed {
2644 im.origin_position[1] -= 1_f32;
2645 if im.origin_position[1] <= sb.boundary {
2646 im.origin_position[1] = sb.resume_point;
2647 };
2648 }
2649 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2650 } else {
2651 for _ in 0..sb.scroll_speed {
2652 im.origin_position[1] += 1_f32;
2653 if im.origin_position[1] >= sb.boundary {
2654 im.origin_position[1] = sb.resume_point;
2655 };
2656 }
2657 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2658 };
2659 };
2660 };
2661 }
2662 };
2663 };
2664 };
2665 }
2666
2667 pub fn add_image_texture(
2669 &mut self,
2670 name: &str,
2671 path: &str,
2672 flip: [bool; 2],
2673 create_new_resource: bool,
2674 ctx: &egui::Context,
2675 ) {
2676 if let Ok(mut file) = File::open(path) {
2677 let mut buffer = Vec::new();
2678 file.read_to_end(&mut buffer).unwrap();
2679 let img_bytes = buffer;
2680 let img = image::load_from_memory(&img_bytes).unwrap();
2681 let rgba_data = match flip {
2682 [true, true] => img.fliph().flipv().into_rgba8(),
2683 [true, false] => img.fliph().into_rgba8(),
2684 [false, true] => img.flipv().into_rgba8(),
2685 _ => img.into_rgba8(),
2686 };
2687 let (w, h) = (rgba_data.width(), rgba_data.height());
2688 let raw_data: Vec<u8> = rgba_data.into_raw();
2689
2690 let color_image =
2691 egui::ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
2692 let image_texture = Some(ctx.load_texture(name, color_image, TextureOptions::LINEAR));
2693 if create_new_resource {
2694 self.rust_constructor_resource
2695 .push(RCR::ImageTexture(ImageTexture {
2696 discern_type: "ImageTexture".to_string(),
2697 name: name.to_string(),
2698 texture: image_texture,
2699 cite_path: path.to_string(),
2700 }));
2701 } else if let Ok(id) = self.get_resource_index("ImageTexture", name) {
2702 if let RCR::ImageTexture(it) = &mut self.rust_constructor_resource[id] {
2703 if !create_new_resource {
2704 it.texture = image_texture;
2705 it.cite_path = path.to_string();
2706 };
2707 };
2708 } else {
2709 self.rust_constructor_resource
2710 .push(RCR::ImageTexture(ImageTexture {
2711 discern_type: "ImageTexture".to_string(),
2712 name: name.to_string(),
2713 texture: image_texture,
2714 cite_path: path.to_string(),
2715 }));
2716 };
2717 } else {
2718 self.problem_report(
2719 RustConstructorError::ImageGetFailed {
2720 image_path: path.to_string(),
2721 },
2722 SeverityLevel::SevereWarning,
2723 );
2724 };
2725 }
2726
2727 pub fn add_image(
2729 &mut self,
2730 name: &str,
2731 position_size: [f32; 4],
2732 grid: [u32; 4],
2733 center_display_and_use_overlay: (HorizontalAlign, VerticalAlign, bool),
2734 alpha_and_overlay_color: [u8; 5],
2735 image_texture_name: &str,
2736 ) {
2737 if let Ok(id) = self.get_resource_index("ImageTexture", image_texture_name) {
2738 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id].clone() {
2739 self.rust_constructor_resource.push(RCR::Image(Image {
2740 discern_type: "Image".to_string(),
2741 name: name.to_string(),
2742 image_texture: it.texture.clone(),
2743 image_position: [position_size[0], position_size[1]],
2744 image_size: [position_size[2], position_size[3]],
2745 x_grid: [grid[0], grid[1]],
2746 y_grid: [grid[2], grid[3]],
2747 center_display: (
2748 center_display_and_use_overlay.0,
2749 center_display_and_use_overlay.1,
2750 ),
2751 alpha: alpha_and_overlay_color[0],
2752 overlay_color: [
2753 alpha_and_overlay_color[1],
2754 alpha_and_overlay_color[2],
2755 alpha_and_overlay_color[3],
2756 alpha_and_overlay_color[4],
2757 ],
2758 use_overlay_color: center_display_and_use_overlay.2,
2759 origin_position: [position_size[0], position_size[1]],
2760 cite_texture: image_texture_name.to_string(),
2761 last_frame_cite_texture: image_texture_name.to_string(),
2762 }));
2763 };
2764 };
2765 }
2766
2767 pub fn image(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2769 if let Ok(id) = self.get_resource_index("Image", name) {
2770 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
2771 if im.cite_texture != im.last_frame_cite_texture {
2772 if let Ok(id2) = self.get_resource_index("ImageTexture", &im.cite_texture) {
2773 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id2].clone() {
2774 im.image_texture = it.texture;
2775 };
2776 };
2777 };
2778 im.reg_render_resource(&mut self.render_resource_list);
2779 im.image_position[0] = match im.x_grid[1] {
2780 0 => im.origin_position[0],
2781 _ => {
2782 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64
2783 * im.x_grid[0] as f64) as f32
2784 + im.origin_position[0]
2785 }
2786 };
2787 im.image_position[1] = match im.y_grid[1] {
2788 0 => im.origin_position[1],
2789 _ => {
2790 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64
2791 * im.y_grid[0] as f64) as f32
2792 + im.origin_position[1]
2793 }
2794 };
2795 match im.center_display.0 {
2796 HorizontalAlign::Left => {}
2797 HorizontalAlign::Center => im.image_position[0] -= im.image_size[0] / 2.0,
2798 HorizontalAlign::Right => im.image_position[0] -= im.image_size[0],
2799 };
2800 match im.center_display.1 {
2801 VerticalAlign::Top => {}
2802 VerticalAlign::Center => im.image_position[1] -= im.image_size[1] / 2.0,
2803 VerticalAlign::Bottom => im.image_position[1] -= im.image_size[1],
2804 };
2805 if let Some(texture) = &im.image_texture {
2806 let rect = Rect::from_min_size(
2807 Pos2::new(im.image_position[0], im.image_position[1]),
2808 Vec2::new(im.image_size[0], im.image_size[1]),
2809 );
2810 let color = if im.use_overlay_color {
2811 Color32::from_rgba_unmultiplied(
2813 im.overlay_color[0],
2814 im.overlay_color[1],
2815 im.overlay_color[2],
2816 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
2818 )
2819 } else {
2820 Color32::from_white_alpha(im.alpha)
2821 };
2822
2823 egui::Image::new(egui::ImageSource::Texture(texture.into()))
2825 .tint(color)
2826 .paint_at(ui, rect)
2827 };
2828 im.last_frame_cite_texture = im.cite_texture.clone();
2829 self.rust_constructor_resource[id] = RCR::Image(im);
2830 };
2831 };
2832 }
2833
2834 pub fn add_message_box(
2836 &mut self,
2837 box_itself_title_content_image_name_and_sound_path: [&str; 5],
2838 box_size: [f32; 2],
2839 box_keep_existing: bool,
2840 box_existing_time: f32,
2841 box_normal_and_restore_speed: [f32; 2],
2842 ) {
2843 if !self.check_resource_exists(
2844 "MessageBox",
2845 box_itself_title_content_image_name_and_sound_path[0],
2846 ) {
2847 if let Ok(id) = self.get_resource_index(
2848 "Image",
2849 box_itself_title_content_image_name_and_sound_path[3],
2850 ) {
2851 if let RCR::Image(im) = &mut self.rust_constructor_resource[id] {
2852 im.image_size = [box_size[1] - 15_f32, box_size[1] - 15_f32];
2853 im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
2854 im.x_grid = [1, 1];
2855 im.y_grid = [0, 1];
2856 im.name = format!("MessageBox{}", im.name);
2857 };
2858 };
2859 if let Ok(id) = self.get_resource_index(
2860 "Text",
2861 box_itself_title_content_image_name_and_sound_path[1],
2862 ) {
2863 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2864 t.x_grid = [1, 1];
2865 t.y_grid = [0, 1];
2866 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2867 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2868 t.name = format!("MessageBox{}", t.name);
2869 };
2870 };
2871 if let Ok(id) = self.get_resource_index(
2872 "Text",
2873 box_itself_title_content_image_name_and_sound_path[2],
2874 ) {
2875 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2876 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2877 t.x_grid = [1, 1];
2878 t.y_grid = [0, 1];
2879 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2880 t.name = format!("MessageBox{}", t.name);
2881 };
2882 };
2883 self.rust_constructor_resource
2884 .push(RCR::MessageBox(MessageBox {
2885 discern_type: "MessageBox".to_string(),
2886 name: box_itself_title_content_image_name_and_sound_path[0].to_string(),
2887 box_size,
2888 box_title_name: format!(
2889 "MessageBox{}",
2890 box_itself_title_content_image_name_and_sound_path[1]
2891 ),
2892 box_content_name: format!(
2893 "MessageBox{}",
2894 box_itself_title_content_image_name_and_sound_path[2]
2895 ),
2896 box_image_name: format!(
2897 "MessageBox{}",
2898 box_itself_title_content_image_name_and_sound_path[3]
2899 ),
2900 box_keep_existing,
2901 box_existing_time,
2902 box_exist: true,
2903 box_speed: box_normal_and_restore_speed[0],
2904 box_restore_speed: box_normal_and_restore_speed[1],
2905 box_memory_offset: 0_f32,
2906 }));
2907 if !box_keep_existing {
2908 self.add_split_time(
2909 &format!(
2910 "MessageBox{}",
2911 box_itself_title_content_image_name_and_sound_path[0]
2912 ),
2913 false,
2914 );
2915 };
2916 self.add_split_time(
2917 &format!(
2918 "MessageBox{}Animation",
2919 box_itself_title_content_image_name_and_sound_path[0]
2920 ),
2921 false,
2922 );
2923 self.add_rect(
2924 &format!(
2925 "MessageBox{}",
2926 box_itself_title_content_image_name_and_sound_path[0]
2927 ),
2928 [0_f32, 0_f32, box_size[0], box_size[1], 20_f32],
2929 [1, 1, 0, 1],
2930 (HorizontalAlign::Left, VerticalAlign::Top),
2931 [100, 100, 100, 125, 240, 255, 255, 255],
2932 0.0,
2933 );
2934 self.add_image(
2935 &format!(
2936 "MessageBox{}Close",
2937 box_itself_title_content_image_name_and_sound_path[0]
2938 ),
2939 [0_f32, 0_f32, 30_f32, 30_f32],
2940 [0, 0, 0, 0],
2941 (HorizontalAlign::Center, VerticalAlign::Center, false),
2942 [255, 0, 0, 0, 0],
2943 "CloseMessageBox",
2944 );
2945 self.add_switch(
2946 [
2947 &format!(
2948 "MessageBox{}Close",
2949 box_itself_title_content_image_name_and_sound_path[0]
2950 ),
2951 &format!(
2952 "MessageBox{}Close",
2953 box_itself_title_content_image_name_and_sound_path[0]
2954 ),
2955 "",
2956 box_itself_title_content_image_name_and_sound_path[4],
2957 ],
2958 vec![
2959 SwitchData {
2960 texture: "CloseMessageBox".to_string(),
2961 color: [255, 255, 255, 0],
2962 text: String::new(),
2963 hint_text: String::new(),
2964 },
2965 SwitchData {
2966 texture: "CloseMessageBox".to_string(),
2967 color: [180, 180, 180, 200],
2968 text: String::new(),
2969 hint_text: String::new(),
2970 },
2971 SwitchData {
2972 texture: "CloseMessageBox".to_string(),
2973 color: [255, 255, 255, 200],
2974 text: String::new(),
2975 hint_text: String::new(),
2976 },
2977 SwitchData {
2978 texture: "CloseMessageBox".to_string(),
2979 color: [180, 180, 180, 200],
2980 text: String::new(),
2981 hint_text: String::new(),
2982 },
2983 ],
2984 [false, true, true],
2985 2,
2986 vec![SwitchClickAction {
2987 click_method: PointerButton::Primary,
2988 action: true,
2989 }],
2990 );
2991 } else {
2992 self.problem_report(
2993 RustConstructorError::MessageBoxAlreadyExists {
2994 message_box_name: box_itself_title_content_image_name_and_sound_path[0]
2995 .to_string(),
2996 },
2997 SeverityLevel::SevereWarning,
2998 );
2999 };
3000 }
3001
3002 pub fn message_box_display(&mut self, ctx: &egui::Context, ui: &mut Ui) {
3004 let mut offset = 0_f32;
3005 let mut delete_count = 0;
3006 let mut index_list = Vec::new();
3007 for i in 0..self.rust_constructor_resource.len() {
3008 if let RCR::MessageBox(_) = self.rust_constructor_resource[i] {
3009 index_list.push(i);
3010 };
3011 }
3012 for u in 0..index_list.len() {
3013 let mut deleted = false;
3014 let i = u - delete_count;
3015 if let RCR::MessageBox(mut mb) = self.rust_constructor_resource[index_list[i]].clone() {
3016 if let Ok(id1) = self.get_resource_index("Image", &mb.box_image_name) {
3017 if let RCR::Image(mut im1) = self.rust_constructor_resource[id1].clone() {
3018 if let Ok(id2) =
3019 self.get_resource_index("CustomRect", &format!("MessageBox{}", mb.name))
3020 {
3021 if let RCR::CustomRect(mut cr) =
3022 self.rust_constructor_resource[id2].clone()
3023 {
3024 if let Ok(id3) = self.get_resource_index("Text", &mb.box_title_name)
3025 {
3026 if let RCR::Text(mut t1) =
3027 self.rust_constructor_resource[id3].clone()
3028 {
3029 if let Ok(id4) =
3030 self.get_resource_index("Text", &mb.box_content_name)
3031 {
3032 if let RCR::Text(mut t2) =
3033 self.rust_constructor_resource[id4].clone()
3034 {
3035 if let Ok(id5) = self.get_resource_index(
3036 "Switch",
3037 &format!("MessageBox{}Close", mb.name),
3038 ) {
3039 if let RCR::Switch(mut s) =
3040 self.rust_constructor_resource[id5].clone()
3041 {
3042 if let Ok(id6) = self.get_resource_index(
3043 "Image",
3044 &format!("MessageBox{}Close", mb.name),
3045 ) {
3046 if let RCR::Image(mut im2) = self
3047 .rust_constructor_resource[id6]
3048 .clone()
3049 {
3050 if mb.box_size[1]
3051 < self.get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3052 + self.get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3053 [1]
3054 + 10_f32
3055 {
3056 mb.box_size[1] = self
3057 .get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3058 + self
3059 .get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3060 [1]
3061 + 10_f32;
3062 cr.size[1] = mb.box_size[1];
3063 im1.image_size = [
3064 mb.box_size[1] - 15_f32,
3065 mb.box_size[1] - 15_f32,
3066 ];
3067 t1.wrap_width = mb.box_size[0]
3068 - mb.box_size[1]
3069 + 5_f32;
3070 t2.wrap_width = mb.box_size[0]
3071 - mb.box_size[1]
3072 + 5_f32;
3073 };
3074 if self.timer.total_time
3075 - self
3076 .split_time(&format!(
3077 "MessageBox{}Animation",
3078 mb.name
3079 ))
3080 .unwrap()[1]
3081 >= self.vertrefresh
3082 {
3083 self.add_split_time(
3084 &format!(
3085 "MessageBox{}Animation",
3086 mb.name
3087 ),
3088 true,
3089 );
3090 if offset
3091 != mb.box_memory_offset
3092 {
3093 if mb.box_memory_offset
3094 < offset
3095 {
3096 if mb.box_memory_offset
3097 + mb.box_restore_speed
3098 >= offset
3099 {
3100 mb.box_memory_offset = offset;
3101 } else {
3102 mb.box_memory_offset +=
3103 mb.box_restore_speed;
3104 };
3105 } else if mb
3106 .box_memory_offset
3107 - mb.box_restore_speed
3108 <= offset
3109 {
3110 mb.box_memory_offset =
3111 offset;
3112 } else {
3113 mb.box_memory_offset -=
3114 mb.box_restore_speed;
3115 };
3116 };
3117 if cr.origin_position[0]
3118 != -mb.box_size[0] - 5_f32
3119 {
3120 if mb.box_exist {
3121 if cr.origin_position[0]
3122 - mb.box_speed
3123 <= -mb.box_size[0]
3124 - 5_f32
3125 {
3126 cr.origin_position[0] =
3127 -mb.box_size[0] - 5_f32;
3128 if self.check_resource_exists("SplitTime", &format!("MessageBox{}", mb.name)) {
3129 self.add_split_time(
3130 &format!("MessageBox{}", mb.name),
3131 true,
3132 );
3133 };
3134 } else {
3135 cr.origin_position[0] -=
3136 mb.box_speed;
3137 };
3138 } else if cr.origin_position
3139 [0]
3140 + mb.box_speed
3141 >= 15_f32
3142 {
3143 cr.origin_position[0] =
3144 15_f32;
3145 delete_count += 1;
3146 deleted = true;
3147 } else {
3148 cr.origin_position
3149 [0] += mb.box_speed;
3150 };
3151 };
3152 };
3153 cr.origin_position[1] =
3154 mb.box_memory_offset + 20_f32;
3155 im1.origin_position = [
3156 cr.origin_position[0] + 5_f32,
3157 cr.origin_position[1]
3158 + mb.box_size[1] / 2_f32,
3159 ];
3160 t1.origin_position = [
3161 im1.origin_position[0]
3162 + im1.image_size[0]
3163 + 5_f32,
3164 cr.origin_position[1] + 5_f32,
3165 ];
3166 t2.origin_position = [
3167 im1.origin_position[0]
3168 + im1.image_size[0]
3169 + 5_f32,
3170 t1.origin_position[1]
3171 + self
3172 .get_text_size(
3173 &mb.box_title_name
3174 .clone(),
3175 ui,
3176 )
3177 .unwrap()[1],
3178 ];
3179 im2.origin_position = cr.position;
3180 if !mb.box_keep_existing
3181 && self.timer.total_time
3182 - self
3183 .split_time(&format!(
3184 "MessageBox{}",
3185 mb.name
3186 ))
3187 .unwrap()[1]
3188 >= mb.box_existing_time
3189 && cr.origin_position[0]
3190 == -mb.box_size[0] - 5_f32
3191 {
3192 mb.box_exist = false;
3193 if cr.origin_position[0]
3194 + mb.box_speed
3195 >= 15_f32
3196 {
3197 cr.origin_position[0] =
3198 15_f32;
3199 } else {
3200 cr.origin_position[0] +=
3201 mb.box_speed;
3202 };
3203 };
3204 if let Some(mouse_pos) =
3205 ui.input(|i| {
3206 i.pointer.hover_pos()
3207 })
3208 {
3209 let rect =
3210 egui::Rect::from_min_size(
3211 Pos2 {
3212 x: im2
3213 .image_position
3214 [0],
3215 y: im2
3216 .image_position
3217 [1],
3218 },
3219 Vec2 {
3220 x: cr.size[0]
3221 + 25_f32,
3222 y: cr.size[1]
3223 + 25_f32,
3224 },
3225 );
3226 if rect.contains(mouse_pos) {
3227 s.appearance[0].color[3] =
3228 200;
3229 } else {
3230 s.appearance[0].color[3] =
3231 0;
3232 };
3233 };
3234 self.rust_constructor_resource
3235 [index_list[i]] =
3236 RCR::MessageBox(mb.clone());
3237 self.rust_constructor_resource
3238 [id1] = RCR::Image(im1.clone());
3239 self.rust_constructor_resource
3240 [id2] =
3241 RCR::CustomRect(cr.clone());
3242 self.rust_constructor_resource
3243 [id3] = RCR::Text(t1.clone());
3244 self.rust_constructor_resource
3245 [id4] = RCR::Text(t2.clone());
3246 self.rust_constructor_resource
3247 [id5] = RCR::Switch(s.clone());
3248 self.rust_constructor_resource
3249 [id6] = RCR::Image(im2.clone());
3250 self.rect(
3251 ui,
3252 &format!(
3253 "MessageBox{}",
3254 mb.name
3255 ),
3256 ctx,
3257 );
3258 self.image(
3259 ui,
3260 &mb.box_image_name.clone(),
3261 ctx,
3262 );
3263 self.text(
3264 ui,
3265 &t1.name.clone(),
3266 ctx,
3267 );
3268 self.text(
3269 ui,
3270 &t2.name.clone(),
3271 ctx,
3272 );
3273 if self
3274 .switch(
3275 &format!(
3276 "MessageBox{}Close",
3277 mb.name
3278 ),
3279 ui,
3280 ctx,
3281 s.state == 0
3282 && mb.box_exist,
3283 true,
3284 )
3285 .unwrap()[0]
3286 == 0
3287 {
3288 mb.box_exist = false;
3289 if cr.origin_position[0]
3290 + mb.box_speed
3291 >= 15_f32
3292 {
3293 cr.origin_position[0] =
3294 15_f32;
3295 } else {
3296 cr.origin_position[0] +=
3297 mb.box_speed;
3298 };
3299 self.rust_constructor_resource[id2] = RCR::CustomRect(cr.clone());
3300 self.rust_constructor_resource[index_list[i]] = RCR::MessageBox(mb.clone());
3301 };
3302 if deleted {
3303 if let Ok(id) = self
3304 .get_resource_index(
3305 "Image",
3306 &mb.box_image_name,
3307 )
3308 {
3309 self.rust_constructor_resource.remove(id);
3310 };
3311 if let Ok(id) = self
3312 .get_resource_index(
3313 "CustomRect",
3314 &format!(
3315 "MessageBox{}",
3316 mb.name
3317 ),
3318 )
3319 {
3320 self.rust_constructor_resource.remove(id);
3321 };
3322 if let Ok(id) = self
3323 .get_resource_index(
3324 "Text",
3325 &mb.box_title_name,
3326 )
3327 {
3328 self.rust_constructor_resource.remove(id);
3329 };
3330 if let Ok(id) = self
3331 .get_resource_index(
3332 "Text",
3333 &mb.box_content_name,
3334 )
3335 {
3336 self.rust_constructor_resource.remove(id);
3337 };
3338 if let Ok(id) = self
3339 .get_resource_index(
3340 "Switch",
3341 &format!(
3342 "MessageBox{}Close",
3343 mb.name
3344 ),
3345 )
3346 {
3347 self.rust_constructor_resource.remove(id);
3348 };
3349 if let Ok(id) = self
3350 .get_resource_index(
3351 "Image",
3352 &format!(
3353 "MessageBox{}Close",
3354 mb.name
3355 ),
3356 )
3357 {
3358 self.rust_constructor_resource.remove(id);
3359 };
3360 if let Ok(id) = self.get_resource_index("SplitTime", &format!("MessageBox{}Animation", mb.name)) {
3361 self.rust_constructor_resource.remove(id);
3362 };
3363 if !mb.box_keep_existing {
3364 if let Ok(id) = self
3365 .get_resource_index(
3366 "SplitTime",
3367 &format!(
3368 "MessageBox{}",
3369 mb.name
3370 ),
3371 )
3372 {
3373 self.rust_constructor_resource.remove(id);
3374 };
3375 };
3376 if let Ok(id) = self
3377 .get_resource_index(
3378 "MessageBox",
3379 &mb.name,
3380 )
3381 {
3382 self.rust_constructor_resource.remove(id);
3383 };
3384 } else {
3385 offset +=
3386 mb.box_size[1] + 15_f32;
3387 };
3388 };
3389 };
3390 };
3391 };
3392 };
3393 };
3394 };
3395 };
3396 };
3397 };
3398 };
3399 };
3400 };
3401 }
3402 }
3403
3404 pub fn add_switch(
3406 &mut self,
3407 name_switch_image_name_text_name_and_sound_path: [&str; 4],
3408 mut appearance: Vec<SwitchData>,
3409 enable_hover_click_image_and_use_overlay: [bool; 3],
3410 switch_amounts_state: u32,
3411 click_method: Vec<SwitchClickAction>,
3412 ) {
3413 let mut count = 1;
3414 if enable_hover_click_image_and_use_overlay[0] {
3415 count += 1;
3416 };
3417 if enable_hover_click_image_and_use_overlay[1] {
3418 count += 1;
3419 };
3420 if appearance.len() as u32 != count * switch_amounts_state {
3421 self.problem_report(
3422 RustConstructorError::SwitchAppearanceMismatch {
3423 switch_name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3424 differ: (count as i32 * switch_amounts_state as i32 - appearance.len() as i32)
3425 .unsigned_abs(),
3426 },
3427 SeverityLevel::SevereWarning,
3428 );
3429 for _ in
3430 0..(count as i32 * switch_amounts_state as i32 - appearance.len() as i32) as usize
3431 {
3432 appearance.push(SwitchData {
3433 texture: "Error".to_string(),
3434 color: [255, 255, 255, 255],
3435 text: String::new(),
3436 hint_text: String::new(),
3437 });
3438 }
3439 };
3440 let mut text_origin_position = [0_f32, 0_f32];
3441 if let Ok(id) =
3442 self.get_resource_index("Image", name_switch_image_name_text_name_and_sound_path[1])
3443 {
3444 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
3445 im.use_overlay_color = true;
3446 if self.check_resource_exists(
3447 "Text",
3448 name_switch_image_name_text_name_and_sound_path[2],
3449 ) {
3450 if let Ok(id2) = self.get_resource_index(
3451 "Text",
3452 name_switch_image_name_text_name_and_sound_path[2],
3453 ) {
3454 if let RCR::Text(t) = &mut self.rust_constructor_resource[id2] {
3455 t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
3456 t.x_grid = [0, 0];
3457 t.y_grid = [0, 0];
3458 text_origin_position = t.origin_position;
3459 };
3460 };
3461 };
3462 self.rust_constructor_resource[id] = RCR::Image(im);
3463 };
3464 };
3465 if !appearance.iter().any(|x| x.hint_text.is_empty()) {
3466 self.add_text(
3467 [
3468 &format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0]),
3469 "",
3470 "Content",
3471 ],
3472 [0_f32, 0_f32, 25_f32, 300_f32, 10_f32],
3473 [255, 255, 255, 0, 0, 0, 0, 0],
3474 (HorizontalAlign::Left, VerticalAlign::Top, true, false),
3475 [0, 0, 0, 0],
3476 vec![],
3477 );
3478 self.add_split_time(
3479 &format!(
3480 "{}StartHoverTime",
3481 name_switch_image_name_text_name_and_sound_path[0]
3482 ),
3483 false,
3484 );
3485 self.add_split_time(
3486 &format!(
3487 "{}HintFadeAnimation",
3488 name_switch_image_name_text_name_and_sound_path[0]
3489 ),
3490 false,
3491 );
3492 };
3493 self.rust_constructor_resource.push(RCR::Switch(Switch {
3494 discern_type: "Switch".to_string(),
3495 name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3496 appearance: appearance.clone(),
3497 switch_image_name: name_switch_image_name_text_name_and_sound_path[1].to_string(),
3498 enable_hover_click_image: [
3499 enable_hover_click_image_and_use_overlay[0],
3500 enable_hover_click_image_and_use_overlay[1],
3501 ],
3502 state: 0,
3503 click_method,
3504 last_time_hovered: false,
3505 last_time_clicked: false,
3506 last_time_clicked_index: 0,
3507 animation_count: count,
3508 hint_text_name: if !appearance.iter().any(|x| x.hint_text.is_empty()) {
3509 format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0])
3510 } else {
3511 "".to_string()
3512 },
3513 text_name: name_switch_image_name_text_name_and_sound_path[2].to_string(),
3514 text_origin_position,
3515 sound_path: name_switch_image_name_text_name_and_sound_path[3].to_string(),
3516 }));
3517 }
3518
3519 pub fn switch(
3521 &mut self,
3522 name: &str,
3523 ui: &mut Ui,
3524 ctx: &egui::Context,
3525 enable: bool,
3526 play_sound: bool,
3527 ) -> Result<[usize; 2], RustConstructorError> {
3528 let mut activated = [5, 0];
3529 let mut appearance_count = 0;
3530 if let Ok(id) = self.get_resource_index("Switch", name) {
3531 if let RCR::Switch(mut s) = self.rust_constructor_resource[id].clone() {
3532 if let Ok(id2) = self.get_resource_index("Image", &s.switch_image_name.clone()) {
3533 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone() {
3534 s.reg_render_resource(&mut self.render_resource_list);
3535 let rect = Rect::from_min_size(
3536 Pos2::new(im.image_position[0], im.image_position[1]),
3537 Vec2::new(im.image_size[0], im.image_size[1]),
3538 );
3539 let mut hovered = false;
3540 if enable {
3541 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
3542 if rect.contains(mouse_pos) {
3544 if !s.hint_text_name.is_empty() {
3545 if let Ok(id3) =
3546 self.get_resource_index("Text", &s.hint_text_name)
3547 {
3548 if let RCR::Text(mut t) =
3549 self.rust_constructor_resource[id3].clone()
3550 {
3551 if !s.last_time_hovered {
3552 self.add_split_time(
3553 &format!("{}StartHoverTime", s.name),
3554 true,
3555 );
3556 } else if self.timer.total_time
3557 - self
3558 .split_time(&format!(
3559 "{}StartHoverTime",
3560 s.name
3561 ))
3562 .unwrap()[1]
3563 >= 2_f32
3564 || t.rgba[3] != 0
3565 {
3566 t.rgba[3] = 255;
3567 t.origin_position = [mouse_pos.x, mouse_pos.y];
3568 };
3569 t.center_display.0 = if mouse_pos.x
3570 + self
3571 .get_text_size(&s.hint_text_name, ui)
3572 .unwrap()[0]
3573 <= ctx.available_rect().width()
3574 {
3575 HorizontalAlign::Left
3576 } else {
3577 HorizontalAlign::Right
3578 };
3579 t.center_display.1 = if mouse_pos.y
3580 + self
3581 .get_text_size(&s.hint_text_name, ui)
3582 .unwrap()[1]
3583 <= ctx.available_rect().height()
3584 {
3585 VerticalAlign::Top
3586 } else {
3587 VerticalAlign::Bottom
3588 };
3589 self.rust_constructor_resource[id3] = RCR::Text(t);
3590 };
3591 };
3592 };
3593 hovered = true;
3594 let mut clicked = vec![];
3595 let mut active = false;
3596 for u in 0..s.click_method.len() as u32 {
3597 clicked.push(ui.input(|i| {
3598 i.pointer.button_down(
3599 s.click_method[u as usize].click_method,
3600 )
3601 }));
3602 if clicked[u as usize] {
3603 active = true;
3604 s.last_time_clicked_index = u as usize;
3605 break;
3606 };
3607 }
3608 if active {
3609 s.last_time_clicked = true;
3610 if s.enable_hover_click_image[1] {
3611 if s.enable_hover_click_image[0] {
3612 appearance_count = 2;
3613 } else {
3614 appearance_count = 1;
3615 };
3616 } else if !s.enable_hover_click_image[0] {
3617 appearance_count = 0;
3618 };
3619 } else {
3620 if s.last_time_clicked {
3621 if play_sound {
3622 general_click_feedback(&s.sound_path);
3623 };
3624 let mut count = 1;
3625 if s.enable_hover_click_image[0] {
3626 count += 1;
3627 };
3628 if s.enable_hover_click_image[1] {
3629 count += 1;
3630 };
3631 if s.click_method[s.last_time_clicked_index].action {
3632 if s.state < (s.appearance.len() / count - 1) as u32
3633 {
3634 s.state += 1;
3635 } else {
3636 s.state = 0;
3637 };
3638 };
3639 activated[0] = s.last_time_clicked_index;
3640 s.last_time_clicked = false;
3641 };
3642 if s.enable_hover_click_image[0] {
3643 appearance_count = 1;
3644 } else {
3645 appearance_count = 0;
3646 };
3647 };
3648 } else {
3649 s.last_time_clicked = false;
3650 appearance_count = 0;
3651 };
3652 } else {
3653 s.last_time_clicked = false;
3654 appearance_count = 0;
3655 };
3656 } else {
3657 s.last_time_clicked = false;
3658 appearance_count = 0;
3659 };
3660 if !hovered && !s.hint_text_name.is_empty() {
3661 if s.last_time_hovered {
3662 self.add_split_time(&format!("{}HintFadeAnimation", s.name), true);
3663 };
3664 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3665 if let RCR::Text(mut t) =
3666 self.rust_constructor_resource[id3].clone()
3667 {
3668 if self.timer.total_time
3669 - self
3670 .split_time(&format!("{}HintFadeAnimation", s.name))
3671 .unwrap()[1]
3672 >= self.vertrefresh
3673 {
3674 t.rgba[3] = t.rgba[3].saturating_sub(1);
3675 };
3676 self.rust_constructor_resource[id3] = RCR::Text(t);
3677 };
3678 };
3679 };
3680 im.overlay_color = s.appearance
3681 [(s.state * s.animation_count + appearance_count) as usize]
3682 .color;
3683 if let Ok(id4) = self.get_resource_index(
3684 "ImageTexture",
3685 &s.appearance
3686 [(s.state * s.animation_count + appearance_count) as usize]
3687 .texture
3688 .clone(),
3689 ) {
3690 if let RCR::ImageTexture(it) =
3691 self.rust_constructor_resource[id4].clone()
3692 {
3693 im.image_texture = it.texture.clone();
3694 };
3695 };
3696 if !s.hint_text_name.is_empty() {
3697 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3698 if let RCR::Text(mut t) =
3699 self.rust_constructor_resource[id3].clone()
3700 {
3701 t.background_rgb[3] = t.rgba[3];
3702 t.text_content = s.appearance
3703 [(s.state * s.animation_count + appearance_count) as usize]
3704 .hint_text
3705 .clone();
3706 self.rust_constructor_resource[id3] = RCR::Text(t);
3707 };
3708 };
3709 };
3710 s.last_time_hovered = hovered;
3711 activated[1] = s.state as usize;
3712 self.rust_constructor_resource[id] = RCR::Switch(s.clone());
3713 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
3714 self.image(ui, &s.switch_image_name.clone(), ctx);
3715 if self.check_resource_exists("Text", &s.text_name) {
3716 if let Ok(id4) = self.get_resource_index("Text", &s.text_name) {
3717 if let RCR::Text(mut t2) =
3718 self.rust_constructor_resource[id4].clone()
3719 {
3720 t2.origin_position = [
3721 im.image_position[0] + s.text_origin_position[0],
3722 im.image_position[1] + s.text_origin_position[1],
3723 ];
3724 t2.text_content = s.appearance
3725 [(s.state * s.animation_count + appearance_count) as usize]
3726 .text
3727 .clone();
3728 self.rust_constructor_resource[id4] = RCR::Text(t2);
3729 };
3730 };
3731 self.text(ui, &s.text_name, ctx);
3732 };
3733 if self.check_resource_exists("Text", &s.hint_text_name) {
3734 self.text(ui, &s.hint_text_name, ctx);
3735 };
3736 Ok(activated)
3737 } else {
3738 Err(RustConstructorError::ImageNotFound {
3740 image_name: s.switch_image_name,
3741 })
3742 }
3743 } else {
3744 self.problem_report(
3745 RustConstructorError::ImageNotFound {
3746 image_name: name.to_string(),
3747 },
3748 SeverityLevel::SevereWarning,
3749 );
3750 Err(RustConstructorError::ImageNotFound {
3751 image_name: s.switch_image_name,
3752 })
3753 }
3754 } else {
3755 Err(RustConstructorError::SwitchNotFound {
3757 switch_name: name.to_string(),
3758 })
3759 }
3760 } else {
3761 self.problem_report(
3762 RustConstructorError::SwitchNotFound {
3763 switch_name: name.to_string(),
3764 },
3765 SeverityLevel::SevereWarning,
3766 );
3767 Err(RustConstructorError::SwitchNotFound {
3768 switch_name: name.to_string(),
3769 })
3770 }
3771 }
3772}