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 self.rust_constructor_resource[id] = RCR::PageData(pd.clone());
1316 };
1317 return Ok(pd.change_page_updated);
1318 };
1319 };
1320 self.problem_report(
1321 RustConstructorError::PageNotFound {
1322 page_name: name.to_string(),
1323 },
1324 SeverityLevel::SevereWarning,
1325 );
1326 Err(RustConstructorError::PageNotFound {
1327 page_name: name.to_string(),
1328 })
1329 }
1330
1331 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
1333 if let Ok(id) = self.get_resource_index("PageData", name) {
1334 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1335 let return_value = pd.enter_page_updated;
1336 pd.enter_page_updated = true;
1337 return Ok(return_value);
1338 };
1339 };
1340 self.problem_report(
1341 RustConstructorError::PageNotFound {
1342 page_name: name.to_string(),
1343 },
1344 SeverityLevel::SevereWarning,
1345 );
1346 Err(RustConstructorError::PageNotFound {
1347 page_name: name.to_string(),
1348 })
1349 }
1350
1351 pub fn new_page_update(&mut self, name: &str) {
1353 if let Ok(id) = self.get_resource_index("PageData", name) {
1354 self.timer.start_time = self.timer.total_time;
1355 self.update_timer();
1356 if let RCR::PageData(pd) = &mut self.rust_constructor_resource[id] {
1357 pd.change_page_updated = true;
1358 };
1359 };
1360 }
1361
1362 pub fn update_frame_stats(&mut self, ctx: &egui::Context) {
1364 let current_time = ctx.input(|i| i.time);
1365 if let Some(last) = self.last_frame_time {
1366 let delta = (current_time - last) as f32;
1367 self.frame_times.push(delta);
1368 const MAX_SAMPLES: usize = 120;
1369 if self.frame_times.len() > MAX_SAMPLES {
1370 let remove_count = self.frame_times.len() - MAX_SAMPLES;
1371 self.frame_times.drain(0..remove_count);
1372 }
1373 }
1374 self.last_frame_time = Some(current_time);
1375 }
1376
1377 pub fn current_fps(&self) -> f32 {
1379 if self.frame_times.is_empty() {
1380 0.0
1381 } else {
1382 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
1383 }
1384 }
1385
1386 pub fn add_split_time(&mut self, name: &str, reset: bool) {
1388 if reset {
1389 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1390 if let RCR::SplitTime(st) = &mut self.rust_constructor_resource[id] {
1391 st.time = [self.timer.now_time, self.timer.total_time];
1392 };
1393 };
1394 } else {
1395 self.rust_constructor_resource
1396 .push(RCR::SplitTime(SplitTime {
1397 discern_type: "SplitTime".to_string(),
1398 name: name.to_string(),
1399 time: [self.timer.now_time, self.timer.total_time],
1400 }));
1401 };
1402 }
1403
1404 pub fn split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
1406 if let Ok(id) = self.get_resource_index("SplitTime", name) {
1407 if let RCR::SplitTime(st) = self.rust_constructor_resource[id].clone() {
1408 return Ok(st.time);
1409 };
1410 };
1411 self.problem_report(
1412 RustConstructorError::SplitTimeNotFound {
1413 split_time_name: name.to_string(),
1414 },
1415 SeverityLevel::SevereWarning,
1416 );
1417 Err(RustConstructorError::SplitTimeNotFound {
1418 split_time_name: name.to_string(),
1419 })
1420 }
1421
1422 pub fn update_timer(&mut self) {
1424 let elapsed = self.timer.timer.elapsed();
1425 let seconds = elapsed.as_secs();
1426 let milliseconds = elapsed.subsec_millis();
1427 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
1428 self.timer.now_time = self.timer.total_time - self.timer.start_time
1429 }
1430
1431 pub fn add_rect(
1433 &mut self,
1434 name: &str,
1435 position_size_and_rounding: [f32; 5],
1436 grid: [u32; 4],
1437 center_display: [bool; 4],
1438 color: [u8; 8],
1439 border_width: f32,
1440 ) {
1441 self.rust_constructor_resource
1442 .push(RCR::CustomRect(CustomRect {
1443 discern_type: "CustomRect".to_string(),
1444 name: name.to_string(),
1445 position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1446 size: [position_size_and_rounding[2], position_size_and_rounding[3]],
1447 rounding: position_size_and_rounding[4],
1448 x_grid: [grid[0], grid[1]],
1449 y_grid: [grid[2], grid[3]],
1450 center_display,
1451 color: [color[0], color[1], color[2], color[3]],
1452 border_width,
1453 border_color: [color[4], color[5], color[6], color[7]],
1454 origin_position: [position_size_and_rounding[0], position_size_and_rounding[1]],
1455 }));
1456 }
1457
1458 pub fn rect(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1460 if let Ok(id) = self.get_resource_index("CustomRect", name) {
1461 if let RCR::CustomRect(cr) = &mut self.rust_constructor_resource[id] {
1462 cr.reg_render_resource(&mut self.render_resource_list);
1463 cr.position[0] = match cr.x_grid[1] {
1464 0 => cr.origin_position[0],
1465 _ => {
1466 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64
1467 * cr.x_grid[0] as f64) as f32
1468 + cr.origin_position[0]
1469 }
1470 };
1471 cr.position[1] = match cr.y_grid[1] {
1472 0 => cr.origin_position[1],
1473 _ => {
1474 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64
1475 * cr.y_grid[0] as f64) as f32
1476 + cr.origin_position[1]
1477 }
1478 };
1479 let pos_x;
1480 let pos_y;
1481 if cr.center_display[2] {
1482 pos_x = cr.position[0] - cr.size[0] / 2.0;
1483 } else if cr.center_display[0] {
1484 pos_x = cr.position[0];
1485 } else {
1486 pos_x = cr.position[0] - cr.size[0];
1487 };
1488 if cr.center_display[3] {
1489 pos_y = cr.position[1] - cr.size[1] / 2.0;
1490 } else if cr.center_display[1] {
1491 pos_y = cr.position[1];
1492 } else {
1493 pos_y = cr.position[1] - cr.size[1];
1494 };
1495 ui.painter().rect(
1496 Rect::from_min_max(
1497 Pos2::new(pos_x, pos_y),
1498 Pos2::new(pos_x + cr.size[0], pos_y + cr.size[1]),
1499 ),
1500 cr.rounding,
1501 Color32::from_rgba_unmultiplied(
1502 cr.color[0],
1503 cr.color[1],
1504 cr.color[2],
1505 cr.color[3],
1506 ),
1507 Stroke {
1508 width: cr.border_width,
1509 color: Color32::from_rgba_unmultiplied(
1510 cr.border_color[0],
1511 cr.border_color[1],
1512 cr.border_color[2],
1513 cr.border_color[3],
1514 ),
1515 },
1516 egui::StrokeKind::Inside,
1517 );
1518 };
1519 };
1520 }
1521
1522 pub fn add_text(
1524 &mut self,
1525 name_content_and_font: [&str; 3],
1526 position_font_size_wrap_width_rounding: [f32; 5],
1527 color: [u8; 8],
1528 center_display_write_background_and_enable_copy: [bool; 6],
1529 grid: [u32; 4],
1530 hyperlink_text: Vec<(usize, usize, &str)>,
1531 ) {
1532 self.rust_constructor_resource.push(RCR::Text(Text {
1533 discern_type: "Text".to_string(),
1534 name: name_content_and_font[0].to_string(),
1535 text_content: name_content_and_font[1].to_string(),
1536 font_size: position_font_size_wrap_width_rounding[2],
1537 rgba: [color[0], color[1], color[2], color[3]],
1538 position: [
1539 position_font_size_wrap_width_rounding[0],
1540 position_font_size_wrap_width_rounding[1],
1541 ],
1542 center_display: [
1543 center_display_write_background_and_enable_copy[0],
1544 center_display_write_background_and_enable_copy[1],
1545 center_display_write_background_and_enable_copy[2],
1546 center_display_write_background_and_enable_copy[3],
1547 ],
1548 wrap_width: position_font_size_wrap_width_rounding[3],
1549 write_background: center_display_write_background_and_enable_copy[4],
1550 background_rgb: [color[4], color[5], color[6], color[7]],
1551 rounding: position_font_size_wrap_width_rounding[4],
1552 x_grid: [grid[0], grid[1]],
1553 y_grid: [grid[2], grid[3]],
1554 origin_position: [
1555 position_font_size_wrap_width_rounding[0],
1556 position_font_size_wrap_width_rounding[1],
1557 ],
1558 font: name_content_and_font[2].to_string(),
1559 selection: None,
1560 selectable: center_display_write_background_and_enable_copy[5],
1561 hyperlink_text: hyperlink_text
1562 .into_iter()
1563 .map(|(a, b, c)| {
1564 (
1565 a,
1566 if b > name_content_and_font[1].len() - 1 {
1567 name_content_and_font[1].len() - 1
1568 } else {
1569 b
1570 },
1571 c.to_string(),
1572 )
1573 })
1574 .collect(),
1575 }));
1576 }
1577
1578 pub fn text(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
1580 if let Ok(id) = self.get_resource_index("Text", name) {
1581 if let RCR::Text(mut t) = self.rust_constructor_resource[id].clone() {
1582 t.reg_render_resource(&mut self.render_resource_list);
1583 let galley = ui.fonts(|f| {
1585 f.layout(
1586 t.text_content.to_string(),
1587 if self.check_resource_exists("Font", &t.font.clone()) {
1588 FontId::new(t.font_size, egui::FontFamily::Name(t.font.clone().into()))
1589 } else {
1590 FontId::proportional(t.font_size)
1591 },
1592 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
1593 t.wrap_width,
1594 )
1595 });
1596 let text_size = galley.size();
1597 t.position[0] = match t.x_grid[1] {
1598 0 => t.origin_position[0],
1599 _ => {
1600 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64
1601 * t.x_grid[0] as f64) as f32
1602 + t.origin_position[0]
1603 }
1604 };
1605 t.position[1] = match t.y_grid[1] {
1606 0 => t.origin_position[1],
1607 _ => {
1608 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64
1609 * t.y_grid[0] as f64) as f32
1610 + t.origin_position[1]
1611 }
1612 };
1613 let pos_x;
1614 let pos_y;
1615 if t.center_display[2] {
1616 pos_x = t.position[0] - text_size.x / 2.0;
1617 } else if t.center_display[0] {
1618 pos_x = t.position[0];
1619 } else {
1620 pos_x = t.position[0] - text_size.x;
1621 };
1622 if t.center_display[3] {
1623 pos_y = t.position[1] - text_size.y / 2.0;
1624 } else if t.center_display[1] {
1625 pos_y = t.position[1];
1626 } else {
1627 pos_y = t.position[1] - text_size.y;
1628 };
1629 let position = Pos2::new(pos_x, pos_y);
1631
1632 if t.write_background {
1633 let rect = Rect::from_min_size(position, text_size);
1634 ui.painter().rect_filled(
1636 rect,
1637 t.rounding,
1638 Color32::from_rgba_unmultiplied(
1639 t.background_rgb[0],
1640 t.background_rgb[1],
1641 t.background_rgb[2],
1642 t.background_rgb[3],
1643 ),
1644 ); };
1646 ui.painter().galley(
1648 position,
1649 galley.clone(),
1650 Color32::from_rgba_unmultiplied(
1651 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3], ),
1653 );
1654
1655 if t.selectable {
1656 let rect = Rect::from_min_size(
1657 [position[0] - 20_f32, position[1] - 5_f32].into(),
1658 [text_size[0] + 40_f32, text_size[1] + 10_f32].into(),
1659 );
1660
1661 let rect2 = Rect::from_min_size(
1662 [0_f32, 0_f32].into(),
1663 [ctx.available_rect().width(), ctx.available_rect().height()].into(),
1664 );
1665
1666 let response = ui.interact(
1668 rect,
1669 egui::Id::new(format!("text_{}_click_and_drag", t.name)),
1670 egui::Sense::click_and_drag(),
1671 );
1672
1673 let response2 = ui.interact(
1674 rect2,
1675 egui::Id::new(format!("text_{}_total", t.name)),
1676 egui::Sense::click(),
1677 );
1678
1679 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
1681 let relative_pos = pointer_pos - position.to_vec2();
1682 let cursor = galley.cursor_from_pos(relative_pos);
1683 cursor.index
1684 };
1685
1686 if !response.clicked() && response2.clicked() {
1687 t.selection = None;
1688 };
1689
1690 if response.clicked() || response.drag_started() {
1691 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1692 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1693 t.selection = Some((cursor, cursor));
1694 };
1695 response.request_focus();
1696 };
1697
1698 if response.dragged() && t.selection.is_some() {
1699 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1700 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
1701 if let Some((start, _)) = t.selection {
1702 t.selection = Some((start, cursor));
1703 };
1704 };
1705 };
1706
1707 if response.has_focus() {
1709 let copy_triggered = ui.input(|input| {
1711 let c_released = input.key_released(egui::Key::C);
1712 let cmd_pressed = input.modifiers.command || input.modifiers.mac_cmd;
1713 let ctrl_pressed = input.modifiers.ctrl;
1714 c_released && (cmd_pressed || ctrl_pressed)
1715 });
1716 if copy_triggered {
1717 if let Some((start, end)) = t.selection {
1718 let (start, end) = (start.min(end), start.max(end));
1719 let chars: Vec<char> = t.text_content.chars().collect();
1720 if start <= chars.len() && end <= chars.len() && start < end {
1721 let selected_text: String = chars[start..end].iter().collect();
1722 ui.ctx().copy_text(selected_text);
1723 };
1724 };
1725 };
1726 };
1727
1728 if let Some((start, end)) = t.selection {
1730 let (start, end) = (start.min(end), start.max(end));
1731 if start != end {
1732 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
1734 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
1735
1736 let start_pos = start_cursor.left_top();
1737 let end_pos = end_cursor.right_top();
1738 if start_pos.y == end_pos.y {
1740 let rows = &galley.rows;
1743 let row_height = if !rows.is_empty() {
1744 if let Some(row) = rows.first() {
1746 row.height()
1747 } else {
1748 text_size.y / t.text_content.lines().count() as f32
1749 }
1750 } else {
1751 text_size.y / t.text_content.lines().count() as f32
1752 };
1753
1754 let selection_rect = Rect::from_min_max(
1755 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1756 Pos2::new(
1757 position.x + end_pos.x,
1758 position.y + start_pos.y + row_height,
1759 ),
1760 );
1761 ui.painter().rect_filled(
1762 selection_rect,
1763 0.0,
1764 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1765 );
1766 } else {
1767 let rows = &galley.rows;
1769 let row_height = if !rows.is_empty() {
1770 rows[0].height()
1771 } else {
1772 text_size.y / t.text_content.lines().count() as f32
1773 };
1774
1775 let selection_top = position.y + start_pos.y.min(end_pos.y);
1777 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
1778
1779 let start_row_index = (start_pos.y / row_height).floor() as usize;
1781 let end_row_index = (end_pos.y / row_height).floor() as usize;
1782 let (first_row_index, last_row_index) =
1783 if start_row_index <= end_row_index {
1784 (start_row_index, end_row_index)
1785 } else {
1786 (end_row_index, start_row_index)
1787 };
1788
1789 for (i, row) in rows.iter().enumerate() {
1790 let row_y = position.y + row_height * i as f32;
1791 let row_bottom = row_y + row_height;
1792 if row_bottom > selection_top && row_y <= selection_bottom {
1794 let left = if i == first_row_index {
1795 position.x + start_pos.x
1797 } else {
1798 position.x + row.rect().min.x
1800 };
1801
1802 let right = if i == last_row_index {
1803 position.x + end_pos.x
1805 } else {
1806 position.x + row.rect().max.x
1808 };
1809
1810 let selection_rect = Rect::from_min_max(
1811 Pos2::new(left, row_y),
1812 Pos2::new(right, row_bottom),
1813 );
1814
1815 if selection_rect.width() > 0.0
1817 && selection_rect.height() > 0.0
1818 {
1819 ui.painter().rect_filled(
1820 selection_rect,
1821 0.0,
1822 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1823 );
1824 };
1825 };
1826 }
1827 };
1828 };
1829 };
1830 };
1831
1832 for (start, end, url) in &t.hyperlink_text {
1834 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
1836 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
1837
1838 let start_pos = start_cursor.left_top();
1839 let end_pos = end_cursor.right_top();
1840
1841 let mut is_hovering_link = false;
1843 if let Some(pointer_pos) = ui.input(|i| i.pointer.hover_pos()) {
1844 let relative_pos = pointer_pos - position.to_vec2();
1845 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1846 if cursor.index >= *start && cursor.index <= *end {
1847 is_hovering_link = true;
1848 };
1849 };
1850
1851 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1852
1853 let link_responses = if start_cursor.min.y == end_cursor.min.y {
1855 let link_rect = Rect::from_min_max(
1857 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1858 Pos2::new(
1859 position.x + end_pos.x,
1860 position.y + start_pos.y + row_height,
1861 ),
1862 );
1863 vec![ui.interact(
1864 link_rect,
1865 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
1866 egui::Sense::click(),
1867 )]
1868 } else {
1869 let start_row = (start_pos.y / row_height).round() as usize;
1871 let end_row = (end_pos.y / row_height).round() as usize;
1872 let mut responses = Vec::new();
1873
1874 for row in start_row..=end_row {
1875 if let Some(current_row) = galley.rows.get(row) {
1876 let row_rect = current_row.rect();
1877 let row_y = position.y + row as f32 * row_height;
1878
1879 let link_rect = if row == start_row {
1880 Rect::from_min_max(
1882 Pos2::new(position.x + start_pos.x, row_y),
1883 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1884 )
1885 } else if row == end_row {
1886 Rect::from_min_max(
1888 Pos2::new(position.x + row_rect.min.x, row_y),
1889 Pos2::new(position.x + end_pos.x, row_y + row_height),
1890 )
1891 } else {
1892 Rect::from_min_max(
1894 Pos2::new(position.x + row_rect.min.x, row_y),
1895 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
1896 )
1897 };
1898
1899 responses.push(ui.interact(
1900 link_rect,
1901 egui::Id::new(format!(
1902 "link_{}_{}_{}_row_{}",
1903 t.name, start, end, row
1904 )),
1905 egui::Sense::click(),
1906 ));
1907 };
1908 }
1909 responses
1910 };
1911
1912 let mut is_pressing_link = false;
1914 for link_response in &link_responses {
1915 if link_response.is_pointer_button_down_on()
1916 && !link_response.drag_started()
1917 {
1918 t.selection = None;
1919 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1920 let relative_pos = pointer_pos - position.to_vec2();
1921 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1922 if cursor.index >= *start && cursor.index <= *end {
1923 is_pressing_link = true;
1924 break;
1925 };
1926 };
1927 };
1928 }
1929
1930 let mut clicked_on_link = false;
1932 for link_response in &link_responses {
1933 if link_response.clicked() {
1934 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
1935 let relative_pos = pointer_pos - position.to_vec2();
1936 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
1937 if cursor.index >= *start && cursor.index <= *end {
1938 clicked_on_link = true;
1939 break;
1940 };
1941 };
1942 };
1943 }
1944
1945 if clicked_on_link {
1946 if !url.is_empty() {
1948 ui.ctx().open_url(egui::OpenUrl::new_tab(url));
1949 };
1950 };
1951
1952 if is_pressing_link {
1954 if start_cursor.min.y == end_cursor.min.y {
1955 let selection_rect = Rect::from_min_max(
1957 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
1958 Pos2::new(
1959 position.x + end_pos.x,
1960 position.y
1961 + start_pos.y
1962 + galley.rows.first().map_or(14.0, |row| row.height()),
1963 ),
1964 );
1965 ui.painter().rect_filled(
1966 selection_rect,
1967 0.0,
1968 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1969 );
1970 } else {
1971 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
1973 let start_row = (start_pos.y / row_height).round() as usize;
1974 let end_row = (end_pos.y / row_height).round() as usize;
1975
1976 for row in start_row..=end_row {
1977 if let Some(current_row) = galley.rows.get(row) {
1978 let row_rect = current_row.rect();
1979
1980 if row == start_row {
1981 let selection_rect = Rect::from_min_max(
1983 Pos2::new(
1984 position.x + start_pos.x,
1985 position.y + row as f32 * row_height,
1986 ),
1987 Pos2::new(
1988 position.x + row_rect.max.x,
1989 position.y + row as f32 * row_height + row_height,
1990 ),
1991 );
1992 ui.painter().rect_filled(
1993 selection_rect,
1994 0.0,
1995 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
1996 );
1997 } else if row == end_row {
1998 let selection_rect = Rect::from_min_max(
2000 Pos2::new(
2001 position.x + row_rect.min.x,
2002 position.y + row as f32 * row_height,
2003 ),
2004 Pos2::new(
2005 position.x + end_pos.x,
2006 position.y + row as f32 * row_height + row_height,
2007 ),
2008 );
2009 ui.painter().rect_filled(
2010 selection_rect,
2011 0.0,
2012 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2013 );
2014 } else {
2015 let selection_rect = Rect::from_min_max(
2017 Pos2::new(
2018 position.x + row_rect.min.x,
2019 position.y + row as f32 * row_height,
2020 ),
2021 Pos2::new(
2022 position.x + row_rect.max.x,
2023 position.y + row as f32 * row_height + row_height,
2024 ),
2025 );
2026 ui.painter().rect_filled(
2027 selection_rect,
2028 0.0,
2029 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2030 );
2031 };
2032 };
2033 }
2034 };
2035 };
2036
2037 if start_cursor.min.y == end_cursor.min.y {
2040 let underline_y = position.y
2042 + start_pos.y
2043 + galley.rows.first().map_or(14.0, |row| row.height())
2044 - 2.0;
2045
2046 let color = if is_hovering_link {
2048 Color32::from_rgba_unmultiplied(
2049 t.rgba[0].saturating_add(50),
2050 t.rgba[1],
2051 t.rgba[2],
2052 t.rgba[3],
2053 )
2054 } else {
2055 Color32::from_rgba_unmultiplied(
2056 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2057 )
2058 };
2059
2060 ui.painter().line_segment(
2061 [
2062 Pos2::new(position.x + start_pos.x, underline_y),
2063 Pos2::new(position.x + end_pos.x, underline_y),
2064 ],
2065 Stroke::new(t.font_size / 10_f32, color),
2066 );
2067 } else {
2068 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2073 let end_row = (end_pos.y / row_height).round() as usize;
2074
2075 for row in start_row..=end_row {
2076 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
2080 let row_rect = current_row.rect();
2081
2082 let color = Color32::from_rgba_unmultiplied(
2083 t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3],
2084 );
2085
2086 if row == start_row {
2087 ui.painter().line_segment(
2089 [
2090 Pos2::new(position.x + start_pos.x, row_y),
2091 Pos2::new(position.x + row_rect.max.x, row_y),
2092 ],
2093 Stroke::new(t.font_size / 10_f32, color),
2094 );
2095 } else if row == end_row {
2096 ui.painter().line_segment(
2098 [
2099 Pos2::new(position.x + row_rect.min.x, row_y),
2100 Pos2::new(position.x + end_pos.x, row_y),
2101 ],
2102 Stroke::new(t.font_size / 10_f32, color),
2103 );
2104 } else {
2105 ui.painter().line_segment(
2107 [
2108 Pos2::new(position.x + row_rect.min.x, row_y),
2109 Pos2::new(position.x + row_rect.max.x, row_y),
2110 ],
2111 Stroke::new(t.font_size / 10_f32, color),
2112 );
2113 };
2114 };
2115 }
2116 };
2117 }
2118 self.rust_constructor_resource[id] = RCR::Text(t);
2119 };
2120 };
2121 }
2122
2123 pub fn get_text_size(
2125 &mut self,
2126 resource_name: &str,
2127 ui: &mut Ui,
2128 ) -> Result<[f32; 2], RustConstructorError> {
2129 if let Ok(id) = self.get_resource_index("Text", resource_name) {
2130 if let RCR::Text(t) = self.rust_constructor_resource[id].clone() {
2131 let galley = ui.fonts(|f| {
2132 f.layout(
2133 t.text_content.to_string(),
2134 FontId::proportional(t.font_size),
2135 Color32::from_rgba_unmultiplied(t.rgba[0], t.rgba[1], t.rgba[2], t.rgba[3]),
2136 t.wrap_width,
2137 )
2138 });
2139 return Ok([galley.size().x, galley.size().y]);
2140 };
2141 };
2142 self.problem_report(
2143 RustConstructorError::TextNotFound {
2144 text_name: resource_name.to_string(),
2145 },
2146 SeverityLevel::SevereWarning,
2147 );
2148 Err(RustConstructorError::TextNotFound {
2149 text_name: resource_name.to_string(),
2150 })
2151 }
2152
2153 pub fn add_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2155 self.rust_constructor_resource.push(RCR::Variable(Variable {
2156 discern_type: "Variable".to_string(),
2157 name: name.to_string(),
2158 value: value.into(),
2159 }));
2160 }
2161
2162 pub fn modify_var<T: Into<Value>>(&mut self, name: &str, value: T) {
2164 if let Ok(id) = self.get_resource_index("Variable", name) {
2165 if let RCR::Variable(v) = &mut self.rust_constructor_resource[id] {
2166 v.value = value.into();
2167 };
2168 };
2169 }
2170
2171 pub fn var(&mut self, name: &str) -> Result<Value, RustConstructorError> {
2173 if let Ok(id) = self.get_resource_index("Variable", name) {
2174 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2175 return Ok(v.clone().value);
2176 };
2177 };
2178 self.problem_report(
2179 RustConstructorError::VariableNotFound {
2180 variable_name: name.to_string(),
2181 },
2182 SeverityLevel::SevereWarning,
2183 );
2184 Err(RustConstructorError::VariableNotFound {
2185 variable_name: name.to_string(),
2186 })
2187 }
2188
2189 pub fn var_i(&mut self, name: &str) -> Result<i32, RustConstructorError> {
2191 if let Ok(id) = self.get_resource_index("Variable", name) {
2192 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2193 match &v.value {
2194 Value::Int(i) => Ok(*i),
2196 _ => {
2197 self.problem_report(
2198 RustConstructorError::VariableNotInt {
2199 variable_name: name.to_string(),
2200 },
2201 SeverityLevel::SevereWarning,
2202 );
2203 Err(RustConstructorError::VariableNotInt {
2204 variable_name: name.to_string(),
2205 })
2206 }
2207 }
2208 } else {
2209 Err(RustConstructorError::VariableNotFound {
2211 variable_name: name.to_string(),
2212 })
2213 }
2214 } else {
2215 self.problem_report(
2216 RustConstructorError::VariableNotFound {
2217 variable_name: name.to_string(),
2218 },
2219 SeverityLevel::SevereWarning,
2220 );
2221 Err(RustConstructorError::VariableNotFound {
2222 variable_name: name.to_string(),
2223 })
2224 }
2225 }
2226
2227 pub fn var_u(&mut self, name: &str) -> Result<u32, RustConstructorError> {
2229 if let Ok(id) = self.get_resource_index("Variable", name) {
2230 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2231 match &v.value {
2232 Value::UInt(u) => Ok(*u),
2234 _ => {
2235 self.problem_report(
2236 RustConstructorError::VariableNotUInt {
2237 variable_name: name.to_string(),
2238 },
2239 SeverityLevel::SevereWarning,
2240 );
2241 Err(RustConstructorError::VariableNotUInt {
2242 variable_name: name.to_string(),
2243 })
2244 }
2245 }
2246 } else {
2247 Err(RustConstructorError::VariableNotFound {
2249 variable_name: name.to_string(),
2250 })
2251 }
2252 } else {
2253 self.problem_report(
2254 RustConstructorError::VariableNotFound {
2255 variable_name: name.to_string(),
2256 },
2257 SeverityLevel::SevereWarning,
2258 );
2259 Err(RustConstructorError::VariableNotFound {
2260 variable_name: name.to_string(),
2261 })
2262 }
2263 }
2264
2265 pub fn var_f(&mut self, name: &str) -> Result<f32, RustConstructorError> {
2267 if let Ok(id) = self.get_resource_index("Variable", name) {
2268 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2269 match &v.value {
2270 Value::Float(f) => Ok(*f),
2272 _ => {
2273 self.problem_report(
2274 RustConstructorError::VariableNotFloat {
2275 variable_name: name.to_string(),
2276 },
2277 SeverityLevel::SevereWarning,
2278 );
2279 Err(RustConstructorError::VariableNotFloat {
2280 variable_name: name.to_string(),
2281 })
2282 }
2283 }
2284 } else {
2285 Err(RustConstructorError::VariableNotFound {
2287 variable_name: name.to_string(),
2288 })
2289 }
2290 } else {
2291 self.problem_report(
2292 RustConstructorError::VariableNotFound {
2293 variable_name: name.to_string(),
2294 },
2295 SeverityLevel::SevereWarning,
2296 );
2297 Err(RustConstructorError::VariableNotFound {
2298 variable_name: name.to_string(),
2299 })
2300 }
2301 }
2302
2303 pub fn var_b(&mut self, name: &str) -> Result<bool, RustConstructorError> {
2305 if let Ok(id) = self.get_resource_index("Variable", name) {
2306 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2307 match &v.value {
2308 Value::Bool(b) => Ok(*b),
2310 _ => {
2311 self.problem_report(
2312 RustConstructorError::VariableNotBool {
2313 variable_name: name.to_string(),
2314 },
2315 SeverityLevel::SevereWarning,
2316 );
2317 Err(RustConstructorError::VariableNotBool {
2318 variable_name: name.to_string(),
2319 })
2320 }
2321 }
2322 } else {
2323 Err(RustConstructorError::VariableNotFound {
2325 variable_name: name.to_string(),
2326 })
2327 }
2328 } else {
2329 self.problem_report(
2330 RustConstructorError::VariableNotFound {
2331 variable_name: name.to_string(),
2332 },
2333 SeverityLevel::SevereWarning,
2334 );
2335 Err(RustConstructorError::VariableNotFound {
2336 variable_name: name.to_string(),
2337 })
2338 }
2339 }
2340
2341 pub fn var_v(&mut self, name: &str) -> Result<Vec<Value>, RustConstructorError> {
2343 if let Ok(id) = self.get_resource_index("Variable", name) {
2344 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2345 match &v.value {
2346 Value::Vec(v) => Ok(v.clone()),
2348 _ => {
2349 self.problem_report(
2350 RustConstructorError::VariableNotVec {
2351 variable_name: name.to_string(),
2352 },
2353 SeverityLevel::SevereWarning,
2354 );
2355 Err(RustConstructorError::VariableNotVec {
2356 variable_name: name.to_string(),
2357 })
2358 }
2359 }
2360 } else {
2361 Err(RustConstructorError::VariableNotFound {
2363 variable_name: name.to_string(),
2364 })
2365 }
2366 } else {
2367 self.problem_report(
2368 RustConstructorError::VariableNotFound {
2369 variable_name: name.to_string(),
2370 },
2371 SeverityLevel::SevereWarning,
2372 );
2373 Err(RustConstructorError::VariableNotFound {
2374 variable_name: name.to_string(),
2375 })
2376 }
2377 }
2378
2379 pub fn var_s(&mut self, name: &str) -> Result<String, RustConstructorError> {
2381 if let Ok(id) = self.get_resource_index("Variable", name) {
2382 if let RCR::Variable(v) = self.rust_constructor_resource[id].clone() {
2383 match &v.value {
2384 Value::String(s) => Ok(s.clone()),
2386 _ => {
2387 self.problem_report(
2388 RustConstructorError::VariableNotString {
2389 variable_name: name.to_string(),
2390 },
2391 SeverityLevel::SevereWarning,
2392 );
2393 Err(RustConstructorError::VariableNotString {
2394 variable_name: name.to_string(),
2395 })
2396 }
2397 }
2398 } else {
2399 Err(RustConstructorError::VariableNotFound {
2401 variable_name: name.to_string(),
2402 })
2403 }
2404 } else {
2405 self.problem_report(
2406 RustConstructorError::VariableNotFound {
2407 variable_name: name.to_string(),
2408 },
2409 SeverityLevel::SevereWarning,
2410 );
2411 Err(RustConstructorError::VariableNotFound {
2412 variable_name: name.to_string(),
2413 })
2414 }
2415 }
2416
2417 pub fn var_decode_b(&mut self, target: Value) -> Result<bool, RustConstructorError> {
2419 match target {
2420 Value::Bool(b) => {
2421 Ok(b)
2423 }
2424 _ => {
2425 self.problem_report(
2426 RustConstructorError::VariableNotBool {
2427 variable_name: format!("{:?}", target),
2428 },
2429 SeverityLevel::SevereWarning,
2430 );
2431 Err(RustConstructorError::VariableNotBool {
2432 variable_name: format!("{:?}", target),
2433 })
2434 }
2435 }
2436 }
2437
2438 pub fn var_decode_i(&mut self, target: Value) -> Result<i32, RustConstructorError> {
2440 match target {
2441 Value::Int(i) => {
2442 Ok(i)
2444 }
2445 _ => {
2446 self.problem_report(
2447 RustConstructorError::VariableNotInt {
2448 variable_name: format!("{:?}", target),
2449 },
2450 SeverityLevel::SevereWarning,
2451 );
2452 Err(RustConstructorError::VariableNotInt {
2453 variable_name: format!("{:?}", target),
2454 })
2455 }
2456 }
2457 }
2458
2459 pub fn var_decode_u(&mut self, target: Value) -> Result<u32, RustConstructorError> {
2461 match target {
2462 Value::UInt(u) => {
2463 Ok(u)
2465 }
2466 _ => {
2467 self.problem_report(
2468 RustConstructorError::VariableNotUInt {
2469 variable_name: format!("{:?}", target),
2470 },
2471 SeverityLevel::SevereWarning,
2472 );
2473 Err(RustConstructorError::VariableNotUInt {
2474 variable_name: format!("{:?}", target),
2475 })
2476 }
2477 }
2478 }
2479
2480 pub fn var_decode_f(&mut self, target: Value) -> Result<f32, RustConstructorError> {
2482 match target {
2483 Value::Float(f) => {
2484 Ok(f)
2486 }
2487 _ => {
2488 self.problem_report(
2489 RustConstructorError::VariableNotFloat {
2490 variable_name: format!("{:?}", target),
2491 },
2492 SeverityLevel::SevereWarning,
2493 );
2494 Err(RustConstructorError::VariableNotFloat {
2495 variable_name: format!("{:?}", target),
2496 })
2497 }
2498 }
2499 }
2500
2501 pub fn var_decode_s(&mut self, target: Value) -> Result<String, RustConstructorError> {
2503 match target {
2504 Value::String(s) => {
2505 Ok(s)
2507 }
2508 _ => {
2509 self.problem_report(
2510 RustConstructorError::VariableNotString {
2511 variable_name: format!("{:?}", target),
2512 },
2513 SeverityLevel::SevereWarning,
2514 );
2515 Err(RustConstructorError::VariableNotString {
2516 variable_name: format!("{:?}", target),
2517 })
2518 }
2519 }
2520 }
2521
2522 pub fn add_scroll_background(
2524 &mut self,
2525 name: &str,
2526 image_name: Vec<String>,
2527 horizontal_or_vertical: bool,
2528 left_and_top_or_right_and_bottom: bool,
2529 scroll_speed: u32,
2530 size_position_boundary: [f32; 5],
2531 ) {
2532 let mut image_id = vec![];
2533 for i in image_name.clone() {
2534 for u in 0..self.rust_constructor_resource.len() {
2535 if let RCR::Image(im) = self.rust_constructor_resource[u].clone() {
2536 if im.name == i {
2537 image_id.push(u);
2538 };
2539 };
2540 }
2541 }
2542 for (count, _) in image_id.clone().into_iter().enumerate() {
2543 if let RCR::Image(im) = &mut self.rust_constructor_resource[image_id[count]] {
2544 im.x_grid = [0, 0];
2545 im.y_grid = [0, 0];
2546 im.center_display = [true, true, false, false];
2547 im.image_size = [size_position_boundary[0], size_position_boundary[1]];
2548 let mut temp_position;
2549 if horizontal_or_vertical {
2550 temp_position = size_position_boundary[2];
2551 } else {
2552 temp_position = size_position_boundary[3];
2553 };
2554 if horizontal_or_vertical {
2555 for _ in 0..count {
2556 if left_and_top_or_right_and_bottom {
2557 temp_position += size_position_boundary[0];
2558 } else {
2559 temp_position -= size_position_boundary[0];
2560 };
2561 }
2562 im.origin_position = [temp_position, size_position_boundary[3]];
2563 } else {
2564 for _ in 0..count {
2565 if left_and_top_or_right_and_bottom {
2566 temp_position += size_position_boundary[1];
2567 } else {
2568 temp_position -= size_position_boundary[1];
2569 };
2570 }
2571 im.origin_position = [size_position_boundary[2], temp_position];
2572 };
2573 };
2574 }
2575 if let RCR::Image(im) = self.rust_constructor_resource[image_id[image_id.len() - 1]].clone()
2576 {
2577 let resume_point = if horizontal_or_vertical {
2578 im.origin_position[0]
2579 } else {
2580 im.origin_position[1]
2581 };
2582 self.rust_constructor_resource
2583 .push(RCR::ScrollBackground(ScrollBackground {
2584 discern_type: "ScrollBackground".to_string(),
2585 name: name.to_string(),
2586 image_name,
2587 horizontal_or_vertical,
2588 left_and_top_or_right_and_bottom,
2589 scroll_speed,
2590 boundary: size_position_boundary[4],
2591 resume_point,
2592 }));
2593 };
2594 }
2595
2596 pub fn scroll_background(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2598 if let Ok(id) = self.get_resource_index("ScrollBackground", name) {
2599 if let RCR::ScrollBackground(sb) = self.rust_constructor_resource[id].clone() {
2600 sb.reg_render_resource(&mut self.render_resource_list);
2601 if self.get_resource_index("SplitTime", name).is_err() {
2602 self.add_split_time(name, false);
2603 };
2604 for i in 0..sb.image_name.len() {
2605 self.image(ui, &sb.image_name[i].clone(), ctx);
2606 }
2607 if self.timer.now_time - self.split_time(name).unwrap()[0] >= self.vertrefresh {
2608 self.add_split_time(name, true);
2609 for i in 0..sb.image_name.len() {
2610 if let Ok(id2) = self.get_resource_index("Image", &sb.image_name[i].clone())
2611 {
2612 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone()
2613 {
2614 if sb.horizontal_or_vertical {
2615 if sb.left_and_top_or_right_and_bottom {
2616 for _ in 0..sb.scroll_speed {
2617 im.origin_position[0] -= 1_f32;
2618 if im.origin_position[0] <= sb.boundary {
2619 im.origin_position[0] = sb.resume_point;
2620 };
2621 }
2622 self.rust_constructor_resource[id2] =
2623 RCR::Image(im.clone());
2624 } else {
2625 for _ in 0..sb.scroll_speed {
2626 im.origin_position[0] += 1_f32;
2627 if im.origin_position[0] >= sb.boundary {
2628 im.origin_position[0] = sb.resume_point;
2629 };
2630 }
2631 self.rust_constructor_resource[id2] =
2632 RCR::Image(im.clone());
2633 };
2634 } else if sb.left_and_top_or_right_and_bottom {
2635 for _ in 0..sb.scroll_speed {
2636 im.origin_position[1] -= 1_f32;
2637 if im.origin_position[1] <= sb.boundary {
2638 im.origin_position[1] = sb.resume_point;
2639 };
2640 }
2641 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2642 } else {
2643 for _ in 0..sb.scroll_speed {
2644 im.origin_position[1] += 1_f32;
2645 if im.origin_position[1] >= sb.boundary {
2646 im.origin_position[1] = sb.resume_point;
2647 };
2648 }
2649 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
2650 };
2651 };
2652 };
2653 }
2654 };
2655 };
2656 };
2657 }
2658
2659 pub fn add_image_texture(
2661 &mut self,
2662 name: &str,
2663 path: &str,
2664 flip: [bool; 2],
2665 create_new_resource: bool,
2666 ctx: &egui::Context,
2667 ) {
2668 if let Ok(mut file) = File::open(path) {
2669 let mut buffer = Vec::new();
2670 file.read_to_end(&mut buffer).unwrap();
2671 let img_bytes = buffer;
2672 let img = image::load_from_memory(&img_bytes).unwrap();
2673 let rgba_data = match flip {
2674 [true, true] => img.fliph().flipv().into_rgba8(),
2675 [true, false] => img.fliph().into_rgba8(),
2676 [false, true] => img.flipv().into_rgba8(),
2677 _ => img.into_rgba8(),
2678 };
2679 let (w, h) = (rgba_data.width(), rgba_data.height());
2680 let raw_data: Vec<u8> = rgba_data.into_raw();
2681
2682 let color_image =
2683 egui::ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
2684 let image_texture = Some(ctx.load_texture(name, color_image, TextureOptions::LINEAR));
2685 if create_new_resource {
2686 self.rust_constructor_resource
2687 .push(RCR::ImageTexture(ImageTexture {
2688 discern_type: "ImageTexture".to_string(),
2689 name: name.to_string(),
2690 texture: image_texture,
2691 cite_path: path.to_string(),
2692 }));
2693 } else if let Ok(id) = self.get_resource_index("ImageTexture", name) {
2694 if let RCR::ImageTexture(it) = &mut self.rust_constructor_resource[id] {
2695 if !create_new_resource {
2696 it.texture = image_texture;
2697 it.cite_path = path.to_string();
2698 };
2699 };
2700 } else {
2701 self.rust_constructor_resource
2702 .push(RCR::ImageTexture(ImageTexture {
2703 discern_type: "ImageTexture".to_string(),
2704 name: name.to_string(),
2705 texture: image_texture,
2706 cite_path: path.to_string(),
2707 }));
2708 };
2709 } else {
2710 self.problem_report(
2711 RustConstructorError::ImageGetFailed {
2712 image_path: path.to_string(),
2713 },
2714 SeverityLevel::SevereWarning,
2715 );
2716 };
2717 }
2718
2719 pub fn add_image(
2721 &mut self,
2722 name: &str,
2723 position_size: [f32; 4],
2724 grid: [u32; 4],
2725 center_display_and_use_overlay: [bool; 5],
2726 alpha_and_overlay_color: [u8; 5],
2727 image_texture_name: &str,
2728 ) {
2729 if let Ok(id) = self.get_resource_index("ImageTexture", image_texture_name) {
2730 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id].clone() {
2731 self.rust_constructor_resource.push(RCR::Image(Image {
2732 discern_type: "Image".to_string(),
2733 name: name.to_string(),
2734 image_texture: it.texture.clone(),
2735 image_position: [position_size[0], position_size[1]],
2736 image_size: [position_size[2], position_size[3]],
2737 x_grid: [grid[0], grid[1]],
2738 y_grid: [grid[2], grid[3]],
2739 center_display: [
2740 center_display_and_use_overlay[0],
2741 center_display_and_use_overlay[1],
2742 center_display_and_use_overlay[2],
2743 center_display_and_use_overlay[3],
2744 ],
2745 alpha: alpha_and_overlay_color[0],
2746 overlay_color: [
2747 alpha_and_overlay_color[1],
2748 alpha_and_overlay_color[2],
2749 alpha_and_overlay_color[3],
2750 alpha_and_overlay_color[4],
2751 ],
2752 use_overlay_color: center_display_and_use_overlay[4],
2753 origin_position: [position_size[0], position_size[1]],
2754 cite_texture: image_texture_name.to_string(),
2755 last_frame_cite_texture: image_texture_name.to_string(),
2756 }));
2757 };
2758 };
2759 }
2760
2761 pub fn image(&mut self, ui: &mut Ui, name: &str, ctx: &egui::Context) {
2763 if let Ok(id) = self.get_resource_index("Image", name) {
2764 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
2765 if im.cite_texture != im.last_frame_cite_texture {
2766 if let Ok(id2) = self.get_resource_index("ImageTexture", &im.cite_texture) {
2767 if let RCR::ImageTexture(it) = self.rust_constructor_resource[id2].clone() {
2768 im.image_texture = it.texture;
2769 };
2770 };
2771 };
2772 im.reg_render_resource(&mut self.render_resource_list);
2773 im.image_position[0] = match im.x_grid[1] {
2774 0 => im.origin_position[0],
2775 _ => {
2776 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64
2777 * im.x_grid[0] as f64) as f32
2778 + im.origin_position[0]
2779 }
2780 };
2781 im.image_position[1] = match im.y_grid[1] {
2782 0 => im.origin_position[1],
2783 _ => {
2784 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64
2785 * im.y_grid[0] as f64) as f32
2786 + im.origin_position[1]
2787 }
2788 };
2789 if im.center_display[2] {
2790 im.image_position[0] -= im.image_size[0] / 2.0;
2791 } else if !im.center_display[0] {
2792 im.image_position[0] -= im.image_size[0];
2793 };
2794 if im.center_display[3] {
2795 im.image_position[1] -= im.image_size[1] / 2.0;
2796 } else if !im.center_display[1] {
2797 im.image_position[1] -= im.image_size[1];
2798 };
2799 if let Some(texture) = &im.image_texture {
2800 let rect = Rect::from_min_size(
2801 Pos2::new(im.image_position[0], im.image_position[1]),
2802 Vec2::new(im.image_size[0], im.image_size[1]),
2803 );
2804 let color = if im.use_overlay_color {
2805 Color32::from_rgba_unmultiplied(
2807 im.overlay_color[0],
2808 im.overlay_color[1],
2809 im.overlay_color[2],
2810 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
2812 )
2813 } else {
2814 Color32::from_white_alpha(im.alpha)
2815 };
2816
2817 egui::Image::new(egui::ImageSource::Texture(texture.into()))
2819 .tint(color)
2820 .paint_at(ui, rect)
2821 };
2822 im.last_frame_cite_texture = im.cite_texture.clone();
2823 self.rust_constructor_resource[id] = RCR::Image(im);
2824 };
2825 };
2826 }
2827
2828 pub fn add_message_box(
2830 &mut self,
2831 box_itself_title_content_image_name_and_sound_path: [&str; 5],
2832 box_size: [f32; 2],
2833 box_keep_existing: bool,
2834 box_existing_time: f32,
2835 box_normal_and_restore_speed: [f32; 2],
2836 ) {
2837 if !self.check_resource_exists(
2838 "MessageBox",
2839 box_itself_title_content_image_name_and_sound_path[0],
2840 ) {
2841 if let Ok(id) = self.get_resource_index(
2842 "Image",
2843 box_itself_title_content_image_name_and_sound_path[3],
2844 ) {
2845 if let RCR::Image(im) = &mut self.rust_constructor_resource[id] {
2846 im.image_size = [box_size[1] - 15_f32, box_size[1] - 15_f32];
2847 im.center_display = [true, false, false, true];
2848 im.x_grid = [1, 1];
2849 im.y_grid = [0, 1];
2850 im.name = format!("MessageBox{}", im.name);
2851 };
2852 };
2853 if let Ok(id) = self.get_resource_index(
2854 "Text",
2855 box_itself_title_content_image_name_and_sound_path[1],
2856 ) {
2857 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2858 t.x_grid = [1, 1];
2859 t.y_grid = [0, 1];
2860 t.center_display = [true, true, false, false];
2861 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2862 t.name = format!("MessageBox{}", t.name);
2863 };
2864 };
2865 if let Ok(id) = self.get_resource_index(
2866 "Text",
2867 box_itself_title_content_image_name_and_sound_path[2],
2868 ) {
2869 if let RCR::Text(t) = &mut self.rust_constructor_resource[id] {
2870 t.center_display = [true, true, false, false];
2871 t.x_grid = [1, 1];
2872 t.y_grid = [0, 1];
2873 t.wrap_width = box_size[0] - box_size[1] + 5_f32;
2874 t.name = format!("MessageBox{}", t.name);
2875 };
2876 };
2877 self.rust_constructor_resource
2878 .push(RCR::MessageBox(MessageBox {
2879 discern_type: "MessageBox".to_string(),
2880 name: box_itself_title_content_image_name_and_sound_path[0].to_string(),
2881 box_size,
2882 box_title_name: format!(
2883 "MessageBox{}",
2884 box_itself_title_content_image_name_and_sound_path[1]
2885 ),
2886 box_content_name: format!(
2887 "MessageBox{}",
2888 box_itself_title_content_image_name_and_sound_path[2]
2889 ),
2890 box_image_name: format!(
2891 "MessageBox{}",
2892 box_itself_title_content_image_name_and_sound_path[3]
2893 ),
2894 box_keep_existing,
2895 box_existing_time,
2896 box_exist: true,
2897 box_speed: box_normal_and_restore_speed[0],
2898 box_restore_speed: box_normal_and_restore_speed[1],
2899 box_memory_offset: 0_f32,
2900 }));
2901 if !box_keep_existing {
2902 self.add_split_time(
2903 &format!(
2904 "MessageBox{}",
2905 box_itself_title_content_image_name_and_sound_path[0]
2906 ),
2907 false,
2908 );
2909 };
2910 self.add_split_time(
2911 &format!(
2912 "MessageBox{}Animation",
2913 box_itself_title_content_image_name_and_sound_path[0]
2914 ),
2915 false,
2916 );
2917 self.add_rect(
2918 &format!(
2919 "MessageBox{}",
2920 box_itself_title_content_image_name_and_sound_path[0]
2921 ),
2922 [0_f32, 0_f32, box_size[0], box_size[1], 20_f32],
2923 [1, 1, 0, 1],
2924 [true, true, false, false],
2925 [100, 100, 100, 125, 240, 255, 255, 255],
2926 0.0,
2927 );
2928 self.add_image(
2929 &format!(
2930 "MessageBox{}Close",
2931 box_itself_title_content_image_name_and_sound_path[0]
2932 ),
2933 [0_f32, 0_f32, 30_f32, 30_f32],
2934 [0, 0, 0, 0],
2935 [false, false, true, true, false],
2936 [255, 0, 0, 0, 0],
2937 "CloseMessageBox",
2938 );
2939 self.add_switch(
2940 [
2941 &format!(
2942 "MessageBox{}Close",
2943 box_itself_title_content_image_name_and_sound_path[0]
2944 ),
2945 &format!(
2946 "MessageBox{}Close",
2947 box_itself_title_content_image_name_and_sound_path[0]
2948 ),
2949 "",
2950 box_itself_title_content_image_name_and_sound_path[4],
2951 ],
2952 vec![
2953 SwitchData {
2954 texture: "CloseMessageBox".to_string(),
2955 color: [255, 255, 255, 0],
2956 text: String::new(),
2957 hint_text: String::new(),
2958 },
2959 SwitchData {
2960 texture: "CloseMessageBox".to_string(),
2961 color: [180, 180, 180, 200],
2962 text: String::new(),
2963 hint_text: String::new(),
2964 },
2965 SwitchData {
2966 texture: "CloseMessageBox".to_string(),
2967 color: [255, 255, 255, 200],
2968 text: String::new(),
2969 hint_text: String::new(),
2970 },
2971 SwitchData {
2972 texture: "CloseMessageBox".to_string(),
2973 color: [180, 180, 180, 200],
2974 text: String::new(),
2975 hint_text: String::new(),
2976 },
2977 ],
2978 [false, true, true],
2979 2,
2980 vec![SwitchClickAction {
2981 click_method: PointerButton::Primary,
2982 action: true,
2983 }],
2984 );
2985 } else {
2986 self.problem_report(
2987 RustConstructorError::MessageBoxAlreadyExists {
2988 message_box_name: box_itself_title_content_image_name_and_sound_path[0]
2989 .to_string(),
2990 },
2991 SeverityLevel::SevereWarning,
2992 );
2993 };
2994 }
2995
2996 pub fn message_box_display(&mut self, ctx: &egui::Context, ui: &mut Ui) {
2998 let mut offset = 0_f32;
2999 let mut delete_count = 0;
3000 let mut index_list = Vec::new();
3001 for i in 0..self.rust_constructor_resource.len() {
3002 if let RCR::MessageBox(_) = self.rust_constructor_resource[i] {
3003 index_list.push(i);
3004 };
3005 }
3006 for u in 0..index_list.len() {
3007 let mut deleted = false;
3008 let i = u - delete_count;
3009 if let RCR::MessageBox(mut mb) = self.rust_constructor_resource[index_list[i]].clone() {
3010 if let Ok(id1) = self.get_resource_index("Image", &mb.box_image_name) {
3011 if let RCR::Image(mut im1) = self.rust_constructor_resource[id1].clone() {
3012 if let Ok(id2) =
3013 self.get_resource_index("CustomRect", &format!("MessageBox{}", mb.name))
3014 {
3015 if let RCR::CustomRect(mut cr) =
3016 self.rust_constructor_resource[id2].clone()
3017 {
3018 if let Ok(id3) = self.get_resource_index("Text", &mb.box_title_name)
3019 {
3020 if let RCR::Text(mut t1) =
3021 self.rust_constructor_resource[id3].clone()
3022 {
3023 if let Ok(id4) =
3024 self.get_resource_index("Text", &mb.box_content_name)
3025 {
3026 if let RCR::Text(mut t2) =
3027 self.rust_constructor_resource[id4].clone()
3028 {
3029 if let Ok(id5) = self.get_resource_index(
3030 "Switch",
3031 &format!("MessageBox{}Close", mb.name),
3032 ) {
3033 if let RCR::Switch(mut s) =
3034 self.rust_constructor_resource[id5].clone()
3035 {
3036 if let Ok(id6) = self.get_resource_index(
3037 "Image",
3038 &format!("MessageBox{}Close", mb.name),
3039 ) {
3040 if let RCR::Image(mut im2) = self
3041 .rust_constructor_resource[id6]
3042 .clone()
3043 {
3044 if mb.box_size[1]
3045 < self.get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3046 + self.get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3047 [1]
3048 + 10_f32
3049 {
3050 mb.box_size[1] = self
3051 .get_text_size(&mb.box_title_name.clone(), ui).unwrap()[1]
3052 + self
3053 .get_text_size(&mb.box_content_name.clone(), ui).unwrap()
3054 [1]
3055 + 10_f32;
3056 cr.size[1] = mb.box_size[1];
3057 im1.image_size = [
3058 mb.box_size[1] - 15_f32,
3059 mb.box_size[1] - 15_f32,
3060 ];
3061 t1.wrap_width = mb.box_size[0]
3062 - mb.box_size[1]
3063 + 5_f32;
3064 t2.wrap_width = mb.box_size[0]
3065 - mb.box_size[1]
3066 + 5_f32;
3067 };
3068 if self.timer.total_time
3069 - self
3070 .split_time(&format!(
3071 "MessageBox{}Animation",
3072 mb.name
3073 ))
3074 .unwrap()[1]
3075 >= self.vertrefresh
3076 {
3077 self.add_split_time(
3078 &format!(
3079 "MessageBox{}Animation",
3080 mb.name
3081 ),
3082 true,
3083 );
3084 if offset
3085 != mb.box_memory_offset
3086 {
3087 if mb.box_memory_offset
3088 < offset
3089 {
3090 if mb.box_memory_offset
3091 + mb.box_restore_speed
3092 >= offset
3093 {
3094 mb.box_memory_offset = offset;
3095 } else {
3096 mb.box_memory_offset +=
3097 mb.box_restore_speed;
3098 };
3099 } else if mb
3100 .box_memory_offset
3101 - mb.box_restore_speed
3102 <= offset
3103 {
3104 mb.box_memory_offset =
3105 offset;
3106 } else {
3107 mb.box_memory_offset -=
3108 mb.box_restore_speed;
3109 };
3110 };
3111 if cr.origin_position[0]
3112 != -mb.box_size[0] - 5_f32
3113 {
3114 if mb.box_exist {
3115 if cr.origin_position[0]
3116 - mb.box_speed
3117 <= -mb.box_size[0]
3118 - 5_f32
3119 {
3120 cr.origin_position[0] =
3121 -mb.box_size[0] - 5_f32;
3122 if self.check_resource_exists("SplitTime", &format!("MessageBox{}", mb.name)) {
3123 self.add_split_time(
3124 &format!("MessageBox{}", mb.name),
3125 true,
3126 );
3127 };
3128 } else {
3129 cr.origin_position[0] -=
3130 mb.box_speed;
3131 };
3132 } else if cr.origin_position
3133 [0]
3134 + mb.box_speed
3135 >= 15_f32
3136 {
3137 cr.origin_position[0] =
3138 15_f32;
3139 delete_count += 1;
3140 deleted = true;
3141 } else {
3142 cr.origin_position
3143 [0] += mb.box_speed;
3144 };
3145 };
3146 };
3147 cr.origin_position[1] =
3148 mb.box_memory_offset + 20_f32;
3149 im1.origin_position = [
3150 cr.origin_position[0] + 5_f32,
3151 cr.origin_position[1]
3152 + mb.box_size[1] / 2_f32,
3153 ];
3154 t1.origin_position = [
3155 im1.origin_position[0]
3156 + im1.image_size[0]
3157 + 5_f32,
3158 cr.origin_position[1] + 5_f32,
3159 ];
3160 t2.origin_position = [
3161 im1.origin_position[0]
3162 + im1.image_size[0]
3163 + 5_f32,
3164 t1.origin_position[1]
3165 + self
3166 .get_text_size(
3167 &mb.box_title_name
3168 .clone(),
3169 ui,
3170 )
3171 .unwrap()[1],
3172 ];
3173 im2.origin_position = cr.position;
3174 if !mb.box_keep_existing
3175 && self.timer.total_time
3176 - self
3177 .split_time(&format!(
3178 "MessageBox{}",
3179 mb.name
3180 ))
3181 .unwrap()[1]
3182 >= mb.box_existing_time
3183 && cr.origin_position[0]
3184 == -mb.box_size[0] - 5_f32
3185 {
3186 mb.box_exist = false;
3187 if cr.origin_position[0]
3188 + mb.box_speed
3189 >= 15_f32
3190 {
3191 cr.origin_position[0] =
3192 15_f32;
3193 } else {
3194 cr.origin_position[0] +=
3195 mb.box_speed;
3196 };
3197 };
3198 if let Some(mouse_pos) =
3199 ui.input(|i| {
3200 i.pointer.hover_pos()
3201 })
3202 {
3203 let rect =
3204 egui::Rect::from_min_size(
3205 Pos2 {
3206 x: im2
3207 .image_position
3208 [0],
3209 y: im2
3210 .image_position
3211 [1],
3212 },
3213 Vec2 {
3214 x: cr.size[0]
3215 + 25_f32,
3216 y: cr.size[1]
3217 + 25_f32,
3218 },
3219 );
3220 if rect.contains(mouse_pos) {
3221 s.appearance[0].color[3] =
3222 200;
3223 } else {
3224 s.appearance[0].color[3] =
3225 0;
3226 };
3227 };
3228 self.rust_constructor_resource
3229 [index_list[i]] =
3230 RCR::MessageBox(mb.clone());
3231 self.rust_constructor_resource
3232 [id1] = RCR::Image(im1.clone());
3233 self.rust_constructor_resource
3234 [id2] =
3235 RCR::CustomRect(cr.clone());
3236 self.rust_constructor_resource
3237 [id3] = RCR::Text(t1.clone());
3238 self.rust_constructor_resource
3239 [id4] = RCR::Text(t2.clone());
3240 self.rust_constructor_resource
3241 [id5] = RCR::Switch(s.clone());
3242 self.rust_constructor_resource
3243 [id6] = RCR::Image(im2.clone());
3244 self.rect(
3245 ui,
3246 &format!(
3247 "MessageBox{}",
3248 mb.name
3249 ),
3250 ctx,
3251 );
3252 self.image(
3253 ui,
3254 &mb.box_image_name.clone(),
3255 ctx,
3256 );
3257 self.text(
3258 ui,
3259 &t1.name.clone(),
3260 ctx,
3261 );
3262 self.text(
3263 ui,
3264 &t2.name.clone(),
3265 ctx,
3266 );
3267 if self
3268 .switch(
3269 &format!(
3270 "MessageBox{}Close",
3271 mb.name
3272 ),
3273 ui,
3274 ctx,
3275 s.state == 0
3276 && mb.box_exist,
3277 true,
3278 )
3279 .unwrap()[0]
3280 == 0
3281 {
3282 mb.box_exist = false;
3283 if cr.origin_position[0]
3284 + mb.box_speed
3285 >= 15_f32
3286 {
3287 cr.origin_position[0] =
3288 15_f32;
3289 } else {
3290 cr.origin_position[0] +=
3291 mb.box_speed;
3292 };
3293 self.rust_constructor_resource[id2] = RCR::CustomRect(cr.clone());
3294 self.rust_constructor_resource[index_list[i]] = RCR::MessageBox(mb.clone());
3295 };
3296 if deleted {
3297 if let Ok(id) = self
3298 .get_resource_index(
3299 "Image",
3300 &mb.box_image_name,
3301 )
3302 {
3303 self.rust_constructor_resource.remove(id);
3304 };
3305 if let Ok(id) = self
3306 .get_resource_index(
3307 "CustomRect",
3308 &format!(
3309 "MessageBox{}",
3310 mb.name
3311 ),
3312 )
3313 {
3314 self.rust_constructor_resource.remove(id);
3315 };
3316 if let Ok(id) = self
3317 .get_resource_index(
3318 "Text",
3319 &mb.box_title_name,
3320 )
3321 {
3322 self.rust_constructor_resource.remove(id);
3323 };
3324 if let Ok(id) = self
3325 .get_resource_index(
3326 "Text",
3327 &mb.box_content_name,
3328 )
3329 {
3330 self.rust_constructor_resource.remove(id);
3331 };
3332 if let Ok(id) = self
3333 .get_resource_index(
3334 "Switch",
3335 &format!(
3336 "MessageBox{}Close",
3337 mb.name
3338 ),
3339 )
3340 {
3341 self.rust_constructor_resource.remove(id);
3342 };
3343 if let Ok(id) = self
3344 .get_resource_index(
3345 "Image",
3346 &format!(
3347 "MessageBox{}Close",
3348 mb.name
3349 ),
3350 )
3351 {
3352 self.rust_constructor_resource.remove(id);
3353 };
3354 if let Ok(id) = self.get_resource_index("SplitTime", &format!("MessageBox{}Animation", mb.name)) {
3355 self.rust_constructor_resource.remove(id);
3356 };
3357 if !mb.box_keep_existing {
3358 if let Ok(id) = self
3359 .get_resource_index(
3360 "SplitTime",
3361 &format!(
3362 "MessageBox{}",
3363 mb.name
3364 ),
3365 )
3366 {
3367 self.rust_constructor_resource.remove(id);
3368 };
3369 };
3370 if let Ok(id) = self
3371 .get_resource_index(
3372 "MessageBox",
3373 &mb.name,
3374 )
3375 {
3376 self.rust_constructor_resource.remove(id);
3377 };
3378 } else {
3379 offset +=
3380 mb.box_size[1] + 15_f32;
3381 };
3382 };
3383 };
3384 };
3385 };
3386 };
3387 };
3388 };
3389 };
3390 };
3391 };
3392 };
3393 };
3394 };
3395 }
3396 }
3397
3398 pub fn add_switch(
3400 &mut self,
3401 name_switch_image_name_text_name_and_sound_path: [&str; 4],
3402 mut appearance: Vec<SwitchData>,
3403 enable_hover_click_image_and_use_overlay: [bool; 3],
3404 switch_amounts_state: u32,
3405 click_method: Vec<SwitchClickAction>,
3406 ) {
3407 let mut count = 1;
3408 if enable_hover_click_image_and_use_overlay[0] {
3409 count += 1;
3410 };
3411 if enable_hover_click_image_and_use_overlay[1] {
3412 count += 1;
3413 };
3414 if appearance.len() as u32 != count * switch_amounts_state {
3415 self.problem_report(
3416 RustConstructorError::SwitchAppearanceMismatch {
3417 switch_name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3418 differ: (count as i32 * switch_amounts_state as i32 - appearance.len() as i32)
3419 .unsigned_abs(),
3420 },
3421 SeverityLevel::SevereWarning,
3422 );
3423 for _ in
3424 0..(count as i32 * switch_amounts_state as i32 - appearance.len() as i32) as usize
3425 {
3426 appearance.push(SwitchData {
3427 texture: "Error".to_string(),
3428 color: [255, 255, 255, 255],
3429 text: String::new(),
3430 hint_text: String::new(),
3431 });
3432 }
3433 };
3434 let mut text_origin_position = [0_f32, 0_f32];
3435 if let Ok(id) =
3436 self.get_resource_index("Image", name_switch_image_name_text_name_and_sound_path[1])
3437 {
3438 if let RCR::Image(mut im) = self.rust_constructor_resource[id].clone() {
3439 im.use_overlay_color = true;
3440 if self.check_resource_exists(
3441 "Text",
3442 name_switch_image_name_text_name_and_sound_path[2],
3443 ) {
3444 if let Ok(id2) = self.get_resource_index(
3445 "Text",
3446 name_switch_image_name_text_name_and_sound_path[2],
3447 ) {
3448 if let RCR::Text(t) = &mut self.rust_constructor_resource[id2] {
3449 t.center_display = [false, false, true, true];
3450 t.x_grid = [0, 0];
3451 t.y_grid = [0, 0];
3452 text_origin_position = t.origin_position;
3453 };
3454 };
3455 };
3456 self.rust_constructor_resource[id] = RCR::Image(im);
3457 };
3458 };
3459 if !appearance.iter().any(|x| x.hint_text.is_empty())
3460 {
3461 self.add_text(
3462 [
3463 &format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0]),
3464 "",
3465 "Content",
3466 ],
3467 [0_f32, 0_f32, 25_f32, 300_f32, 10_f32],
3468 [255, 255, 255, 0, 0, 0, 0, 0],
3469 [true, true, false, false, true, false],
3470 [0, 0, 0, 0],
3471 vec![],
3472 );
3473 self.add_split_time(
3474 &format!(
3475 "{}StartHoverTime",
3476 name_switch_image_name_text_name_and_sound_path[0]
3477 ),
3478 false,
3479 );
3480 self.add_split_time(
3481 &format!(
3482 "{}HintFadeAnimation",
3483 name_switch_image_name_text_name_and_sound_path[0]
3484 ),
3485 false,
3486 );
3487 };
3488 self.rust_constructor_resource.push(RCR::Switch(Switch {
3489 discern_type: "Switch".to_string(),
3490 name: name_switch_image_name_text_name_and_sound_path[0].to_string(),
3491 appearance: appearance.clone(),
3492 switch_image_name: name_switch_image_name_text_name_and_sound_path[1].to_string(),
3493 enable_hover_click_image: [
3494 enable_hover_click_image_and_use_overlay[0],
3495 enable_hover_click_image_and_use_overlay[1],
3496 ],
3497 state: 0,
3498 click_method,
3499 last_time_hovered: false,
3500 last_time_clicked: false,
3501 last_time_clicked_index: 0,
3502 animation_count: count,
3503 hint_text_name: if !appearance
3504 .iter()
3505 .any(|x| x.hint_text.is_empty())
3506 {
3507 format!("{}Hint", name_switch_image_name_text_name_and_sound_path[0])
3508 } else {
3509 "".to_string()
3510 },
3511 text_name: name_switch_image_name_text_name_and_sound_path[2].to_string(),
3512 text_origin_position,
3513 sound_path: name_switch_image_name_text_name_and_sound_path[3].to_string(),
3514 }));
3515 }
3516
3517 pub fn switch(
3519 &mut self,
3520 name: &str,
3521 ui: &mut Ui,
3522 ctx: &egui::Context,
3523 enable: bool,
3524 play_sound: bool,
3525 ) -> Result<[usize; 2], RustConstructorError> {
3526 let mut activated = [5, 0];
3527 let mut appearance_count = 0;
3528 if let Ok(id) = self.get_resource_index("Switch", name) {
3529 if let RCR::Switch(mut s) = self.rust_constructor_resource[id].clone() {
3530 if let Ok(id2) = self.get_resource_index("Image", &s.switch_image_name.clone()) {
3531 if let RCR::Image(mut im) = self.rust_constructor_resource[id2].clone() {
3532 s.reg_render_resource(&mut self.render_resource_list);
3533 let rect = Rect::from_min_size(
3534 Pos2::new(im.image_position[0], im.image_position[1]),
3535 Vec2::new(im.image_size[0], im.image_size[1]),
3536 );
3537 let mut hovered = false;
3538 if enable {
3539 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
3540 if rect.contains(mouse_pos) {
3542 if !s.hint_text_name.is_empty() {
3543 if let Ok(id3) =
3544 self.get_resource_index("Text", &s.hint_text_name)
3545 {
3546 if let RCR::Text(mut t) =
3547 self.rust_constructor_resource[id3].clone()
3548 {
3549 if !s.last_time_hovered {
3550 self.add_split_time(
3551 &format!("{}StartHoverTime", s.name),
3552 true,
3553 );
3554 } else if self.timer.total_time
3555 - self
3556 .split_time(&format!(
3557 "{}StartHoverTime",
3558 s.name
3559 ))
3560 .unwrap()[1]
3561 >= 2_f32
3562 || t.rgba[3] != 0
3563 {
3564 t.rgba[3] = 255;
3565 t.origin_position = [mouse_pos.x, mouse_pos.y];
3566 };
3567 t.center_display[0] = mouse_pos.x + self
3568 .get_text_size(&s.hint_text_name, ui)
3569 .unwrap()[0]
3570 <= ctx.available_rect().width();
3571 t.center_display[1] = mouse_pos.y
3572 + self
3573 .get_text_size(&s.hint_text_name, ui)
3574 .unwrap()[1]
3575 <= ctx.available_rect().height();
3576 self.rust_constructor_resource[id3] = RCR::Text(t);
3577 };
3578 };
3579 };
3580 hovered = true;
3581 let mut clicked = vec![];
3582 let mut active = false;
3583 for u in 0..s.click_method.len() as u32 {
3584 clicked.push(ui.input(|i| {
3585 i.pointer.button_down(
3586 s.click_method[u as usize].click_method,
3587 )
3588 }));
3589 if clicked[u as usize] {
3590 active = true;
3591 s.last_time_clicked_index = u as usize;
3592 break;
3593 };
3594 }
3595 if active {
3596 s.last_time_clicked = true;
3597 if s.enable_hover_click_image[1] {
3598 if s.enable_hover_click_image[0] {
3599 appearance_count = 2;
3600 } else {
3601 appearance_count = 1;
3602 };
3603 } else if !s.enable_hover_click_image[0] {
3604 appearance_count = 0;
3605 };
3606 } else {
3607 if s.last_time_clicked {
3608 if play_sound {
3609 general_click_feedback(&s.sound_path);
3610 };
3611 let mut count = 1;
3612 if s.enable_hover_click_image[0] {
3613 count += 1;
3614 };
3615 if s.enable_hover_click_image[1] {
3616 count += 1;
3617 };
3618 if s.click_method[s.last_time_clicked_index].action {
3619 if s.state < (s.appearance.len() / count - 1) as u32
3620 {
3621 s.state += 1;
3622 } else {
3623 s.state = 0;
3624 };
3625 };
3626 activated[0] = s.last_time_clicked_index;
3627 s.last_time_clicked = false;
3628 };
3629 if s.enable_hover_click_image[0] {
3630 appearance_count = 1;
3631 } else {
3632 appearance_count = 0;
3633 };
3634 };
3635 } else {
3636 s.last_time_clicked = false;
3637 appearance_count = 0;
3638 };
3639 } else {
3640 s.last_time_clicked = false;
3641 appearance_count = 0;
3642 };
3643 } else {
3644 s.last_time_clicked = false;
3645 appearance_count = 0;
3646 };
3647 if !hovered && !s.hint_text_name.is_empty() {
3648 if s.last_time_hovered {
3649 self.add_split_time(&format!("{}HintFadeAnimation", s.name), true);
3650 };
3651 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3652 if let RCR::Text(mut t) =
3653 self.rust_constructor_resource[id3].clone()
3654 {
3655 if self.timer.total_time
3656 - self
3657 .split_time(&format!("{}HintFadeAnimation", s.name))
3658 .unwrap()[1]
3659 >= self.vertrefresh
3660 {
3661 t.rgba[3] = t.rgba[3].saturating_sub(1);
3662 };
3663 self.rust_constructor_resource[id3] = RCR::Text(t);
3664 };
3665 };
3666 };
3667 im.overlay_color = s.appearance
3668 [(s.state * s.animation_count + appearance_count) as usize]
3669 .color;
3670 if let Ok(id4) = self.get_resource_index(
3671 "ImageTexture",
3672 &s.appearance
3673 [(s.state * s.animation_count + appearance_count) as usize]
3674 .texture
3675 .clone(),
3676 ) {
3677 if let RCR::ImageTexture(it) =
3678 self.rust_constructor_resource[id4].clone()
3679 {
3680 im.image_texture = it.texture.clone();
3681 };
3682 };
3683 if !s.hint_text_name.is_empty() {
3684 if let Ok(id3) = self.get_resource_index("Text", &s.hint_text_name) {
3685 if let RCR::Text(mut t) =
3686 self.rust_constructor_resource[id3].clone()
3687 {
3688 t.background_rgb[3] = t.rgba[3];
3689 t.text_content = s.appearance
3690 [(s.state * s.animation_count + appearance_count) as usize]
3691 .hint_text
3692 .clone();
3693 self.rust_constructor_resource[id3] = RCR::Text(t);
3694 };
3695 };
3696 };
3697 s.last_time_hovered = hovered;
3698 activated[1] = s.state as usize;
3699 self.rust_constructor_resource[id] = RCR::Switch(s.clone());
3700 self.rust_constructor_resource[id2] = RCR::Image(im.clone());
3701 self.image(ui, &s.switch_image_name.clone(), ctx);
3702 if self.check_resource_exists("Text", &s.text_name) {
3703 if let Ok(id4) = self.get_resource_index("Text", &s.text_name) {
3704 if let RCR::Text(mut t2) =
3705 self.rust_constructor_resource[id4].clone()
3706 {
3707 t2.origin_position = [
3708 im.image_position[0] + s.text_origin_position[0],
3709 im.image_position[1] + s.text_origin_position[1],
3710 ];
3711 t2.text_content = s.appearance
3712 [(s.state * s.animation_count + appearance_count) as usize]
3713 .text
3714 .clone();
3715 self.rust_constructor_resource[id4] = RCR::Text(t2);
3716 };
3717 };
3718 self.text(ui, &s.text_name, ctx);
3719 };
3720 if self.check_resource_exists("Text", &s.hint_text_name) {
3721 self.text(ui, &s.hint_text_name, ctx);
3722 };
3723 Ok(activated)
3724 } else {
3725 Err(RustConstructorError::ImageNotFound {
3727 image_name: s.switch_image_name,
3728 })
3729 }
3730 } else {
3731 self.problem_report(
3732 RustConstructorError::ImageNotFound {
3733 image_name: name.to_string(),
3734 },
3735 SeverityLevel::SevereWarning,
3736 );
3737 Err(RustConstructorError::ImageNotFound {
3738 image_name: s.switch_image_name,
3739 })
3740 }
3741 } else {
3742 Err(RustConstructorError::SwitchNotFound {
3744 switch_name: name.to_string(),
3745 })
3746 }
3747 } else {
3748 self.problem_report(
3749 RustConstructorError::SwitchNotFound {
3750 switch_name: name.to_string(),
3751 },
3752 SeverityLevel::SevereWarning,
3753 );
3754 Err(RustConstructorError::SwitchNotFound {
3755 switch_name: name.to_string(),
3756 })
3757 }
3758 }
3759}