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