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 page_handler(&mut self, ctx: &egui::Context) {
929 self.update_frame_stats(ctx);
931 self.render_resource_list = Vec::new();
933 self.update_timer();
935 if let Ok(id) = self
936 .get_resource_index("PageData", &self.page.clone())
937 {
938 if let RCR::PageData(pd) = self.rust_constructor_resource[id].clone() {
939 if pd.forced_update {
940 ctx.request_repaint();
942 };
943 };
944 };
945 }
946
947 pub fn add_page(&mut self, name: &str, forced_update: bool) {
949 self.rust_constructor_resource.push(RCR::PageData(PageData {
950 discern_type: "PageData".to_string(),
951 name: name.to_string(),
952 forced_update,
953 change_page_updated: false,
954 enter_page_updated: false,
955 }));
956 }
957
958 pub fn switch_page(&mut self, page: &str) {
960 if let Ok(id) = self.get_resource_index("PageData", page) {
961 self.page = page.to_string();
962 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
963 pd.enter_page_updated = false;
964 self.timer.start_time = self.timer.total_time;
965 self.update_timer();
966 };
967 };
968 }
969
970 pub fn tray_icon_init(&mut self, icon_path: &str, tooltip: &str, menu: Box<Menu>) {
972 let icon = load_icon_from_file(icon_path).unwrap();
973 if let Ok(tray_icon) = TrayIconBuilder::new()
974 .with_menu(menu)
975 .with_tooltip(tooltip)
976 .with_icon(icon)
977 .with_icon_as_template(true)
978 .build()
979 {
980 self.tray_icon = Some(tray_icon);
981 self.tray_icon_created = true;
982 };
983 }
984
985 pub fn check_resource_exists(&mut self, resource_type: &str, resource_name: &str) -> bool {
987 for i in 0..self.rust_constructor_resource.len() {
988 match self.rust_constructor_resource[i].clone() {
989 RCR::Image(im) => {
990 if im.match_resource(resource_name, resource_type) {
991 return true;
992 }
993 }
994 RCR::Text(t) => {
995 if t.match_resource(resource_name, resource_type) {
996 return true;
997 }
998 }
999 RCR::CustomRect(cr) => {
1000 if cr.match_resource(resource_name, resource_type) {
1001 return true;
1002 }
1003 }
1004 RCR::ScrollBackground(sb) => {
1005 if sb.match_resource(resource_name, resource_type) {
1006 return true;
1007 }
1008 }
1009 RCR::Variable(v) => {
1010 if v.match_resource(resource_name, resource_type) {
1011 return true;
1012 }
1013 }
1014 RCR::Font(f) => {
1015 if f.match_resource(resource_name, resource_type) {
1016 return true;
1017 }
1018 }
1019 RCR::SplitTime(st) => {
1020 if st.match_resource(resource_name, resource_type) {
1021 return true;
1022 }
1023 }
1024 RCR::Switch(s) => {
1025 if s.match_resource(resource_name, resource_type) {
1026 return true;
1027 }
1028 }
1029 RCR::MessageBox(mb) => {
1030 if mb.match_resource(resource_name, resource_type) {
1031 return true;
1032 }
1033 }
1034 RCR::ImageTexture(it) => {
1035 if it.match_resource(resource_name, resource_type) {
1036 return true;
1037 }
1038 }
1039 RCR::PageData(pd) => {
1040 if pd.match_resource(resource_name, resource_type) {
1041 return true;
1042 }
1043 }
1044 }
1045 }
1046 false
1047 }
1048
1049 pub fn get_resource_index(
1051 &mut self,
1052 resource_type: &str,
1053 resource_name: &str,
1054 ) -> Result<usize, RustConstructorError> {
1055 for i in 0..self.rust_constructor_resource.len() {
1056 match self.rust_constructor_resource[i].clone() {
1057 RCR::Image(im) => {
1058 if im.match_resource(resource_name, resource_type) {
1059 return Ok(i);
1060 }
1061 }
1062 RCR::Text(t) => {
1063 if t.match_resource(resource_name, resource_type) {
1064 return Ok(i);
1065 }
1066 }
1067 RCR::CustomRect(cr) => {
1068 if cr.match_resource(resource_name, resource_type) {
1069 return Ok(i);
1070 }
1071 }
1072 RCR::ScrollBackground(sb) => {
1073 if sb.match_resource(resource_name, resource_type) {
1074 return Ok(i);
1075 }
1076 }
1077 RCR::Variable(v) => {
1078 if v.match_resource(resource_name, resource_type) {
1079 return Ok(i);
1080 }
1081 }
1082 RCR::Font(f) => {
1083 if f.match_resource(resource_name, resource_type) {
1084 return Ok(i);
1085 }
1086 }
1087 RCR::SplitTime(st) => {
1088 if st.match_resource(resource_name, resource_type) {
1089 return Ok(i);
1090 }
1091 }
1092 RCR::Switch(s) => {
1093 if s.match_resource(resource_name, resource_type) {
1094 return Ok(i);
1095 }
1096 }
1097 RCR::MessageBox(mb) => {
1098 if mb.match_resource(resource_name, resource_type) {
1099 return Ok(i);
1100 }
1101 }
1102 RCR::ImageTexture(it) => {
1103 if it.match_resource(resource_name, resource_type) {
1104 return Ok(i);
1105 }
1106 }
1107 RCR::PageData(pd) => {
1108 if pd.match_resource(resource_name, resource_type) {
1109 return Ok(i);
1110 }
1111 }
1112 };
1113 }
1114 self.problem_report(
1115 RustConstructorError::ResourceNotFound {
1116 resource_name: resource_name.to_string(),
1117 resource_type: resource_type.to_string(),
1118 },
1119 SeverityLevel::SevereWarning,
1120 );
1121 Err(RustConstructorError::ResourceNotFound {
1122 resource_name: resource_name.to_string(),
1123 resource_type: resource_type.to_string(),
1124 })
1125 }
1126
1127 pub fn add_fonts(&mut self, font_name: &str, font_path: &str) {
1129 let mut fonts = FontDefinitions::default();
1130 if let Ok(font_read_data) = std::fs::read(font_path) {
1131 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
1132 fonts.font_data.insert(
1133 font_name.to_owned(),
1134 Arc::new(FontData::from_owned(
1135 Arc::try_unwrap(font_data).ok().unwrap(),
1136 )),
1137 );
1138
1139 fonts
1141 .families
1142 .entry(egui::FontFamily::Proportional)
1143 .or_default()
1144 .insert(0, font_name.to_owned());
1145
1146 fonts
1147 .families
1148 .entry(egui::FontFamily::Monospace)
1149 .or_default()
1150 .insert(0, font_name.to_owned());
1151
1152 self.rust_constructor_resource.push(RCR::Font(Font {
1153 name: font_name.to_string(),
1154 discern_type: "Font".to_string(),
1155 font_definitions: fonts,
1156 path: font_path.to_string(),
1157 }));
1158 } else {
1159 self.problem_report(
1160 RustConstructorError::FontGetFailed {
1161 font_path: font_path.to_string(),
1162 },
1163 SeverityLevel::SevereWarning,
1164 );
1165 };
1166 }
1169
1170 pub fn font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
1172 if let Ok(id) = self.get_resource_index("Font", name) {
1173 if let RCR::Font(f) = &mut self.rust_constructor_resource[id] {
1174 return Ok(f.font_definitions.clone());
1175 }
1176 }
1177 self.problem_report(
1178 RustConstructorError::FontNotFound {
1179 font_name: name.to_string(),
1180 },
1181 SeverityLevel::SevereWarning,
1182 );
1183 Err(RustConstructorError::FontNotFound {
1184 font_name: name.to_string(),
1185 })
1186 }
1187
1188 pub fn register_all_fonts(&mut self, ctx: &egui::Context) {
1190 let mut font_definitions = egui::FontDefinitions::default();
1191 let mut font_resources = Vec::new();
1192 for i in 0..self.rust_constructor_resource.len() {
1193 if let RCR::Font(f) = &self.rust_constructor_resource[i] {
1194 font_resources.push(f.clone());
1195 };
1196 }
1197 for i in &font_resources {
1198 let font_name = i.name.clone();
1199 if let Ok(font_def) = self.font(&font_name) {
1201 if let Some(font_data) = font_def.font_data.get(&font_name) {
1203 font_definitions
1204 .font_data
1205 .insert(font_name.clone(), Arc::clone(font_data));
1206 font_definitions
1207 .families
1208 .entry(egui::FontFamily::Name(font_name.clone().into()))
1209 .or_default()
1210 .push(font_name.clone());
1211 };
1212
1213 font_definitions
1215 .families
1216 .entry(egui::FontFamily::Proportional)
1217 .or_default()
1218 .insert(0, font_name.to_owned());
1219
1220 font_definitions
1221 .families
1222 .entry(egui::FontFamily::Monospace)
1223 .or_default()
1224 .insert(0, font_name.to_owned());
1225 };
1226 }
1227 ctx.set_fonts(font_definitions);
1228 }
1229
1230 pub fn problem_report(
1232 &mut self,
1233 problem_type: RustConstructorError,
1234 severity_level: SeverityLevel,
1235 ) {
1236 let (problem, annotation) = match problem_type.clone() {
1237 RustConstructorError::FontGetFailed { font_path } => (
1238 format!("Font get failed: {}", font_path,),
1239 "Please check if the font file exists and the path is correct.",
1240 ),
1241 RustConstructorError::FontNotFound { font_name } => (
1242 format!("Font not found: {}", font_name,),
1243 "Please check whether the font has been added.",
1244 ),
1245 RustConstructorError::ImageGetFailed { image_path } => (
1246 format!("Image get failed: {}", image_path,),
1247 "Please check whether the image path is correct and whether the image has been added.",
1248 ),
1249 RustConstructorError::ImageNotFound { image_name } => (
1250 format!("Image not found: {}", image_name,),
1251 "Please check whether the image has been added.",
1252 ),
1253 RustConstructorError::TextNotFound { text_name } => (
1254 format!("Text not found: {}", text_name,),
1255 "Please check whether the text has been added.",
1256 ),
1257 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
1258 format!("Message box already exists: {}", message_box_name),
1259 "Please check whether the code for generating the message box has been accidentally called multiple times.",
1260 ),
1261 RustConstructorError::SplitTimeNotFound { split_time_name } => (
1262 format!("Split time not found: {}", split_time_name,),
1263 "Please check whether the split time has been added.",
1264 ),
1265 RustConstructorError::SwitchAppearanceMismatch {
1266 switch_name,
1267 differ,
1268 } => (
1269 format!(
1270 "Switch appearance list's number of items is large / small {} more: {}",
1271 differ, switch_name
1272 ),
1273 "Please check whether the number of appearance list items matches the number of enabled animations.",
1274 ),
1275 RustConstructorError::SwitchNotFound { switch_name } => (
1276 format!("Switch not found: {}", switch_name,),
1277 "Please check whether the switch has been added.",
1278 ),
1279 RustConstructorError::PageNotFound { page_name } => (
1280 format!("Page not found: {}", page_name,),
1281 "Please check whether the page has been added.",
1282 ),
1283 RustConstructorError::VariableNotFound { variable_name } => (
1284 format!("Variable not found: {}", variable_name,),
1285 "Please check whether the variable has been added.",
1286 ),
1287 RustConstructorError::VariableNotBool { variable_name } => (
1288 format!("Variable is not bool: {}", variable_name,),
1289 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1290 ),
1291 RustConstructorError::VariableNotFloat { variable_name } => (
1292 format!("Variable is not f32: {}", variable_name,),
1293 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1294 ),
1295 RustConstructorError::VariableNotInt { variable_name } => (
1296 format!("Variable is not int: {}", variable_name,),
1297 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1298 ),
1299 RustConstructorError::VariableNotString { variable_name } => (
1300 format!("Variable is not string: {}", variable_name,),
1301 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1302 ),
1303 RustConstructorError::VariableNotUInt { variable_name } => (
1304 format!("Variable is not uint: {}", variable_name,),
1305 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1306 ),
1307 RustConstructorError::VariableNotVec { variable_name } => (
1308 format!("Variable is not vec: {}", variable_name,),
1309 "Please check whether the variable names and types are correct and whether there are duplicate items.",
1310 ),
1311 RustConstructorError::ResourceNotFound {
1312 resource_name,
1313 resource_type,
1314 } => (
1315 format!(
1316 "Resource not found: {}(\"{}\")",
1317 resource_type, resource_name,
1318 ),
1319 "Please check whether the resource has been added.",
1320 ),
1321 };
1322 if self.config.rc_strict_mode {
1324 panic!("{}", problem);
1325 } else {
1326 let sound = self.config.problem_report_sound.clone();
1327 std::thread::spawn(move || {
1328 play_wav(&sound).unwrap_or(0_f64);
1329 });
1330 self.problem_list.push(Problem {
1331 severity_level,
1332 problem,
1333 annotation: annotation.to_string(),
1334 report_state: ReportState {
1335 current_page: self.page.clone(),
1336 current_total_runtime: self.timer.total_time,
1337 current_page_runtime: self.timer.now_time,
1338 },
1339 problem_type: problem_type.clone(),
1340 });
1341 };
1342 }
1343
1344 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
1346 if let Ok(id) = self.get_resource_index("PageData", name) {
1347 if let RCR::PageData(pd) = self.rust_constructor_resource[id].clone() {
1348 if !pd.change_page_updated {
1349 self.new_page_update(name);
1350 };
1351 return Ok(pd.change_page_updated);
1352 };
1353 };
1354 self.problem_report(
1355 RustConstructorError::PageNotFound {
1356 page_name: name.to_string(),
1357 },
1358 SeverityLevel::SevereWarning,
1359 );
1360 Err(RustConstructorError::PageNotFound {
1361 page_name: name.to_string(),
1362 })
1363 }
1364
1365 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
1367 if let Ok(id) = self.get_resource_index("PageData", name) {
1368 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1369 let return_value = pd.enter_page_updated;
1370 pd.enter_page_updated = true;
1371 return Ok(return_value);
1372 };
1373 };
1374 self.problem_report(
1375 RustConstructorError::PageNotFound {
1376 page_name: name.to_string(),
1377 },
1378 SeverityLevel::SevereWarning,
1379 );
1380 Err(RustConstructorError::PageNotFound {
1381 page_name: name.to_string(),
1382 })
1383 }
1384
1385 pub fn new_page_update(&mut self, name: &str) {
1387 if let Ok(id) = self.get_resource_index("PageData", name) {
1388 self.timer.start_time = self.timer.total_time;
1389 self.update_timer();
1390 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1391 pd.change_page_updated = true;
1392 };
1393 };
1394 }
1395
1396 pub fn update_frame_stats(&mut self, ctx: &egui::Context) {
1398 let current_time = ctx.input(|i| i.time);
1399 if let Some(last) = self.last_frame_time {
1400 let delta = (current_time - last) as f32;
1401 self.frame_times.push(delta);
1402 const MAX_SAMPLES: usize = 120;
1403 if self.frame_times.len() > MAX_SAMPLES {
1404 let remove_count = self.frame_times.len() - MAX_SAMPLES;
1405 self.frame_times.drain(0..remove_count);
1406 }
1407 }
1408 self.last_frame_time = Some(current_time);
1409 }
1410
1411 pub fn current_fps(&self) -> f32 {
1413 if self.frame_times.is_empty() {
1414 0.0
1415 } else {
1416 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
1417 }
1418 }
1419
1420 pub fn add_split_time(&mut self, name: &str, reset: bool) {
1422 if reset {
1423 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1424 if let RCR::SplitTime(st) = &mut self.rust_constructor_resource[id] {
1425 st.time = [self.timer.now_time, self.timer.total_time];
1426 };
1427 };
1428 } else {
1429 self.rust_constructor_resource
1430 .push(RCR::SplitTime(SplitTime {
1431 discern_type: "SplitTime".to_string(),
1432 name: name.to_string(),
1433 time: [self.timer.now_time, self.timer.total_time],
1434 }));
1435 };
1436 }
1437
1438 pub fn split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
1440 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1441 if let RCR::SplitTime(st) = self.rust_constructor_resource[id].clone() {
1442 return Ok(st.time);
1443 };
1444 };
1445 self.problem_report(
1446 RustConstructorError::SplitTimeNotFound {
1447 split_time_name: name.to_string(),
1448 },
1449 SeverityLevel::SevereWarning,
1450 );
1451 Err(RustConstructorError::SplitTimeNotFound {
1452 split_time_name: name.to_string(),
1453 })
1454 }
1455
1456 pub fn update_timer(&mut self) {
1458 let elapsed = self.timer.timer.elapsed();
1459 let seconds = elapsed.as_secs();
1460 let milliseconds = elapsed.subsec_millis();
1461 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
1462 self.timer.now_time = self.timer.total_time - self.timer.start_time
1463 }
1464
1465 pub fn add_rect(
1467 &mut self,
1468 name: &str,
1469 position_size_and_rounding: [f32; 5],
1470 grid: [u32; 4],
1471 center_display: (HorizontalAlign, VerticalAlign),
1472 color: [u8; 8],
1473 border_width: f32,
1474 ) {
1475 self.rust_constructor_resource
1476 .push(RCR::CustomRect(CustomRect {
1477 discern_type: "CustomRect".to_string(),
1478 name: name.to_string(),
1479 position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1480 size: [position_size_and_rounding[2], position_size_and_rounding[3]],
1481 rounding: position_size_and_rounding[4],
1482 x_grid: [grid[0], grid[1]],
1483 y_grid: [grid[2], grid[3]],
1484 center_display,
1485 color: [color[0], color[1], color[2], color[3]],
1486 border_width,
1487 border_color: [color[4], color[5], color[6], color[7]],
1488 origin_position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1489 }));
1490 }
1491
1492 pub fn rect(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1494 if let Ok(id) = self.get_resource_index("CustomRect", name) {
1495 if let RCR::CustomRect(cr) = &mut self.rust_constructor_resource[id] {
1496 cr.reg_render_resource(&mut self.render_resource_list);
1497 cr.position[0] = match cr.x_grid[1] {
1498 0 => cr.origin_position[0],
1499 _ => {
1500 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64
1501 * cr.x_grid[0] as f64) as f32
1502 + cr.origin_position[0]
1503 }
1504 };
1505 cr.position[1] = match cr.y_grid[1] {
1506 0 => cr.origin_position[1],
1507 _ => {
1508 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64
1509 * cr.y_grid[0] as f64) as f32
1510 + cr.origin_position[1]
1511 }
1512 };
1513 let pos_x = match cr.center_display.0 {
1514 HorizontalAlign::Left => cr.position[0],
1515 HorizontalAlign::Center => cr.position[0] - cr.size[0] / 2.0,
1516 HorizontalAlign::Right => cr.position[0] - cr.size[0],
1517 };
1518 let pos_y = match cr.center_display.1 {
1519 VerticalAlign::Top => cr.position[1],
1520 VerticalAlign::Center => cr.position[1] - cr.size[1] / 2.0,
1521 VerticalAlign::Bottom => cr.position[1] - cr.size[1],
1522 };
1523 ui.painter().rect(
1524 Rect::from_min_max(
1525 Pos2::new(pos_x, pos_y),
1526 Pos2::new(pos_x + cr.size[0], pos_y + cr.size[1]),
1527 ),
1528 cr.rounding,
1529 Color32::from_rgba_unmultiplied(
1530 cr.color[0],
1531 cr.color[1],
1532 cr.color[2],
1533 cr.color[3],
1534 ),
1535 Stroke {
1536 width: cr.border_width,
1537 color: Color32::from_rgba_unmultiplied(
1538 cr.border_color[0],
1539 cr.border_color[1],
1540 cr.border_color[2],
1541 cr.border_color[3],
1542 ),
1543 },
1544 egui::StrokeKind::Inside,
1545 );
1546 };
1547 };
1548 }
1549
1550 pub fn add_text(
1552 &mut self,
1553 name_content_and_font: [&str; 3],
1554 position_font_size_wrap_width_rounding: [f32; 5],
1555 color: [u8; 8],
1556 center_display_write_background_and_enable_copy: (
1557 HorizontalAlign,
1558 VerticalAlign,
1559 bool,
1560 bool,
1561 ),
1562 grid: [u32; 4],
1563 hyperlink_text: Vec<(usize, usize, &str)>,
1564 ) {
1565 self.rust_constructor_resource.push(RCR::Text(Text {
1566 discern_type: "Text".to_string(),
1567 name: name_content_and_font[0].to_string(),
1568 text_content: name_content_and_font[1].to_string(),
1569 font_size: position_font_size_wrap_width_rounding[2],
1570 rgba: [color[0], color[1], color[2], color[3]],
1571 position: [
1572 position_font_size_wrap_width_rounding[0],
1573 position_font_size_wrap_width_rounding[1],
1574 ],
1575 center_display: (
1576 center_display_write_background_and_enable_copy.0,
1577 center_display_write_background_and_enable_copy.1,
1578 ),
1579 wrap_width: position_font_size_wrap_width_rounding[3],
1580 write_background: center_display_write_background_and_enable_copy.2,
1581 background_rgb: [color[4], color[5], color[6], color[7]],
1582 rounding: position_font_size_wrap_width_rounding[4],
1583 x_grid: [grid[0], grid[1]],
1584 y_grid: [grid[2], grid[3]],
1585 origin_position: [
1586 position_font_size_wrap_width_rounding[0],
1587 position_font_size_wrap_width_rounding[1],
1588 ],
1589 font: name_content_and_font[2].to_string(),
1590 selection: None,
1591 selectable: center_display_write_background_and_enable_copy.3,
1592 hyperlink_text: hyperlink_text
1593 .into_iter()
1594 .map(|(a, b, c)| {
1595 (
1596 a,
1597 if b > name_content_and_font[1].len() {
1598 name_content_and_font[1].len()
1599 } else {
1600 b
1601 },
1602 c.to_string(),
1603 )
1604 })
1605 .collect(),
1606 }));
1607 }
1608
1609 pub fn text(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1611 if let Ok(id) = self.get_resource_index("Text", name) {
1612 if let RCR::Text(mut t) = self.rust_constructor_resource[id].clone() {
1613 t.reg_render_resource(&mut self.render_resource_list);
1614 let galley = ui.fonts(|f| {
1616 f.layout(
1617 t.text_content.to_string(),
1618 if self.check_resource_exists("Font", &t.font.clone()) {
1619 FontId::new(t.font_size, egui::FontFamily::Name(t.font.clone().into()))
1620 } else {
1621 FontId::proportional(t.font_size)
1622 },
1623 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
1624 t.wrap_width,
1625 )
1626 });
1627 let text_size = galley.size();
1628 t.position[0] = match t.x_grid[1] {
1629 0 => t.origin_position[0],
1630 _ => {
1631 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64
1632 * t.x_grid[0] as f64) as f32
1633 + t.origin_position[0]
1634 }
1635 };
1636 t.position[1] = match t.y_grid[1] {
1637 0 => t.origin_position[1],
1638 _ => {
1639 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64
1640 * t.y_grid[0] as f64) as f32
1641 + t.origin_position[1]
1642 }
1643 };
1644 let pos_x = match t.center_display.0 {
1645 HorizontalAlign::Left => t.position[0],
1646 HorizontalAlign::Center => t.position[0] - text_size.x / 2.0,
1647 HorizontalAlign::Right => t.position[0] - text_size.x,
1648 };
1649 let pos_y = match t.center_display.1 {
1650 VerticalAlign::Top => t.position[1],
1651 VerticalAlign::Center => t.position[1] - text_size.y / 2.0,
1652 VerticalAlign::Bottom => t.position[1] - text_size.y,
1653 };
1654 let position = Pos2::new(pos_x, pos_y);
1656
1657 if t.write_background {
1658 let rect = Rect::from_min_size(position, text_size);
1659 ui.painter().rect_filled(
1661 rect,
1662 t.rounding,
1663 Color32::from_rgba_unmultiplied(
1664 t.background_rgb[0],
1665 t.background_rgb[1],
1666 t.background_rgb[2],
1667 t.background_rgb[3],
1668 ),
1669 ); };
1671 ui.painter().galley(
1673 position,
1674 galley.clone(),
1675 Color32::from_rgba_unmultiplied(
1676 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3], ),
1678 );
1679
1680 if t.selectable {
1681 let rect = Rect::from_min_size(
1682 [position[0] - 20_f32, position[1] - 5_f32].into(),
1683 [text_size[0] + 40_f32, text_size[1] + 10_f32].into(),
1684 );
1685
1686 let rect2 = Rect::from_min_size(
1687 [0_f32, 0_f32].into(),
1688 [ctx.available_rect().width(), ctx.available_rect().height()].into(),
1689 );
1690
1691 let response = ui.interact(
1693 rect,
1694 egui::Id::new(format!("text_{}_click_and_drag", t.name)),
1695 egui::Sense::click_and_drag(),
1696 );
1697
1698 let response2 = ui.interact(
1699 rect2,
1700 egui::Id::new(format!("text_{}_total", t.name)),
1701 egui::Sense::click(),
1702 );
1703
1704 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
1706 let relative_pos = pointer_pos - position.to_vec2();
1707 let cursor = galley.cursor_from_pos(relative_pos);
1708 cursor.index
1709 };
1710
1711 if !response.clicked() && response2.clicked() {
1712 t.selection = None;
1713 };
1714
1715 if response.clicked() || response.drag_started() {
1716 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1717 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1718 t.selection = Some((cursor, cursor));
1719 };
1720 response.request_focus();
1721 };
1722
1723 if response.dragged() && t.selection.is_some() {
1724 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1725 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1726 if let Some((start, _)) = t.selection {
1727 t.selection = Some((start, cursor));
1728 };
1729 };
1730 };
1731
1732 if response.has_focus() {
1734 let copy_triggered = ui.input(|input| {
1736 let c_released = input.key_released(egui::Key::C);
1737 let cmd_pressed = input.modifiers.command || input.modifiers.mac_cmd;
1738 let ctrl_pressed = input.modifiers.ctrl;
1739 c_released && (cmd_pressed || ctrl_pressed)
1740 });
1741 if copy_triggered {
1742 if let Some((start, end)) = t.selection {
1743 let (start, end) = (start.min(end), start.max(end));
1744 let chars: Vec<char> = t.text_content.chars().collect();
1745 if start <= chars.len() && end <= chars.len() && start < end {
1746 let selected_text: String = chars[start..end].iter().collect();
1747 ui.ctx().copy_text(selected_text);
1748 };
1749 };
1750 };
1751 };
1752
1753 if let Some((start, end)) = t.selection {
1755 let (start, end) = (start.min(end), start.max(end));
1756 if start != end {
1757 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
1759 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
1760
1761 let start_pos = start_cursor.left_top();
1762 let end_pos = end_cursor.right_top();
1763 if start_pos.y == end_pos.y {
1765 let rows = &galley.rows;
1768 let row_height = if !rows.is_empty() {
1769 if let Some(row) = rows.first() {
1771 row.height()
1772 } else {
1773 text_size.y / t.text_content.lines().count() as f32
1774 }
1775 } else {
1776 text_size.y / t.text_content.lines().count() as f32
1777 };
1778
1779 let selection_rect = Rect::from_min_max(
1780 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1781 Pos2::new(
1782 position.x + end_pos.x,
1783 position.y + start_pos.y + row_height,
1784 ),
1785 );
1786 ui.painter().rect_filled(
1787 selection_rect,
1788 0.0,
1789 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1790 );
1791 } else {
1792 let rows = &galley.rows;
1794 let row_height = if !rows.is_empty() {
1795 rows[0].height()
1796 } else {
1797 text_size.y / t.text_content.lines().count() as f32
1798 };
1799
1800 let selection_top = position.y + start_pos.y.min(end_pos.y);
1802 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
1803
1804 let start_row_index = (start_pos.y / row_height).floor() as usize;
1806 let end_row_index = (end_pos.y / row_height).floor() as usize;
1807 let (first_row_index, last_row_index) =
1808 if start_row_index <= end_row_index {
1809 (start_row_index, end_row_index)
1810 } else {
1811 (end_row_index, start_row_index)
1812 };
1813
1814 for (i, row) in rows.iter().enumerate() {
1815 let row_y = position.y + row_height * i as f32;
1816 let row_bottom = row_y + row_height;
1817 if row_bottom > selection_top && row_y <= selection_bottom {
1819 let left = if i == first_row_index {
1820 position.x + start_pos.x
1822 } else {
1823 position.x + row.rect().min.x
1825 };
1826
1827 let right = if i == last_row_index {
1828 position.x + end_pos.x
1830 } else {
1831 position.x + row.rect().max.x
1833 };
1834
1835 let selection_rect = Rect::from_min_max(
1836 Pos2::new(left, row_y),
1837 Pos2::new(right, row_bottom),
1838 );
1839
1840 if selection_rect.width() > 0.0
1842 && selection_rect.height() > 0.0
1843 {
1844 ui.painter().rect_filled(
1845 selection_rect,
1846 0.0,
1847 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1848 );
1849 };
1850 };
1851 }
1852 };
1853 };
1854 };
1855 };
1856
1857 for (start, end, url) in &t.hyperlink_text {
1859 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
1861 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
1862
1863 let start_pos = start_cursor.left_top();
1864 let end_pos = end_cursor.right_top();
1865
1866 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1867
1868 let link_responses = if start_cursor.min.y == end_cursor.min.y {
1870 let link_rect = Rect::from_min_max(
1872 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1873 Pos2::new(
1874 position.x + end_pos.x,
1875 position.y + start_pos.y + row_height,
1876 ),
1877 );
1878 vec![ui.interact(
1879 link_rect,
1880 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
1881 egui::Sense::click(),
1882 )]
1883 } else {
1884 let start_row = (start_pos.y / row_height).round() as usize;
1886 let end_row = (end_pos.y / row_height).round() as usize;
1887 let mut responses = Vec::new();
1888
1889 for row in start_row..=end_row {
1890 if let Some(current_row) = galley.rows.get(row) {
1891 let row_rect = current_row.rect();
1892 let row_y = position.y + row as f32 * row_height;
1893
1894 let link_rect = if row == start_row {
1895 Rect::from_min_max(
1897 Pos2::new(position.x + start_pos.x, row_y),
1898 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1899 )
1900 } else if row == end_row {
1901 Rect::from_min_max(
1903 Pos2::new(position.x + row_rect.min.x, row_y),
1904 Pos2::new(position.x + end_pos.x, row_y + row_height),
1905 )
1906 } else {
1907 Rect::from_min_max(
1909 Pos2::new(position.x + row_rect.min.x, row_y),
1910 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1911 )
1912 };
1913
1914 responses.push(ui.interact(
1915 link_rect,
1916 egui::Id::new(format!(
1917 "link_{}_{}_{}_row_{}",
1918 t.name, start, end, row
1919 )),
1920 egui::Sense::click(),
1921 ));
1922 };
1923 }
1924 responses
1925 };
1926
1927 let mut is_pressing_link = false;
1929 for link_response in &link_responses {
1930 if link_response.is_pointer_button_down_on()
1931 && !link_response.drag_started()
1932 {
1933 t.selection = None;
1934 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1935 let relative_pos = pointer_pos - position.to_vec2();
1936 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1937 if cursor.index >= *start && cursor.index <= *end {
1938 is_pressing_link = true;
1939 break;
1940 };
1941 };
1942 };
1943 }
1944
1945 let mut clicked_on_link = false;
1947 for link_response in &link_responses {
1948 if link_response.clicked() {
1949 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1950 let relative_pos = pointer_pos - position.to_vec2();
1951 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1952 if cursor.index >= *start && cursor.index <= *end {
1953 clicked_on_link = true;
1954 break;
1955 };
1956 };
1957 };
1958 }
1959
1960 if clicked_on_link {
1961 if !url.is_empty() {
1963 ui.ctx().open_url(egui::OpenUrl::new_tab(url));
1964 };
1965 };
1966
1967 if is_pressing_link {
1969 if start_cursor.min.y == end_cursor.min.y {
1970 let selection_rect = Rect::from_min_max(
1972 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1973 Pos2::new(
1974 position.x + end_pos.x,
1975 position.y
1976 + start_pos.y
1977 + galley.rows.first().map_or(14.0, |row| row.height()),
1978 ),
1979 );
1980 ui.painter().rect_filled(
1981 selection_rect,
1982 0.0,
1983 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1984 );
1985 } else {
1986 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1988 let start_row = (start_pos.y / row_height).round() as usize;
1989 let end_row = (end_pos.y / row_height).round() as usize;
1990
1991 for row in start_row..=end_row {
1992 if let Some(current_row) = galley.rows.get(row) {
1993 let row_rect = current_row.rect();
1994
1995 if row == start_row {
1996 let selection_rect = Rect::from_min_max(
1998 Pos2::new(
1999 position.x + start_pos.x,
2000 position.y + row as f32 * row_height,
2001 ),
2002 Pos2::new(
2003 position.x + row_rect.max.x,
2004 position.y + row as f32 * row_height + row_height,
2005 ),
2006 );
2007 ui.painter().rect_filled(
2008 selection_rect,
2009 0.0,
2010 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2011 );
2012 } else if row == end_row {
2013 let selection_rect = Rect::from_min_max(
2015 Pos2::new(
2016 position.x + row_rect.min.x,
2017 position.y + row as f32 * row_height,
2018 ),
2019 Pos2::new(
2020 position.x + end_pos.x,
2021 position.y + row as f32 * row_height + row_height,
2022 ),
2023 );
2024 ui.painter().rect_filled(
2025 selection_rect,
2026 0.0,
2027 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2028 );
2029 } else {
2030 let selection_rect = Rect::from_min_max(
2032 Pos2::new(
2033 position.x + row_rect.min.x,
2034 position.y + row as f32 * row_height,
2035 ),
2036 Pos2::new(
2037 position.x + row_rect.max.x,
2038 position.y + row as f32 * row_height + row_height,
2039 ),
2040 );
2041 ui.painter().rect_filled(
2042 selection_rect,
2043 0.0,
2044 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2045 );
2046 };
2047 };
2048 }
2049 };
2050 };
2051
2052 if start_cursor.min.y == end_cursor.min.y {
2055 let underline_y = position.y
2057 + start_pos.y
2058 + galley.rows.first().map_or(14.0, |row| row.height())
2059 - 2.0;
2060
2061 let color = Color32::from_rgba_unmultiplied(
2063 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2064 );
2065
2066 ui.painter().line_segment(
2067 [
2068 Pos2::new(position.x + start_pos.x, underline_y),
2069 Pos2::new(position.x + end_pos.x, underline_y),
2070 ],
2071 Stroke::new(t.font_size / 10_f32, color),
2072 );
2073 } else {
2074 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2079 let end_row = (end_pos.y / row_height).round() as usize;
2080
2081 for row in start_row..=end_row {
2082 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
2086 let row_rect = current_row.rect();
2087
2088 let color = Color32::from_rgba_unmultiplied(
2089 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2090 );
2091
2092 if row == start_row {
2093 ui.painter().line_segment(
2095 [
2096 Pos2::new(position.x + start_pos.x, row_y),
2097 Pos2::new(position.x + row_rect.max.x, row_y),
2098 ],
2099 Stroke::new(t.font_size / 10_f32, color),
2100 );
2101 } else if row == end_row {
2102 ui.painter().line_segment(
2104 [
2105 Pos2::new(position.x + row_rect.min.x, row_y),
2106 Pos2::new(position.x + end_pos.x, row_y),
2107 ],
2108 Stroke::new(t.font_size / 10_f32, color),
2109 );
2110 } else {
2111 ui.painter().line_segment(
2113 [
2114 Pos2::new(position.x + row_rect.min.x, row_y),
2115 Pos2::new(position.x + row_rect.max.x, row_y),
2116 ],
2117 Stroke::new(t.font_size / 10_f32, color),
2118 );
2119 };
2120 };
2121 }
2122 };
2123 }
2124 self.rust_constructor_resource[id] = RCR::Text(t);
2125 };
2126 };
2127 }
2128
2129 pub fn get_text_size(
2131 &mut self,
2132 resource_name: &str,
2133 ui: &mut Ui,
2134 ) -> Result<[f32; 2], RustConstructorError> {
2135 if let Ok(id) = self.get_resource_index("Text", resource_name) {
2136 if let RCR::Text(t) = self.rust_constructor_resource[id].clone() {
2137 let galley = ui.fonts(|f| {
2138 f.layout(
2139 t.text_content.to_string(),
2140 FontId::proportional(t.font_size),
2141 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
2142 t.wrap_width,
2143 )
2144 });
2145 return Ok([galley.size().x, galley.size().y]);
2146 };
2147 };
2148 self.problem_report(
2149 RustConstructorError::TextNotFound {
2150 text_name: resource_name.to_string(),
2151 },
2152 SeverityLevel::SevereWarning,
2153 );
2154 Err(RustConstructorError::TextNotFound {
2155 text_name: resource_name.to_string(),
2156 })
2157 }
2158
2159 pub fn add_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2161 self.rust_constructor_resource.push(RCR::Variable(Variable {
2162 discern_type: "Variable".to_string(),
2163 name: name.to_string(),
2164 value: value.into(),
2165 }));
2166 }
2167
2168 pub fn modify_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2170 if let Ok(id) = self.get_resource_index("Variable", name) {
2171 if let RCR::Variable(v) = &mut self.rust_constructor_resource[id] {
2172 v.value = value.into();
2173 };
2174 };
2175 }
2176
2177 pub fn var(&mut self, name: &str) -> Result<Value, RustConstructorError> {
2179 if let Ok(id) = self.get_resource_index("Variable", name) {
2180 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2181 return Ok(v.clone().value);
2182 };
2183 };
2184 self.problem_report(
2185 RustConstructorError::VariableNotFound {
2186 variable_name: name.to_string(),
2187 },
2188 SeverityLevel::SevereWarning,
2189 );
2190 Err(RustConstructorError::VariableNotFound {
2191 variable_name: name.to_string(),
2192 })
2193 }
2194
2195 pub fn var_i(&mut self, name: &str) -> Result<i32, RustConstructorError> {
2197 if let Ok(id) = self.get_resource_index("Variable", name) {
2198 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2199 match &v.value {
2200 Value::Int(i) => Ok(*i),
2202 _ => {
2203 self.problem_report(
2204 RustConstructorError::VariableNotInt {
2205 variable_name: name.to_string(),
2206 },
2207 SeverityLevel::SevereWarning,
2208 );
2209 Err(RustConstructorError::VariableNotInt {
2210 variable_name: name.to_string(),
2211 })
2212 }
2213 }
2214 } else {
2215 Err(RustConstructorError::VariableNotFound {
2217 variable_name: name.to_string(),
2218 })
2219 }
2220 } else {
2221 self.problem_report(
2222 RustConstructorError::VariableNotFound {
2223 variable_name: name.to_string(),
2224 },
2225 SeverityLevel::SevereWarning,
2226 );
2227 Err(RustConstructorError::VariableNotFound {
2228 variable_name: name.to_string(),
2229 })
2230 }
2231 }
2232
2233 pub fn var_u(&mut self, name: &str) -> Result<u32, RustConstructorError> {
2235 if let Ok(id) = self.get_resource_index("Variable", name) {
2236 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2237 match &v.value {
2238 Value::UInt(u) => Ok(*u),
2240 _ => {
2241 self.problem_report(
2242 RustConstructorError::VariableNotUInt {
2243 variable_name: name.to_string(),
2244 },
2245 SeverityLevel::SevereWarning,
2246 );
2247 Err(RustConstructorError::VariableNotUInt {
2248 variable_name: name.to_string(),
2249 })
2250 }
2251 }
2252 } else {
2253 Err(RustConstructorError::VariableNotFound {
2255 variable_name: name.to_string(),
2256 })
2257 }
2258 } else {
2259 self.problem_report(
2260 RustConstructorError::VariableNotFound {
2261 variable_name: name.to_string(),
2262 },
2263 SeverityLevel::SevereWarning,
2264 );
2265 Err(RustConstructorError::VariableNotFound {
2266 variable_name: name.to_string(),
2267 })
2268 }
2269 }
2270
2271 pub fn var_f(&mut self, name: &str) -> Result<f32, RustConstructorError> {
2273 if let Ok(id) = self.get_resource_index("Variable", name) {
2274 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2275 match &v.value {
2276 Value::Float(f) => Ok(*f),
2278 _ => {
2279 self.problem_report(
2280 RustConstructorError::VariableNotFloat {
2281 variable_name: name.to_string(),
2282 },
2283 SeverityLevel::SevereWarning,
2284 );
2285 Err(RustConstructorError::VariableNotFloat {
2286 variable_name: name.to_string(),
2287 })
2288 }
2289 }
2290 } else {
2291 Err(RustConstructorError::VariableNotFound {
2293 variable_name: name.to_string(),
2294 })
2295 }
2296 } else {
2297 self.problem_report(
2298 RustConstructorError::VariableNotFound {
2299 variable_name: name.to_string(),
2300 },
2301 SeverityLevel::SevereWarning,
2302 );
2303 Err(RustConstructorError::VariableNotFound {
2304 variable_name: name.to_string(),
2305 })
2306 }
2307 }
2308
2309 pub fn var_b(&mut self, name: &str) -> Result<bool, RustConstructorError> {
2311 if let Ok(id) = self.get_resource_index("Variable", name) {
2312 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2313 match &v.value {
2314 Value::Bool(b) => Ok(*b),
2316 _ => {
2317 self.problem_report(
2318 RustConstructorError::VariableNotBool {
2319 variable_name: name.to_string(),
2320 },
2321 SeverityLevel::SevereWarning,
2322 );
2323 Err(RustConstructorError::VariableNotBool {
2324 variable_name: name.to_string(),
2325 })
2326 }
2327 }
2328 } else {
2329 Err(RustConstructorError::VariableNotFound {
2331 variable_name: name.to_string(),
2332 })
2333 }
2334 } else {
2335 self.problem_report(
2336 RustConstructorError::VariableNotFound {
2337 variable_name: name.to_string(),
2338 },
2339 SeverityLevel::SevereWarning,
2340 );
2341 Err(RustConstructorError::VariableNotFound {
2342 variable_name: name.to_string(),
2343 })
2344 }
2345 }
2346
2347 pub fn var_v(&mut self, name: &str) -> Result<Vec<Value>, RustConstructorError> {
2349 if let Ok(id) = self.get_resource_index("Variable", name) {
2350 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2351 match &v.value {
2352 Value::Vec(v) => Ok(v.clone()),
2354 _ => {
2355 self.problem_report(
2356 RustConstructorError::VariableNotVec {
2357 variable_name: name.to_string(),
2358 },
2359 SeverityLevel::SevereWarning,
2360 );
2361 Err(RustConstructorError::VariableNotVec {
2362 variable_name: name.to_string(),
2363 })
2364 }
2365 }
2366 } else {
2367 Err(RustConstructorError::VariableNotFound {
2369 variable_name: name.to_string(),
2370 })
2371 }
2372 } else {
2373 self.problem_report(
2374 RustConstructorError::VariableNotFound {
2375 variable_name: name.to_string(),
2376 },
2377 SeverityLevel::SevereWarning,
2378 );
2379 Err(RustConstructorError::VariableNotFound {
2380 variable_name: name.to_string(),
2381 })
2382 }
2383 }
2384
2385 pub fn var_s(&mut self, name: &str) -> Result<String, RustConstructorError> {
2387 if let Ok(id) = self.get_resource_index("Variable", name) {
2388 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2389 match &v.value {
2390 Value::String(s) => Ok(s.clone()),
2392 _ => {
2393 self.problem_report(
2394 RustConstructorError::VariableNotString {
2395 variable_name: name.to_string(),
2396 },
2397 SeverityLevel::SevereWarning,
2398 );
2399 Err(RustConstructorError::VariableNotString {
2400 variable_name: name.to_string(),
2401 })
2402 }
2403 }
2404 } else {
2405 Err(RustConstructorError::VariableNotFound {
2407 variable_name: name.to_string(),
2408 })
2409 }
2410 } else {
2411 self.problem_report(
2412 RustConstructorError::VariableNotFound {
2413 variable_name: name.to_string(),
2414 },
2415 SeverityLevel::SevereWarning,
2416 );
2417 Err(RustConstructorError::VariableNotFound {
2418 variable_name: name.to_string(),
2419 })
2420 }
2421 }
2422
2423 pub fn var_decode_b(&mut self, target: Value) -> Result<bool, RustConstructorError> {
2425 match target {
2426 Value::Bool(b) => {
2427 Ok(b)
2429 }
2430 _ => {
2431 self.problem_report(
2432 RustConstructorError::VariableNotBool {
2433 variable_name: format!("{:?}", target),
2434 },
2435 SeverityLevel::SevereWarning,
2436 );
2437 Err(RustConstructorError::VariableNotBool {
2438 variable_name: format!("{:?}", target),
2439 })
2440 }
2441 }
2442 }
2443
2444 pub fn var_decode_i(&mut self, target: Value) -> Result<i32, RustConstructorError> {
2446 match target {
2447 Value::Int(i) => {
2448 Ok(i)
2450 }
2451 _ => {
2452 self.problem_report(
2453 RustConstructorError::VariableNotInt {
2454 variable_name: format!("{:?}", target),
2455 },
2456 SeverityLevel::SevereWarning,
2457 );
2458 Err(RustConstructorError::VariableNotInt {
2459 variable_name: format!("{:?}", target),
2460 })
2461 }
2462 }
2463 }
2464
2465 pub fn var_decode_u(&mut self, target: Value) -> Result<u32, RustConstructorError> {
2467 match target {
2468 Value::UInt(u) => {
2469 Ok(u)
2471 }
2472 _ => {
2473 self.problem_report(
2474 RustConstructorError::VariableNotUInt {
2475 variable_name: format!("{:?}", target),
2476 },
2477 SeverityLevel::SevereWarning,
2478 );
2479 Err(RustConstructorError::VariableNotUInt {
2480 variable_name: format!("{:?}", target),
2481 })
2482 }
2483 }
2484 }
2485
2486 pub fn var_decode_f(&mut self, target: Value) -> Result<f32, RustConstructorError> {
2488 match target {
2489 Value::Float(f) => {
2490 Ok(f)
2492 }
2493 _ => {
2494 self.problem_report(
2495 RustConstructorError::VariableNotFloat {
2496 variable_name: format!("{:?}", target),
2497 },
2498 SeverityLevel::SevereWarning,
2499 );
2500 Err(RustConstructorError::VariableNotFloat {
2501 variable_name: format!("{:?}", target),
2502 })
2503 }
2504 }
2505 }
2506
2507 pub fn var_decode_s(&mut self, target: Value) -> Result<String, RustConstructorError> {
2509 match target {
2510 Value::String(s) => {
2511 Ok(s)
2513 }
2514 _ => {
2515 self.problem_report(
2516 RustConstructorError::VariableNotString {
2517 variable_name: format!("{:?}", target),
2518 },
2519 SeverityLevel::SevereWarning,
2520 );
2521 Err(RustConstructorError::VariableNotString {
2522 variable_name: format!("{:?}", target),
2523 })
2524 }
2525 }
2526 }
2527
2528 pub fn var_decode_v(&mut self, target: Value) -> Result<Vec<Value>, RustConstructorError> {
2530 match target {
2531 Value::Vec(v) => {
2532 Ok(v)
2534 }
2535 _ => {
2536 self.problem_report(
2537 RustConstructorError::VariableNotVec {
2538 variable_name: format!("{:?}", target),
2539 },
2540 SeverityLevel::SevereWarning,
2541 );
2542 Err(RustConstructorError::VariableNotVec {
2543 variable_name: format!("{:?}", target),
2544 })
2545 }
2546 }
2547 }
2548
2549 pub fn add_scroll_background(
2551 &mut self,
2552 name: &str,
2553 image_name: Vec<String>,
2554 horizontal_or_vertical: bool,
2555 left_and_top_or_right_and_bottom: bool,
2556 scroll_speed: u32,
2557 size_position_boundary: [f32; 5],
2558 ) {
2559 let mut image_id = vec![];
2560 for i in image_name.clone() {
2561 for u in 0..self.rust_constructor_resource.len() {
2562 if let RCR::Image(im) = self.rust_constructor_resource[u].clone() {
2563 if im.name == i {
2564 image_id.push(u);
2565 };
2566 };
2567 };
2568 };
2569 for (count, _) in image_id.clone().into_iter().enumerate() {
2570 if let RCR::Image(im) = &mut self.rust_constructor_resource[image_id[count]] {
2571 im.x_grid = [0, 0];
2572 im.y_grid = [0, 0];
2573 im.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2574 im.image_size = [size_position_boundary[0], size_position_boundary[1]];
2575 let mut temp_position;
2576 if horizontal_or_vertical {
2577 temp_position = size_position_boundary[2];
2578 } else {
2579 temp_position = size_position_boundary[3];
2580 };
2581 if horizontal_or_vertical {
2582 for _ in 0..count {
2583 if left_and_top_or_right_and_bottom {
2584 temp_position += size_position_boundary[0];
2585 } else {
2586 temp_position -= size_position_boundary[0];
2587 };
2588 };
2589 im.origin_position = [temp_position, size_position_boundary[3]];
2590 } else {
2591 for _ in 0..count {
2592 if left_and_top_or_right_and_bottom {
2593 temp_position += size_position_boundary[1];
2594 } else {
2595 temp_position -= size_position_boundary[1];
2596 };
2597 };
2598 im.origin_position = [size_position_boundary[2], temp_position];
2599 };
2600 };
2601 };
2602 if let RCR::Image(im) = self.rust_constructor_resource[image_id[image_id.len() - 1]].clone()
2603 {
2604 let resume_point = if horizontal_or_vertical {
2605 im.origin_position[0]
2606 } else {
2607 im.origin_position[1]
2608 };
2609 self.rust_constructor_resource
2610 .push(RCR::ScrollBackground(ScrollBackground {
2611 discern_type: "ScrollBackground".to_string(),
2612 name: name.to_string(),
2613 image_name,
2614 horizontal_or_vertical,
2615 left_and_top_or_right_and_bottom,
2616 scroll_speed,
2617 boundary: size_position_boundary[4],
2618 resume_point,
2619 }));
2620 };
2621 }
2622
2623 pub fn scroll_background(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2625 if let Ok(id) = self.get_resource_index("ScrollBackground", name) {
2626 if let RCR::ScrollBackground(sb) = self.rust_constructor_resource[id].clone() {
2627 sb.reg_render_resource(&mut self.render_resource_list);
2628 if !self.check_resource_exists("SplitTime", name) {
2629 self.add_split_time(name, false);
2630 };
2631 for i in 0..sb.image_name.len() {
2632 self.image(ui, &sb.image_name[i].clone(), ctx);
2633 };
2634 if self.timer.now_time - self.split_time(name).unwrap()[0] >= self.vertrefresh {
2635 self.add_split_time(name, true);
2636 for i in 0..sb.image_name.len() {
2637 if let Ok(id2) = self.get_resource_index("Image", &sb.image_name[i].clone())
2638 {
2639 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone()
2640 {
2641 if sb.horizontal_or_vertical {
2642 if sb.left_and_top_or_right_and_bottom {
2643 for _ in 0..sb.scroll_speed {
2644 im.origin_position[0] -= 1_f32;
2645 if im.origin_position[0] <= sb.boundary {
2646 im.origin_position[0] = sb.resume_point;
2647 };
2648 }
2649 self.rust_constructor_resource[id2] =
2650 RCR::Image(im.clone());
2651 } else {
2652 for _ in 0..sb.scroll_speed {
2653 im.origin_position[0] += 1_f32;
2654 if im.origin_position[0] >= sb.boundary {
2655 im.origin_position[0] = sb.resume_point;
2656 };
2657 }
2658 self.rust_constructor_resource[id2] =
2659 RCR::Image(im.clone());
2660 };
2661 } else if sb.left_and_top_or_right_and_bottom {
2662 for _ in 0..sb.scroll_speed {
2663 im.origin_position[1] -= 1_f32;
2664 if im.origin_position[1] <= sb.boundary {
2665 im.origin_position[1] = sb.resume_point;
2666 };
2667 }
2668 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2669 } else {
2670 for _ in 0..sb.scroll_speed {
2671 im.origin_position[1] += 1_f32;
2672 if im.origin_position[1] >= sb.boundary {
2673 im.origin_position[1] = sb.resume_point;
2674 };
2675 }
2676 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2677 };
2678 };
2679 };
2680 };
2681 };
2682 };
2683 };
2684 }
2685
2686 pub fn add_image_texture(
2688 &mut self,
2689 name: &str,
2690 path: &str,
2691 flip: [bool; 2],
2692 create_new_resource: bool,
2693 ctx: &egui::Context,
2694 ) {
2695 if let Ok(mut file) = File::open(path) {
2696 let mut buffer = Vec::new();
2697 file.read_to_end(&mut buffer).unwrap();
2698 let img_bytes = buffer;
2699 let img = image::load_from_memory(&img_bytes).unwrap();
2700 let rgba_data = match flip {
2701 [true, true] => img.fliph().flipv().into_rgba8(),
2702 [true, false] => img.fliph().into_rgba8(),
2703 [false, true] => img.flipv().into_rgba8(),
2704 _ => img.into_rgba8(),
2705 };
2706 let (w, h) = (rgba_data.width(), rgba_data.height());
2707 let raw_data: Vec<u8> = rgba_data.into_raw();
2708
2709 let color_image =
2710 egui::ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
2711 let image_texture = Some(ctx.load_texture(name, color_image, TextureOptions::LINEAR));
2712 if create_new_resource {
2713 self.rust_constructor_resource
2714 .push(RCR::ImageTexture(ImageTexture {
2715 discern_type: "ImageTexture".to_string(),
2716 name: name.to_string(),
2717 texture: image_texture,
2718 cite_path: path.to_string(),
2719 }));
2720 } else if let Ok(id) = self.get_resource_index("ImageTexture", name) {
2721 if let RCR::ImageTexture(it) = &mut self.rust_constructor_resource[id] {
2722 if !create_new_resource {
2723 it.texture = image_texture;
2724 it.cite_path = path.to_string();
2725 };
2726 };
2727 } else {
2728 self.rust_constructor_resource
2729 .push(RCR::ImageTexture(ImageTexture {
2730 discern_type: "ImageTexture".to_string(),
2731 name: name.to_string(),
2732 texture: image_texture,
2733 cite_path: path.to_string(),
2734 }));
2735 };
2736 } else {
2737 self.problem_report(
2738 RustConstructorError::ImageGetFailed {
2739 image_path: path.to_string(),
2740 },
2741 SeverityLevel::SevereWarning,
2742 );
2743 };
2744 }
2745
2746 pub fn add_image(
2748 &mut self,
2749 name: &str,
2750 position_size: [f32; 4],
2751 grid: [u32; 4],
2752 center_display_and_use_overlay: (HorizontalAlign, VerticalAlign, bool),
2753 alpha_and_overlay_color: [u8; 5],
2754 image_texture_name: &str,
2755 ) {
2756 if let Ok(id) = self.get_resource_index("ImageTexture", image_texture_name) {
2757 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id].clone() {
2758 self.rust_constructor_resource.push(RCR::Image(Image {
2759 discern_type: "Image".to_string(),
2760 name: name.to_string(),
2761 image_texture: it.texture.clone(),
2762 image_position: [position_size[0], position_size[1]],
2763 image_size: [position_size[2], position_size[3]],
2764 x_grid: [grid[0], grid[1]],
2765 y_grid: [grid[2], grid[3]],
2766 center_display: (
2767 center_display_and_use_overlay.0,
2768 center_display_and_use_overlay.1,
2769 ),
2770 alpha: alpha_and_overlay_color[0],
2771 overlay_color: [
2772 alpha_and_overlay_color[1],
2773 alpha_and_overlay_color[2],
2774 alpha_and_overlay_color[3],
2775 alpha_and_overlay_color[4],
2776 ],
2777 use_overlay_color: center_display_and_use_overlay.2,
2778 origin_position: [position_size[0], position_size[1]],
2779 cite_texture: image_texture_name.to_string(),
2780 last_frame_cite_texture: image_texture_name.to_string(),
2781 }));
2782 };
2783 };
2784 }
2785
2786 pub fn image(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2788 if let Ok(id) = self.get_resource_index("Image", name) {
2789 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
2790 if im.cite_texture != im.last_frame_cite_texture {
2791 if let Ok(id2) = self.get_resource_index("ImageTexture", &im.cite_texture) {
2792 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id2].clone() {
2793 im.image_texture = it.texture;
2794 };
2795 };
2796 };
2797 im.reg_render_resource(&mut self.render_resource_list);
2798 im.image_position[0] = match im.x_grid[1] {
2799 0 => im.origin_position[0],
2800 _ => {
2801 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64
2802 * im.x_grid[0] as f64) as f32
2803 + im.origin_position[0]
2804 }
2805 };
2806 im.image_position[1] = match im.y_grid[1] {
2807 0 => im.origin_position[1],
2808 _ => {
2809 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64
2810 * im.y_grid[0] as f64) as f32
2811 + im.origin_position[1]
2812 }
2813 };
2814 match im.center_display.0 {
2815 HorizontalAlign::Left => {}
2816 HorizontalAlign::Center => im.image_position[0] -= im.image_size[0] / 2.0,
2817 HorizontalAlign::Right => im.image_position[0] -= im.image_size[0],
2818 };
2819 match im.center_display.1 {
2820 VerticalAlign::Top => {}
2821 VerticalAlign::Center => im.image_position[1] -= im.image_size[1] / 2.0,
2822 VerticalAlign::Bottom => im.image_position[1] -= im.image_size[1],
2823 };
2824 if let Some(texture) = &im.image_texture {
2825 let rect = Rect::from_min_size(
2826 Pos2::new(im.image_position[0], im.image_position[1]),
2827 Vec2::new(im.image_size[0], im.image_size[1]),
2828 );
2829 let color = if im.use_overlay_color {
2830 Color32::from_rgba_unmultiplied(
2832 im.overlay_color[0],
2833 im.overlay_color[1],
2834 im.overlay_color[2],
2835 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
2837 )
2838 } else {
2839 Color32::from_white_alpha(im.alpha)
2840 };
2841
2842 egui::Image::new(egui::ImageSource::Texture(texture.into()))
2844 .tint(color)
2845 .paint_at(ui, rect)
2846 };
2847 im.last_frame_cite_texture = im.cite_texture.clone();
2848 self.rust_constructor_resource[id] = RCR::Image(im);
2849 };
2850 };
2851 }
2852
2853 pub fn add_message_box(
2855 &mut self,
2856 box_itself_title_content_image_name_and_sound_path: [&str; 5],
2857 box_size: [f32; 2],
2858 box_keep_existing: bool,
2859 box_existing_time: f32,
2860 box_normal_and_restore_speed: [f32; 2],
2861 ) {
2862 if !self.check_resource_exists(
2863 "MessageBox",
2864 box_itself_title_content_image_name_and_sound_path[0],
2865 ) {
2866 if let Ok(id) = self.get_resource_index(
2867 "Image",
2868 box_itself_title_content_image_name_and_sound_path[3],
2869 ) {
2870 if let RCR::Image(im) = &mut self.rust_constructor_resource[id] {
2871 im.image_size = [box_size[1] - 15_f32, box_size[1] - 15_f32];
2872 im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
2873 im.x_grid = [1, 1];
2874 im.y_grid = [0, 1];
2875 im.name = format!("MessageBox{}", im.name);
2876 };
2877 };
2878 if let Ok(id) = self.get_resource_index(
2879 "Text",
2880 box_itself_title_content_image_name_and_sound_path[1],
2881 ) {
2882 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2883 t.x_grid = [1, 1];
2884 t.y_grid = [0, 1];
2885 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2886 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2887 t.name = format!("MessageBox{}", t.name);
2888 };
2889 };
2890 if let Ok(id) = self.get_resource_index(
2891 "Text",
2892 box_itself_title_content_image_name_and_sound_path[2],
2893 ) {
2894 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2895 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
2896 t.x_grid = [1, 1];
2897 t.y_grid = [0, 1];
2898 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2899 t.name = format!("MessageBox{}", t.name);
2900 };
2901 };
2902 self.rust_constructor_resource
2903 .push(RCR::MessageBox(MessageBox {
2904 discern_type: "MessageBox".to_string(),
2905 name: box_itself_title_content_image_name_and_sound_path[0].to_string(),
2906 box_size,
2907 box_title_name: format!(
2908 "MessageBox{}",
2909 box_itself_title_content_image_name_and_sound_path[1]
2910 ),
2911 box_content_name: format!(
2912 "MessageBox{}",
2913 box_itself_title_content_image_name_and_sound_path[2]
2914 ),
2915 box_image_name: format!(
2916 "MessageBox{}",
2917 box_itself_title_content_image_name_and_sound_path[3]
2918 ),
2919 box_keep_existing,
2920 box_existing_time,
2921 box_exist: true,
2922 box_speed: box_normal_and_restore_speed[0],
2923 box_restore_speed: box_normal_and_restore_speed[1],
2924 box_memory_offset: 0_f32,
2925 }));
2926 if !box_keep_existing {
2927 self.add_split_time(
2928 &format!(
2929 "MessageBox{}",
2930 box_itself_title_content_image_name_and_sound_path[0]
2931 ),
2932 false,
2933 );
2934 };
2935 self.add_split_time(
2936 &format!(
2937 "MessageBox{}Animation",
2938 box_itself_title_content_image_name_and_sound_path[0]
2939 ),
2940 false,
2941 );
2942 self.add_rect(
2943 &format!(
2944 "MessageBox{}",
2945 box_itself_title_content_image_name_and_sound_path[0]
2946 ),
2947 [0_f32, 0_f32, box_size[0], box_size[1], 20_f32],
2948 [1, 1, 0, 1],
2949 (HorizontalAlign::Left, VerticalAlign::Top),
2950 [100, 100, 100, 125, 240, 255, 255, 255],
2951 0.0,
2952 );
2953 self.add_image(
2954 &format!(
2955 "MessageBox{}Close",
2956 box_itself_title_content_image_name_and_sound_path[0]
2957 ),
2958 [0_f32, 0_f32, 30_f32, 30_f32],
2959 [0, 0, 0, 0],
2960 (HorizontalAlign::Center, VerticalAlign::Center, false),
2961 [255, 0, 0, 0, 0],
2962 "CloseMessageBox",
2963 );
2964 self.add_switch(
2965 [
2966 &format!(
2967 "MessageBox{}Close",
2968 box_itself_title_content_image_name_and_sound_path[0]
2969 ),
2970 &format!(
2971 "MessageBox{}Close",
2972 box_itself_title_content_image_name_and_sound_path[0]
2973 ),
2974 "",
2975 box_itself_title_content_image_name_and_sound_path[4],
2976 ],
2977 vec![
2978 SwitchData {
2979 texture: "CloseMessageBox".to_string(),
2980 color: [255, 255, 255, 0],
2981 text: String::new(),
2982 hint_text: String::new(),
2983 },
2984 SwitchData {
2985 texture: "CloseMessageBox".to_string(),
2986 color: [180, 180, 180, 200],
2987 text: String::new(),
2988 hint_text: String::new(),
2989 },
2990 SwitchData {
2991 texture: "CloseMessageBox".to_string(),
2992 color: [255, 255, 255, 200],
2993 text: String::new(),
2994 hint_text: String::new(),
2995 },
2996 SwitchData {
2997 texture: "CloseMessageBox".to_string(),
2998 color: [180, 180, 180, 200],
2999 text: String::new(),
3000 hint_text: String::new(),
3001 },
3002 ],
3003 [false, true, true],
3004 2,
3005 vec![SwitchClickAction {
3006 click_method: PointerButton::Primary,
3007 action: true,
3008 }],
3009 );
3010 } else {
3011 self.problem_report(
3012 RustConstructorError::MessageBoxAlreadyExists {
3013 message_box_name: box_itself_title_content_image_name_and_sound_path[0]
3014 .to_string(),
3015 },
3016 SeverityLevel::SevereWarning,
3017 );
3018 };
3019 }
3020
3021 pub fn message_box_display(&mut self, ctx: &egui::Context, ui: &mut Ui) {
3023 let mut offset = 0_f32;
3024 let mut delete_count = 0;
3025 let mut index_list = Vec::new();
3026 for i in 0..self.rust_constructor_resource.len() {
3027 if let RCR::MessageBox(_) = self.rust_constructor_resource[i] {
3028 index_list.push(i);
3029 };
3030 }
3031 for u in 0..index_list.len() {
3032 let mut deleted = false;
3033 let i = u - delete_count;
3034 if let RCR::MessageBox(mut mb) = self.rust_constructor_resource[index_list[i]].clone() {
3035 if let Ok(id1) = self.get_resource_index("Image", &mb.box_image_name) {
3036 if let RCR::Image(mut im1) = self.rust_constructor_resource[id1].clone() {
3037 if let Ok(id2) =
3038 self.get_resource_index("CustomRect", &format!("MessageBox{}", mb.name))
3039 {
3040 if let RCR::CustomRect(mut cr) =
3041 self.rust_constructor_resource[id2].clone()
3042 {
3043 if let Ok(id3) = self.get_resource_index("Text", &mb.box_title_name)
3044 {
3045 if let RCR::Text(mut t1) =
3046 self.rust_constructor_resource[id3].clone()
3047 {
3048 if let Ok(id4) =
3049 self.get_resource_index("Text", &mb.box_content_name)
3050 {
3051 if let RCR::Text(mut t2) =
3052 self.rust_constructor_resource[id4].clone()
3053 {
3054 if let Ok(id5) = self.get_resource_index(
3055 "Switch",
3056 &format!("MessageBox{}Close", mb.name),
3057 ) {
3058 if let RCR::Switch(mut s) =
3059 self.rust_constructor_resource[id5].clone()
3060 {
3061 if let Ok(id6) = self.get_resource_index(
3062 "Image",
3063 &format!("MessageBox{}Close", mb.name),
3064 ) {
3065 if let RCR::Image(mut im2) = self
3066 .rust_constructor_resource[id6]
3067 .clone()
3068 {
3069 if mb.box_size[1]
3070 < self.get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3071 + self.get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3072 [1]
3073 + 10_f32
3074 {
3075 mb.box_size[1] = self
3076 .get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3077 + self
3078 .get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3079 [1]
3080 + 10_f32;
3081 cr.size[1] = mb.box_size[1];
3082 im1.image_size = [
3083 mb.box_size[1] - 15_f32,
3084 mb.box_size[1] - 15_f32,
3085 ];
3086 t1.wrap_width = mb.box_size[0]
3087 - mb.box_size[1]
3088 + 5_f32;
3089 t2.wrap_width = mb.box_size[0]
3090 - mb.box_size[1]
3091 + 5_f32;
3092 };
3093 if self.timer.total_time
3094 - self
3095 .split_time(&format!(
3096 "MessageBox{}Animation",
3097 mb.name
3098 ))
3099 .unwrap()[1]
3100 >= self.vertrefresh
3101 {
3102 self.add_split_time(
3103 &format!(
3104 "MessageBox{}Animation",
3105 mb.name
3106 ),
3107 true,
3108 );
3109 if offset
3110 != mb.box_memory_offset
3111 {
3112 if mb.box_memory_offset
3113 < offset
3114 {
3115 if mb.box_memory_offset
3116 + mb.box_restore_speed
3117 >= offset
3118 {
3119 mb.box_memory_offset = offset;
3120 } else {
3121 mb.box_memory_offset +=
3122 mb.box_restore_speed;
3123 };
3124 } else if mb
3125 .box_memory_offset
3126 - mb.box_restore_speed
3127 <= offset
3128 {
3129 mb.box_memory_offset =
3130 offset;
3131 } else {
3132 mb.box_memory_offset -=
3133 mb.box_restore_speed;
3134 };
3135 };
3136 if cr.origin_position[0]
3137 != -mb.box_size[0] - 5_f32
3138 {
3139 if mb.box_exist {
3140 if cr.origin_position[0]
3141 - mb.box_speed
3142 <= -mb.box_size[0]
3143 - 5_f32
3144 {
3145 cr.origin_position[0] =
3146 -mb.box_size[0] - 5_f32;
3147 if self.check_resource_exists("SplitTime", &format!("MessageBox{}", mb.name)) {
3148 self.add_split_time(
3149 &format!("MessageBox{}", mb.name),
3150 true,
3151 );
3152 };
3153 } else {
3154 cr.origin_position[0] -=
3155 mb.box_speed;
3156 };
3157 } else if cr.origin_position
3158 [0]
3159 + mb.box_speed
3160 >= 15_f32
3161 {
3162 cr.origin_position[0] =
3163 15_f32;
3164 delete_count += 1;
3165 deleted = true;
3166 } else {
3167 cr.origin_position
3168 [0] += mb.box_speed;
3169 };
3170 };
3171 };
3172 cr.origin_position[1] =
3173 mb.box_memory_offset + 20_f32;
3174 im1.origin_position = [
3175 cr.origin_position[0] + 5_f32,
3176 cr.origin_position[1]
3177 + mb.box_size[1] / 2_f32,
3178 ];
3179 t1.origin_position = [
3180 im1.origin_position[0]
3181 + im1.image_size[0]
3182 + 5_f32,
3183 cr.origin_position[1] + 5_f32,
3184 ];
3185 t2.origin_position = [
3186 im1.origin_position[0]
3187 + im1.image_size[0]
3188 + 5_f32,
3189 t1.origin_position[1]
3190 + self
3191 .get_text_size(
3192 &mb.box_title_name
3193 .clone(),
3194 ui,
3195 )
3196 .unwrap()[1],
3197 ];
3198 im2.origin_position = cr.position;
3199 if !mb.box_keep_existing
3200 && self.timer.total_time
3201 - self
3202 .split_time(&format!(
3203 "MessageBox{}",
3204 mb.name
3205 ))
3206 .unwrap()[1]
3207 >= mb.box_existing_time
3208 && cr.origin_position[0]
3209 == -mb.box_size[0] - 5_f32
3210 {
3211 mb.box_exist = false;
3212 if cr.origin_position[0]
3213 + mb.box_speed
3214 >= 15_f32
3215 {
3216 cr.origin_position[0] =
3217 15_f32;
3218 } else {
3219 cr.origin_position[0] +=
3220 mb.box_speed;
3221 };
3222 };
3223 if let Some(mouse_pos) =
3224 ui.input(|i| {
3225 i.pointer.hover_pos()
3226 })
3227 {
3228 let rect =
3229 egui::Rect::from_min_size(
3230 Pos2 {
3231 x: im2
3232 .image_position
3233 [0],
3234 y: im2
3235 .image_position
3236 [1],
3237 },
3238 Vec2 {
3239 x: cr.size[0]
3240 + 25_f32,
3241 y: cr.size[1]
3242 + 25_f32,
3243 },
3244 );
3245 if rect.contains(mouse_pos) {
3246 s.appearance[0].color[3] =
3247 200;
3248 } else {
3249 s.appearance[0].color[3] =
3250 0;
3251 };
3252 };
3253 self.rust_constructor_resource
3254 [index_list[i]] =
3255 RCR::MessageBox(mb.clone());
3256 self.rust_constructor_resource
3257 [id1] = RCR::Image(im1.clone());
3258 self.rust_constructor_resource
3259 [id2] =
3260 RCR::CustomRect(cr.clone());
3261 self.rust_constructor_resource
3262 [id3] = RCR::Text(t1.clone());
3263 self.rust_constructor_resource
3264 [id4] = RCR::Text(t2.clone());
3265 self.rust_constructor_resource
3266 [id5] = RCR::Switch(s.clone());
3267 self.rust_constructor_resource
3268 [id6] = RCR::Image(im2.clone());
3269 self.rect(
3270 ui,
3271 &format!(
3272 "MessageBox{}",
3273 mb.name
3274 ),
3275 ctx,
3276 );
3277 self.image(
3278 ui,
3279 &mb.box_image_name.clone(),
3280 ctx,
3281 );
3282 self.text(
3283 ui,
3284 &t1.name.clone(),
3285 ctx,
3286 );
3287 self.text(
3288 ui,
3289 &t2.name.clone(),
3290 ctx,
3291 );
3292 if self
3293 .switch(
3294 &format!(
3295 "MessageBox{}Close",
3296 mb.name
3297 ),
3298 ui,
3299 ctx,
3300 s.state == 0
3301 && mb.box_exist,
3302 true,
3303 )
3304 .unwrap()[0]
3305 == 0
3306 {
3307 mb.box_exist = false;
3308 if cr.origin_position[0]
3309 + mb.box_speed
3310 >= 15_f32
3311 {
3312 cr.origin_position[0] =
3313 15_f32;
3314 } else {
3315 cr.origin_position[0] +=
3316 mb.box_speed;
3317 };
3318 self.rust_constructor_resource[id2] = RCR::CustomRect(cr.clone());
3319 self.rust_constructor_resource[index_list[i]] = RCR::MessageBox(mb.clone());
3320 };
3321 if deleted {
3322 if let Ok(id) = self
3323 .get_resource_index(
3324 "Image",
3325 &mb.box_image_name,
3326 )
3327 {
3328 self.rust_constructor_resource.remove(id);
3329 };
3330 if let Ok(id) = self
3331 .get_resource_index(
3332 "CustomRect",
3333 &format!(
3334 "MessageBox{}",
3335 mb.name
3336 ),
3337 )
3338 {
3339 self.rust_constructor_resource.remove(id);
3340 };
3341 if let Ok(id) = self
3342 .get_resource_index(
3343 "Text",
3344 &mb.box_title_name,
3345 )
3346 {
3347 self.rust_constructor_resource.remove(id);
3348 };
3349 if let Ok(id) = self
3350 .get_resource_index(
3351 "Text",
3352 &mb.box_content_name,
3353 )
3354 {
3355 self.rust_constructor_resource.remove(id);
3356 };
3357 if let Ok(id) = self
3358 .get_resource_index(
3359 "Switch",
3360 &format!(
3361 "MessageBox{}Close",
3362 mb.name
3363 ),
3364 )
3365 {
3366 self.rust_constructor_resource.remove(id);
3367 };
3368 if let Ok(id) = self
3369 .get_resource_index(
3370 "Image",
3371 &format!(
3372 "MessageBox{}Close",
3373 mb.name
3374 ),
3375 )
3376 {
3377 self.rust_constructor_resource.remove(id);
3378 };
3379 if let Ok(id) = self.get_resource_index("SplitTime", &format!("MessageBox{}Animation", mb.name)) {
3380 self.rust_constructor_resource.remove(id);
3381 };
3382 if !mb.box_keep_existing {
3383 if let Ok(id) = self
3384 .get_resource_index(
3385 "SplitTime",
3386 &format!(
3387 "MessageBox{}",
3388 mb.name
3389 ),
3390 )
3391 {
3392 self.rust_constructor_resource.remove(id);
3393 };
3394 };
3395 if let Ok(id) = self
3396 .get_resource_index(
3397 "MessageBox",
3398 &mb.name,
3399 )
3400 {
3401 self.rust_constructor_resource.remove(id);
3402 };
3403 } else {
3404 offset +=
3405 mb.box_size[1] + 15_f32;
3406 };
3407 };
3408 };
3409 };
3410 };
3411 };
3412 };
3413 };
3414 };
3415 };
3416 };
3417 };
3418 };
3419 };
3420 }
3421 }
3422
3423 pub fn add_switch(
3425 &mut self,
3426 name_switch_image_name_text_name_and_sound_path: [&str; 4],
3427 mut appearance: Vec<SwitchData>,
3428 enable_hover_click_image_and_use_overlay: [bool; 3],
3429 switch_amounts_state: u32,
3430 click_method: Vec<SwitchClickAction>,
3431 ) {
3432 let mut count = 1;
3433 if enable_hover_click_image_and_use_overlay[0] {
3434 count += 1;
3435 };
3436 if enable_hover_click_image_and_use_overlay[1] {
3437 count += 1;
3438 };
3439 if appearance.len() as u32 != count * switch_amounts_state {
3440 self.problem_report(
3441 RustConstructorError::SwitchAppearanceMismatch {
3442 switch_name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3443 differ: (count as i32 * switch_amounts_state as i32 - appearance.len() as i32)
3444 .unsigned_abs(),
3445 },
3446 SeverityLevel::SevereWarning,
3447 );
3448 for _ in
3449 0..(count as i32 * switch_amounts_state as i32 - appearance.len() as i32) as usize
3450 {
3451 appearance.push(SwitchData {
3452 texture: "Error".to_string(),
3453 color: [255, 255, 255, 255],
3454 text: String::new(),
3455 hint_text: String::new(),
3456 });
3457 }
3458 };
3459 let mut text_origin_position = [0_f32, 0_f32];
3460 if let Ok(id) =
3461 self.get_resource_index("Image", name_switch_image_name_text_name_and_sound_path[1])
3462 {
3463 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
3464 im.use_overlay_color = true;
3465 if self.check_resource_exists(
3466 "Text",
3467 name_switch_image_name_text_name_and_sound_path[2],
3468 ) {
3469 if let Ok(id2) = self.get_resource_index(
3470 "Text",
3471 name_switch_image_name_text_name_and_sound_path[2],
3472 ) {
3473 if let RCR::Text(t) = &mut self.rust_constructor_resource[id2] {
3474 t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
3475 t.x_grid = [0, 0];
3476 t.y_grid = [0, 0];
3477 text_origin_position = t.origin_position;
3478 };
3479 };
3480 };
3481 self.rust_constructor_resource[id] = RCR::Image(im);
3482 };
3483 };
3484 if !appearance.iter().any(|x| x.hint_text.is_empty()) {
3485 self.add_text(
3486 [
3487 &format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0]),
3488 "",
3489 "Content",
3490 ],
3491 [0_f32, 0_f32, 25_f32, 300_f32, 10_f32],
3492 [255, 255, 255, 0, 0, 0, 0, 0],
3493 (HorizontalAlign::Left, VerticalAlign::Top, true, false),
3494 [0, 0, 0, 0],
3495 vec![],
3496 );
3497 self.add_split_time(
3498 &format!(
3499 "{}StartHoverTime",
3500 name_switch_image_name_text_name_and_sound_path[0]
3501 ),
3502 false,
3503 );
3504 self.add_split_time(
3505 &format!(
3506 "{}HintFadeAnimation",
3507 name_switch_image_name_text_name_and_sound_path[0]
3508 ),
3509 false,
3510 );
3511 };
3512 self.rust_constructor_resource.push(RCR::Switch(Switch {
3513 discern_type: "Switch".to_string(),
3514 name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3515 appearance: appearance.clone(),
3516 switch_image_name: name_switch_image_name_text_name_and_sound_path[1].to_string(),
3517 enable_hover_click_image: [
3518 enable_hover_click_image_and_use_overlay[0],
3519 enable_hover_click_image_and_use_overlay[1],
3520 ],
3521 state: 0,
3522 click_method,
3523 last_time_hovered: false,
3524 last_time_clicked: false,
3525 last_time_clicked_index: 0,
3526 animation_count: count,
3527 hint_text_name: if !appearance.iter().any(|x| x.hint_text.is_empty()) {
3528 format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0])
3529 } else {
3530 "".to_string()
3531 },
3532 text_name: name_switch_image_name_text_name_and_sound_path[2].to_string(),
3533 text_origin_position,
3534 sound_path: name_switch_image_name_text_name_and_sound_path[3].to_string(),
3535 }));
3536 }
3537
3538 pub fn switch(
3540 &mut self,
3541 name: &str,
3542 ui: &mut Ui,
3543 ctx: &egui::Context,
3544 enable: bool,
3545 play_sound: bool,
3546 ) -> Result<[usize; 2], RustConstructorError> {
3547 let mut activated = [5, 0];
3548 let mut appearance_count = 0;
3549 if let Ok(id) = self.get_resource_index("Switch", name) {
3550 if let RCR::Switch(mut s) = self.rust_constructor_resource[id].clone() {
3551 if let Ok(id2) = self.get_resource_index("Image", &s.switch_image_name.clone()) {
3552 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone() {
3553 s.reg_render_resource(&mut self.render_resource_list);
3554 let rect = Rect::from_min_size(
3555 Pos2::new(im.image_position[0], im.image_position[1]),
3556 Vec2::new(im.image_size[0], im.image_size[1]),
3557 );
3558 let mut hovered = false;
3559 if enable {
3560 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
3561 if rect.contains(mouse_pos) {
3563 if !s.hint_text_name.is_empty() {
3564 if let Ok(id3) =
3565 self.get_resource_index("Text", &s.hint_text_name)
3566 {
3567 if let RCR::Text(mut t) =
3568 self.rust_constructor_resource[id3].clone()
3569 {
3570 if !s.last_time_hovered {
3571 self.add_split_time(
3572 &format!("{}StartHoverTime", s.name),
3573 true,
3574 );
3575 } else if self.timer.total_time
3576 - self
3577 .split_time(&format!(
3578 "{}StartHoverTime",
3579 s.name
3580 ))
3581 .unwrap()[1]
3582 >= 2_f32
3583 || t.rgba[3] != 0
3584 {
3585 t.rgba[3] = 255;
3586 t.origin_position = [mouse_pos.x, mouse_pos.y];
3587 };
3588 t.center_display.0 = if mouse_pos.x
3589 + self
3590 .get_text_size(&s.hint_text_name, ui)
3591 .unwrap()[0]
3592 <= ctx.available_rect().width()
3593 {
3594 HorizontalAlign::Left
3595 } else {
3596 HorizontalAlign::Right
3597 };
3598 t.center_display.1 = if mouse_pos.y
3599 + self
3600 .get_text_size(&s.hint_text_name, ui)
3601 .unwrap()[1]
3602 <= ctx.available_rect().height()
3603 {
3604 VerticalAlign::Top
3605 } else {
3606 VerticalAlign::Bottom
3607 };
3608 self.rust_constructor_resource[id3] = RCR::Text(t);
3609 };
3610 };
3611 };
3612 hovered = true;
3613 let mut clicked = vec![];
3614 let mut active = false;
3615 for u in 0..s.click_method.len() as u32 {
3616 clicked.push(ui.input(|i| {
3617 i.pointer.button_down(
3618 s.click_method[u as usize].click_method,
3619 )
3620 }));
3621 if clicked[u as usize] {
3622 active = true;
3623 s.last_time_clicked_index = u as usize;
3624 break;
3625 };
3626 }
3627 if active {
3628 s.last_time_clicked = true;
3629 if s.enable_hover_click_image[1] {
3630 if s.enable_hover_click_image[0] {
3631 appearance_count = 2;
3632 } else {
3633 appearance_count = 1;
3634 };
3635 } else if !s.enable_hover_click_image[0] {
3636 appearance_count = 0;
3637 };
3638 } else {
3639 if s.last_time_clicked {
3640 if play_sound {
3641 general_click_feedback(&s.sound_path);
3642 };
3643 let mut count = 1;
3644 if s.enable_hover_click_image[0] {
3645 count += 1;
3646 };
3647 if s.enable_hover_click_image[1] {
3648 count += 1;
3649 };
3650 if s.click_method[s.last_time_clicked_index].action {
3651 if s.state < (s.appearance.len() / count - 1) as u32
3652 {
3653 s.state += 1;
3654 } else {
3655 s.state = 0;
3656 };
3657 };
3658 activated[0] = s.last_time_clicked_index;
3659 s.last_time_clicked = false;
3660 };
3661 if s.enable_hover_click_image[0] {
3662 appearance_count = 1;
3663 } else {
3664 appearance_count = 0;
3665 };
3666 };
3667 } else {
3668 s.last_time_clicked = false;
3669 appearance_count = 0;
3670 };
3671 } else {
3672 s.last_time_clicked = false;
3673 appearance_count = 0;
3674 };
3675 } else {
3676 s.last_time_clicked = false;
3677 appearance_count = 0;
3678 };
3679 if !hovered && !s.hint_text_name.is_empty() {
3680 if s.last_time_hovered {
3681 self.add_split_time(&format!("{}HintFadeAnimation", s.name), true);
3682 };
3683 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3684 if let RCR::Text(mut t) =
3685 self.rust_constructor_resource[id3].clone()
3686 {
3687 if self.timer.total_time
3688 - self
3689 .split_time(&format!("{}HintFadeAnimation", s.name))
3690 .unwrap()[1]
3691 >= self.vertrefresh
3692 {
3693 t.rgba[3] = t.rgba[3].saturating_sub(1);
3694 };
3695 self.rust_constructor_resource[id3] = RCR::Text(t);
3696 };
3697 };
3698 };
3699 im.overlay_color = s.appearance
3700 [(s.state * s.animation_count + appearance_count) as usize]
3701 .color;
3702 if let Ok(id4) = self.get_resource_index(
3703 "ImageTexture",
3704 &s.appearance
3705 [(s.state * s.animation_count + appearance_count) as usize]
3706 .texture
3707 .clone(),
3708 ) {
3709 if let RCR::ImageTexture(it) =
3710 self.rust_constructor_resource[id4].clone()
3711 {
3712 im.image_texture = it.texture.clone();
3713 };
3714 };
3715 if !s.hint_text_name.is_empty() {
3716 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3717 if let RCR::Text(mut t) =
3718 self.rust_constructor_resource[id3].clone()
3719 {
3720 t.background_rgb[3] = t.rgba[3];
3721 t.text_content = s.appearance
3722 [(s.state * s.animation_count + appearance_count) as usize]
3723 .hint_text
3724 .clone();
3725 self.rust_constructor_resource[id3] = RCR::Text(t);
3726 };
3727 };
3728 };
3729 s.last_time_hovered = hovered;
3730 activated[1] = s.state as usize;
3731 self.rust_constructor_resource[id] = RCR::Switch(s.clone());
3732 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
3733 self.image(ui, &s.switch_image_name.clone(), ctx);
3734 if self.check_resource_exists("Text", &s.text_name) {
3735 if let Ok(id4) = self.get_resource_index("Text", &s.text_name) {
3736 if let RCR::Text(mut t2) =
3737 self.rust_constructor_resource[id4].clone()
3738 {
3739 t2.origin_position = [
3740 im.image_position[0] + s.text_origin_position[0],
3741 im.image_position[1] + s.text_origin_position[1],
3742 ];
3743 t2.text_content = s.appearance
3744 [(s.state * s.animation_count + appearance_count) as usize]
3745 .text
3746 .clone();
3747 self.rust_constructor_resource[id4] = RCR::Text(t2);
3748 };
3749 };
3750 self.text(ui, &s.text_name, ctx);
3751 };
3752 if self.check_resource_exists("Text", &s.hint_text_name) {
3753 self.text(ui, &s.hint_text_name, ctx);
3754 };
3755 Ok(activated)
3756 } else {
3757 Err(RustConstructorError::ImageNotFound {
3759 image_name: s.switch_image_name,
3760 })
3761 }
3762 } else {
3763 self.problem_report(
3764 RustConstructorError::ImageNotFound {
3765 image_name: name.to_string(),
3766 },
3767 SeverityLevel::SevereWarning,
3768 );
3769 Err(RustConstructorError::ImageNotFound {
3770 image_name: s.switch_image_name,
3771 })
3772 }
3773 } else {
3774 Err(RustConstructorError::SwitchNotFound {
3776 switch_name: name.to_string(),
3777 })
3778 }
3779 } else {
3780 self.problem_report(
3781 RustConstructorError::SwitchNotFound {
3782 switch_name: name.to_string(),
3783 },
3784 SeverityLevel::SevereWarning,
3785 );
3786 Err(RustConstructorError::SwitchNotFound {
3787 switch_name: name.to_string(),
3788 })
3789 }
3790 }
3791}