1use eframe::{
23 Result,
24 emath::Rect,
25 epaint::{Stroke, textures::TextureOptions},
26};
27use egui::{
28 Color32, ColorImage, Context, FontData, FontDefinitions, FontFamily, FontId, Galley, Id,
29 ImageSource, Key, OpenUrl, PointerButton, Pos2, Sense, StrokeKind, TextureHandle, Ui, Vec2,
30 text::CCursor,
31};
32use std::{
33 any::Any,
34 error::Error,
35 fmt::{Debug, Display, Formatter},
36 fs::{File, read},
37 io::Read,
38 sync::Arc,
39 time::Instant,
40 vec::Vec,
41};
42
43pub trait RustConstructorResource: Debug {
45 fn name(&self) -> &str;
47
48 fn expose_type(&self) -> &str;
50
51 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
53 render_list.push(RenderResource {
54 discern_type: self.expose_type().to_string(),
55 name: self.name().to_string(),
56 });
57 }
58
59 fn as_any(&self) -> &dyn Any;
61
62 fn as_any_mut(&mut self) -> &mut dyn Any;
64}
65
66pub trait BasicFrontResource: RustConstructorResource {
68 fn size(&self) -> [f32; 2];
70
71 fn position(&self) -> [f32; 2];
73
74 fn modify_size(&mut self, width: f32, height: f32);
76
77 fn modify_position(&mut self, x: f32, y: f32);
79
80 fn modify_add_position(&mut self, add_x: f32, add_y: f32);
82}
83
84#[derive(Debug, Clone, PartialEq, PartialOrd)]
86pub struct PositionConfig {
87 pub origin_position: [f32; 2],
89 pub size: [f32; 2],
91 pub x_grid: [u32; 2],
93 pub y_grid: [u32; 2],
95 pub center_display: (HorizontalAlign, VerticalAlign),
97 pub offset: [f32; 2],
99}
100
101impl Default for PositionConfig {
102 fn default() -> Self {
103 PositionConfig {
104 origin_position: [0_f32, 0_f32],
105 size: [100_f32, 100_f32],
106 x_grid: [0, 0],
107 y_grid: [0, 0],
108 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
109 offset: [0_f32, 0_f32],
110 }
111 }
112}
113
114impl PositionConfig {
115 pub fn from_image(image: Image) -> Self {
116 Self {
117 origin_position: image.origin_position,
118 size: image.size,
119 x_grid: image.x_grid,
120 y_grid: image.y_grid,
121 center_display: image.center_display,
122 offset: image.offset,
123 }
124 }
125
126 pub fn from_image_config(image_config: ImageConfig) -> Self {
127 Self {
128 origin_position: image_config.origin_position,
129 size: image_config.size,
130 x_grid: image_config.x_grid,
131 y_grid: image_config.y_grid,
132 center_display: image_config.center_display,
133 offset: image_config.offset,
134 }
135 }
136
137 pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
138 Self {
139 origin_position: custom_rect.origin_position,
140 size: custom_rect.size,
141 x_grid: custom_rect.x_grid,
142 y_grid: custom_rect.y_grid,
143 center_display: custom_rect.center_display,
144 offset: custom_rect.offset,
145 }
146 }
147
148 pub fn from_custom_rect_config(custom_rect_config: CustomRectConfig) -> Self {
149 Self {
150 origin_position: custom_rect_config.origin_position,
151 size: custom_rect_config.size,
152 x_grid: custom_rect_config.x_grid,
153 y_grid: custom_rect_config.y_grid,
154 center_display: custom_rect_config.center_display,
155 offset: custom_rect_config.offset,
156 }
157 }
158
159 pub fn from_text(text: Text) -> Self {
160 Self {
161 origin_position: text.origin_position,
162 size: text.size,
163 x_grid: text.x_grid,
164 y_grid: text.y_grid,
165 center_display: text.center_display,
166 offset: text.offset,
167 }
168 }
169
170 pub fn from_text_config(mut self, text_config: TextConfig) -> Self {
171 self.origin_position = text_config.origin_position;
172 self.size = text_config.size;
173 self.x_grid = text_config.x_grid;
174 self.y_grid = text_config.y_grid;
175 self.center_display = text_config.center_display;
176 self.offset = text_config.offset;
177 self
178 }
179
180 pub fn from_mouse_detector(mouse_detector: MouseDetector) -> Self {
181 Self {
182 origin_position: mouse_detector.origin_position,
183 size: mouse_detector.size,
184 x_grid: mouse_detector.x_grid,
185 y_grid: mouse_detector.y_grid,
186 center_display: mouse_detector.center_display,
187 offset: mouse_detector.offset,
188 }
189 }
190
191 #[inline]
192 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
193 self.origin_position = [x, y];
194 self
195 }
196
197 #[inline]
198 pub fn size(mut self, width: f32, height: f32) -> Self {
199 self.size = [width, height];
200 self
201 }
202
203 #[inline]
204 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
205 self.x_grid = [fetch, total];
206 self
207 }
208
209 #[inline]
210 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
211 self.y_grid = [fetch, total];
212 self
213 }
214
215 #[inline]
216 pub fn center_display(
217 mut self,
218 horizontal_align: HorizontalAlign,
219 vertical_align: VerticalAlign,
220 ) -> Self {
221 self.center_display = (horizontal_align, vertical_align);
222 self
223 }
224
225 #[inline]
226 pub fn offset(mut self, x: f32, y: f32) -> Self {
227 self.offset = [x, y];
228 self
229 }
230}
231
232#[derive(Debug, Clone, PartialEq, PartialOrd)]
234pub enum Value {
235 Bool(bool),
236 Int(i32),
237 UInt(u32),
238 Float(f32),
239 Vec(Vec<Value>),
240 String(String),
241}
242
243impl From<bool> for Value {
244 fn from(b: bool) -> Self {
245 Value::Bool(b)
246 }
247}
248
249impl From<i32> for Value {
250 fn from(i: i32) -> Self {
251 Value::Int(i)
252 }
253}
254
255impl From<u32> for Value {
256 fn from(u: u32) -> Self {
257 Value::UInt(u)
258 }
259}
260
261impl From<f32> for Value {
262 fn from(f: f32) -> Self {
263 Value::Float(f)
264 }
265}
266
267impl<T: Into<Value>> From<Vec<T>> for Value {
268 fn from(v: Vec<T>) -> Self {
269 Value::Vec(v.into_iter().map(|x| x.into()).collect())
270 }
271}
272
273impl From<String> for Value {
274 fn from(s: String) -> Self {
275 Value::String(s)
276 }
277}
278
279#[derive(Debug, Clone, PartialEq, PartialOrd)]
281pub struct ReportState {
282 pub current_page: String,
284 pub current_total_runtime: f32,
286 pub current_page_runtime: f32,
288}
289
290#[derive(Debug, Clone, PartialEq, PartialOrd)]
292pub struct Problem {
293 pub severity_level: SeverityLevel,
295 pub problem: String,
297 pub annotation: String,
299 pub report_state: ReportState,
301 pub problem_type: RustConstructorError,
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
307pub enum SeverityLevel {
308 MildWarning,
310 SevereWarning,
312 Error,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
318pub struct PageData {
319 pub discern_type: String,
320 pub name: String,
321 pub forced_update: bool,
323 pub change_page_updated: bool,
325 pub enter_page_updated: bool,
327}
328
329impl RustConstructorResource for PageData {
330 fn name(&self) -> &str {
331 &self.name
332 }
333
334 fn expose_type(&self) -> &str {
335 &self.discern_type
336 }
337
338 fn as_any(&self) -> &dyn Any {
339 self
340 }
341
342 fn as_any_mut(&mut self) -> &mut dyn Any {
343 self
344 }
345}
346
347impl Default for PageData {
348 fn default() -> Self {
349 PageData {
350 discern_type: String::from("PageData"),
351 name: String::from("PageData"),
352 forced_update: true,
353 change_page_updated: false,
354 enter_page_updated: false,
355 }
356 }
357}
358
359impl PageData {
360 #[inline]
361 pub fn name(mut self, name: &str) -> Self {
362 self.name = name.to_string();
363 self
364 }
365
366 #[inline]
367 pub fn forced_update(mut self, forced_update: bool) -> Self {
368 self.forced_update = forced_update;
369 self
370 }
371}
372
373#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
375pub struct Timer {
376 pub start_time: f32,
378 pub total_time: f32,
380 pub timer: Instant,
382 pub now_time: f32,
384}
385
386impl Default for Timer {
387 fn default() -> Self {
388 Timer {
389 start_time: 0_f32,
390 total_time: 0_f32,
391 timer: Instant::now(),
392 now_time: 0_f32,
393 }
394 }
395}
396
397#[derive(Clone, PartialEq, Eq, Hash)]
399pub struct DebugTextureHandle(TextureHandle);
400
401impl Debug for DebugTextureHandle {
402 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
403 f.debug_struct("DebugTextureHandle").finish()
405 }
406}
407
408impl DebugTextureHandle {
409 pub fn new(texture_handle: TextureHandle) -> Self {
410 Self(texture_handle)
411 }
412}
413
414#[derive(Debug, Clone, PartialEq, Eq, Hash)]
416pub struct ImageTexture {
417 pub discern_type: String,
418 pub name: String,
419 pub texture: Option<DebugTextureHandle>,
421 pub cite_path: String,
423}
424
425impl RustConstructorResource for ImageTexture {
426 fn name(&self) -> &str {
427 &self.name
428 }
429
430 fn expose_type(&self) -> &str {
431 &self.discern_type
432 }
433
434 fn as_any(&self) -> &dyn Any {
435 self
436 }
437
438 fn as_any_mut(&mut self) -> &mut dyn Any {
439 self
440 }
441}
442
443impl Default for ImageTexture {
444 fn default() -> Self {
445 ImageTexture {
446 discern_type: String::from("ImageTexture"),
447 name: String::from("ImageTexture"),
448 texture: None,
449 cite_path: String::from(""),
450 }
451 }
452}
453
454impl ImageTexture {
455 #[inline]
456 pub fn name(mut self, name: &str) -> Self {
457 self.name = name.to_string();
458 self
459 }
460}
461
462#[derive(Debug, Clone, PartialEq, PartialOrd)]
464pub struct CustomRectConfig {
465 pub size: [f32; 2],
467 pub rounding: f32,
469 pub x_grid: [u32; 2],
471 pub y_grid: [u32; 2],
473 pub center_display: (HorizontalAlign, VerticalAlign),
475 pub offset: [f32; 2],
477 pub color: [u8; 4],
479 pub border_width: f32,
481 pub border_color: [u8; 4],
483 pub origin_position: [f32; 2],
485}
486
487impl Default for CustomRectConfig {
488 fn default() -> Self {
489 Self {
490 size: [100_f32, 100_f32],
491 rounding: 2_f32,
492 x_grid: [0, 0],
493 y_grid: [0, 0],
494 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
495 offset: [0_f32, 0_f32],
496 color: [255, 255, 255, 255],
497 border_width: 2_f32,
498 border_color: [0, 0, 0, 255],
499 origin_position: [0_f32, 0_f32],
500 }
501 }
502}
503
504impl CustomRectConfig {
505 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
506 self.origin_position = position_config.origin_position;
507 self.size = position_config.size;
508 self.x_grid = position_config.x_grid;
509 self.y_grid = position_config.y_grid;
510 self.center_display = position_config.center_display;
511 self.offset = position_config.offset;
512 self
513 }
514
515 pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
516 Self {
517 size: custom_rect.size,
518 rounding: custom_rect.rounding,
519 x_grid: custom_rect.x_grid,
520 y_grid: custom_rect.y_grid,
521 center_display: custom_rect.center_display,
522 offset: custom_rect.offset,
523 color: custom_rect.color,
524 border_width: custom_rect.border_width,
525 border_color: custom_rect.border_color,
526 origin_position: custom_rect.origin_position,
527 }
528 }
529
530 #[inline]
531 pub fn size(mut self, width: f32, height: f32) -> Self {
532 self.size = [width, height];
533 self
534 }
535
536 #[inline]
537 pub fn rounding(mut self, rounding: f32) -> Self {
538 self.rounding = rounding;
539 self
540 }
541
542 #[inline]
543 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
544 self.x_grid = [fetch, total];
545 self
546 }
547
548 #[inline]
549 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
550 self.y_grid = [fetch, total];
551 self
552 }
553
554 #[inline]
555 pub fn center_display(
556 mut self,
557 horizontal_align: HorizontalAlign,
558 vertical_align: VerticalAlign,
559 ) -> Self {
560 self.center_display = (horizontal_align, vertical_align);
561 self
562 }
563
564 #[inline]
565 pub fn offset(mut self, x: f32, y: f32) -> Self {
566 self.offset = [x, y];
567 self
568 }
569
570 #[inline]
571 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
572 self.color = [r, g, b, a];
573 self
574 }
575
576 #[inline]
577 pub fn border_width(mut self, border_width: f32) -> Self {
578 self.border_width = border_width;
579 self
580 }
581
582 #[inline]
583 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
584 self.border_color = [r, g, b, a];
585 self
586 }
587
588 #[inline]
589 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
590 self.origin_position = [x, y];
591 self
592 }
593}
594
595#[derive(Debug, Clone, PartialEq, PartialOrd)]
597pub struct CustomRect {
598 pub discern_type: String,
599 pub name: String,
600 pub position: [f32; 2],
602 pub size: [f32; 2],
604 pub rounding: f32,
606 pub x_grid: [u32; 2],
608 pub y_grid: [u32; 2],
610 pub center_display: (HorizontalAlign, VerticalAlign),
612 pub offset: [f32; 2],
614 pub color: [u8; 4],
616 pub border_width: f32,
618 pub border_color: [u8; 4],
620 pub origin_position: [f32; 2],
622}
623
624impl RustConstructorResource for CustomRect {
625 fn name(&self) -> &str {
626 &self.name
627 }
628
629 fn expose_type(&self) -> &str {
630 &self.discern_type
631 }
632
633 fn as_any(&self) -> &dyn Any {
634 self
635 }
636
637 fn as_any_mut(&mut self) -> &mut dyn Any {
638 self
639 }
640}
641
642impl BasicFrontResource for CustomRect {
643 fn position(&self) -> [f32; 2] {
644 self.position
645 }
646
647 fn size(&self) -> [f32; 2] {
648 self.size
649 }
650
651 fn modify_position(&mut self, x: f32, y: f32) {
652 self.origin_position = [x, y];
653 }
654
655 fn modify_size(&mut self, width: f32, height: f32) {
656 self.size = [width, height];
657 }
658
659 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
660 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
661 }
662}
663
664impl Default for CustomRect {
665 fn default() -> Self {
666 Self {
667 discern_type: String::from("CustomRect"),
668 name: String::from("CustomRect"),
669 position: [0_f32, 0_f32],
670 size: [100_f32, 100_f32],
671 rounding: 2_f32,
672 x_grid: [0, 0],
673 y_grid: [0, 0],
674 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
675 offset: [0_f32, 0_f32],
676 color: [255, 255, 255, 255],
677 border_width: 2_f32,
678 border_color: [0, 0, 0, 255],
679 origin_position: [0_f32, 0_f32],
680 }
681 }
682}
683
684impl CustomRect {
685 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
686 self.origin_position = position_config.origin_position;
687 self.size = position_config.size;
688 self.x_grid = position_config.x_grid;
689 self.y_grid = position_config.y_grid;
690 self.center_display = position_config.center_display;
691 self.offset = position_config.offset;
692 self
693 }
694
695 pub fn from_config(mut self, config: CustomRectConfig) -> Self {
696 self.size = config.size;
697 self.rounding = config.rounding;
698 self.x_grid = config.x_grid;
699 self.y_grid = config.y_grid;
700 self.center_display = config.center_display;
701 self.offset = config.offset;
702 self.color = config.color;
703 self.border_width = config.border_width;
704 self.border_color = config.border_color;
705 self.origin_position = config.origin_position;
706 self
707 }
708
709 #[inline]
710 pub fn name(mut self, name: &str) -> Self {
711 self.name = name.to_string();
712 self
713 }
714
715 #[inline]
716 pub fn size(mut self, width: f32, height: f32) -> Self {
717 self.size = [width, height];
718 self
719 }
720
721 #[inline]
722 pub fn rounding(mut self, rounding: f32) -> Self {
723 self.rounding = rounding;
724 self
725 }
726
727 #[inline]
728 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
729 self.x_grid = [fetch, total];
730 self
731 }
732
733 #[inline]
734 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
735 self.y_grid = [fetch, total];
736 self
737 }
738
739 #[inline]
740 pub fn center_display(
741 mut self,
742 horizontal_align: HorizontalAlign,
743 vertical_align: VerticalAlign,
744 ) -> Self {
745 self.center_display = (horizontal_align, vertical_align);
746 self
747 }
748
749 #[inline]
750 pub fn offset(mut self, x: f32, y: f32) -> Self {
751 self.offset = [x, y];
752 self
753 }
754
755 #[inline]
756 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
757 self.color = [r, g, b, a];
758 self
759 }
760
761 #[inline]
762 pub fn border_width(mut self, border_width: f32) -> Self {
763 self.border_width = border_width;
764 self
765 }
766
767 #[inline]
768 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
769 self.border_color = [r, g, b, a];
770 self
771 }
772
773 #[inline]
774 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
775 self.origin_position = [x, y];
776 self
777 }
778}
779
780#[derive(Debug, Clone, PartialEq, PartialOrd)]
782pub struct ImageConfig {
783 pub size: [f32; 2],
785 pub x_grid: [u32; 2],
787 pub y_grid: [u32; 2],
789 pub center_display: (HorizontalAlign, VerticalAlign),
791 pub offset: [f32; 2],
793 pub alpha: u8,
795 pub overlay_color: [u8; 4],
797 pub background_color: [u8; 4],
799 pub rotate_angle: f32,
801 pub rotate_center: [f32; 2],
803 pub origin_position: [f32; 2],
805 pub cite_texture: String,
807}
808
809impl Default for ImageConfig {
810 fn default() -> Self {
811 Self {
812 size: [100_f32, 100_f32],
813 x_grid: [0, 0],
814 y_grid: [0, 0],
815 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
816 offset: [0_f32, 0_f32],
817 alpha: 255,
818 overlay_color: [255, 255, 255, 255],
819 background_color: [0, 0, 0, 0],
820 rotate_angle: 0_f32,
821 rotate_center: [0_f32, 0_f32],
822 origin_position: [0_f32, 0_f32],
823 cite_texture: String::from("ImageTexture"),
824 }
825 }
826}
827
828impl ImageConfig {
829 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
830 self.origin_position = position_config.origin_position;
831 self.size = position_config.size;
832 self.x_grid = position_config.x_grid;
833 self.y_grid = position_config.y_grid;
834 self.center_display = position_config.center_display;
835 self.offset = position_config.offset;
836 self
837 }
838
839 pub fn from_image(image: Image) -> Self {
840 Self {
841 size: image.size,
842 x_grid: image.x_grid,
843 y_grid: image.y_grid,
844 center_display: image.center_display,
845 offset: image.offset,
846 alpha: image.alpha,
847 overlay_color: image.overlay_color,
848 background_color: image.background_color,
849 rotate_angle: image.rotate_angle,
850 rotate_center: image.rotate_center,
851 cite_texture: image.cite_texture,
852 origin_position: image.origin_position,
853 }
854 }
855
856 #[inline]
857 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
858 self.origin_position = [x, y];
859 self
860 }
861
862 #[inline]
863 pub fn size(mut self, width: f32, height: f32) -> Self {
864 self.size = [width, height];
865 self
866 }
867
868 #[inline]
869 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
870 self.x_grid = [fetch, total];
871 self
872 }
873
874 #[inline]
875 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
876 self.y_grid = [fetch, total];
877 self
878 }
879
880 #[inline]
881 pub fn center_display(
882 mut self,
883 horizontal_align: HorizontalAlign,
884 vertical_align: VerticalAlign,
885 ) -> Self {
886 self.center_display = (horizontal_align, vertical_align);
887 self
888 }
889
890 #[inline]
891 pub fn offset(mut self, x: f32, y: f32) -> Self {
892 self.offset = [x, y];
893 self
894 }
895
896 #[inline]
897 pub fn alpha(mut self, alpha: u8) -> Self {
898 self.alpha = alpha;
899 self
900 }
901
902 #[inline]
903 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
904 self.overlay_color = [r, g, b, a];
905 self
906 }
907
908 #[inline]
909 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
910 self.background_color = [r, g, b, a];
911 self
912 }
913
914 #[inline]
915 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
916 self.rotate_angle = rotate_angle;
917 self
918 }
919
920 #[inline]
921 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
922 self.rotate_center = [x, y];
923 self
924 }
925}
926
927#[derive(Debug, Clone, PartialEq)]
929pub struct Image {
930 pub discern_type: String,
931 pub name: String,
932 pub texture: Option<DebugTextureHandle>,
934 pub position: [f32; 2],
936 pub size: [f32; 2],
938 pub x_grid: [u32; 2],
940 pub y_grid: [u32; 2],
942 pub center_display: (HorizontalAlign, VerticalAlign),
944 pub offset: [f32; 2],
946 pub alpha: u8,
948 pub overlay_color: [u8; 4],
950 pub background_color: [u8; 4],
952 pub rotate_angle: f32,
954 pub rotate_center: [f32; 2],
956 pub origin_position: [f32; 2],
958 pub cite_texture: String,
960 pub last_frame_cite_texture: String,
962}
963
964impl RustConstructorResource for Image {
965 fn name(&self) -> &str {
966 &self.name
967 }
968
969 fn expose_type(&self) -> &str {
970 &self.discern_type
971 }
972
973 fn as_any(&self) -> &dyn Any {
974 self
975 }
976
977 fn as_any_mut(&mut self) -> &mut dyn Any {
978 self
979 }
980}
981
982impl BasicFrontResource for Image {
983 fn position(&self) -> [f32; 2] {
984 self.position
985 }
986
987 fn size(&self) -> [f32; 2] {
988 self.size
989 }
990
991 fn modify_position(&mut self, x: f32, y: f32) {
992 self.origin_position = [x, y];
993 }
994
995 fn modify_size(&mut self, width: f32, height: f32) {
996 self.size = [width, height];
997 }
998
999 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
1000 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
1001 }
1002}
1003
1004impl Default for Image {
1005 fn default() -> Self {
1006 Self {
1007 discern_type: String::from("Image"),
1008 name: String::from("Image"),
1009 texture: None,
1010 position: [0_f32, 0_f32],
1011 size: [100_f32, 100_f32],
1012 x_grid: [0, 0],
1013 y_grid: [0, 0],
1014 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1015 offset: [0_f32, 0_f32],
1016 alpha: 255,
1017 overlay_color: [255, 255, 255, 255],
1018 background_color: [0, 0, 0, 0],
1019 rotate_angle: 0_f32,
1020 rotate_center: [0_f32, 0_f32],
1021 origin_position: [0_f32, 0_f32],
1022 cite_texture: String::from("ImageTexture"),
1023 last_frame_cite_texture: String::from("ImageTexture"),
1024 }
1025 }
1026}
1027
1028impl Image {
1029 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1030 self.origin_position = position_config.origin_position;
1031 self.size = position_config.size;
1032 self.x_grid = position_config.x_grid;
1033 self.y_grid = position_config.y_grid;
1034 self.center_display = position_config.center_display;
1035 self.offset = position_config.offset;
1036 self
1037 }
1038
1039 pub fn from_config(mut self, config: ImageConfig) -> Self {
1040 self.size = config.size;
1041 self.x_grid = config.x_grid;
1042 self.y_grid = config.y_grid;
1043 self.center_display = config.center_display;
1044 self.offset = config.offset;
1045 self.alpha = config.alpha;
1046 self.overlay_color = config.overlay_color;
1047 self.background_color = config.background_color;
1048 self.rotate_angle = config.rotate_angle;
1049 self.rotate_center = config.rotate_center;
1050 self.origin_position = config.origin_position;
1051 self.cite_texture = config.cite_texture;
1052 self
1053 }
1054
1055 #[inline]
1056 pub fn name(mut self, name: &str) -> Self {
1057 self.name = name.to_string();
1058 self
1059 }
1060
1061 #[inline]
1062 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1063 self.origin_position = [x, y];
1064 self
1065 }
1066
1067 #[inline]
1068 pub fn size(mut self, width: f32, height: f32) -> Self {
1069 self.size = [width, height];
1070 self
1071 }
1072
1073 #[inline]
1074 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1075 self.x_grid = [fetch, total];
1076 self
1077 }
1078
1079 #[inline]
1080 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1081 self.y_grid = [fetch, total];
1082 self
1083 }
1084
1085 #[inline]
1086 pub fn center_display(
1087 mut self,
1088 horizontal_align: HorizontalAlign,
1089 vertical_align: VerticalAlign,
1090 ) -> Self {
1091 self.center_display = (horizontal_align, vertical_align);
1092 self
1093 }
1094
1095 #[inline]
1096 pub fn offset(mut self, x: f32, y: f32) -> Self {
1097 self.offset = [x, y];
1098 self
1099 }
1100
1101 #[inline]
1102 pub fn alpha(mut self, alpha: u8) -> Self {
1103 self.alpha = alpha;
1104 self
1105 }
1106
1107 #[inline]
1108 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1109 self.overlay_color = [r, g, b, a];
1110 self
1111 }
1112
1113 #[inline]
1114 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1115 self.background_color = [r, g, b, a];
1116 self
1117 }
1118
1119 #[inline]
1120 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1121 self.rotate_angle = rotate_angle;
1122 self
1123 }
1124
1125 #[inline]
1126 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1127 self.rotate_center = [x, y];
1128 self
1129 }
1130}
1131
1132#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1134pub enum HyperlinkSelectMethod {
1135 All(String),
1137 Segment(Vec<(usize, String)>),
1139}
1140
1141#[derive(Debug, Clone, PartialEq, PartialOrd)]
1143pub struct TextConfig {
1144 pub content: String,
1146 pub font_size: f32,
1148 pub color: [u8; 4],
1150 pub center_display: (HorizontalAlign, VerticalAlign),
1152 pub offset: [f32; 2],
1154 pub wrap_width: f32,
1156 pub background_color: [u8; 4],
1158 pub background_rounding: f32,
1160 pub x_grid: [u32; 2],
1162 pub y_grid: [u32; 2],
1164 pub origin_position: [f32; 2],
1166 pub font: String,
1168 pub selectable: bool,
1170 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1172 pub size: [f32; 2],
1174}
1175
1176impl Default for TextConfig {
1177 fn default() -> Self {
1178 Self {
1179 content: String::from("Hello world"),
1180 font_size: 16_f32,
1181 color: [255, 255, 255, 255],
1182 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1183 offset: [0_f32, 0_f32],
1184 wrap_width: 200_f32,
1185 background_color: [0, 0, 0, 0],
1186 background_rounding: 2_f32,
1187 x_grid: [0, 0],
1188 y_grid: [0, 0],
1189 origin_position: [0_f32, 0_f32],
1190 font: String::new(),
1191 selectable: true,
1192 hyperlink_text: Vec::new(),
1193 size: [0_f32, 0_f32],
1194 }
1195 }
1196}
1197
1198impl TextConfig {
1199 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1200 self.origin_position = position_config.origin_position;
1201 self.wrap_width = position_config.size[0];
1202 self.x_grid = position_config.x_grid;
1203 self.y_grid = position_config.y_grid;
1204 self.center_display = position_config.center_display;
1205 self.offset = position_config.offset;
1206 self.size = position_config.size;
1207 self
1208 }
1209
1210 pub fn from_text(text: Text) -> Self {
1211 Self {
1212 content: text.content,
1213 font_size: text.font_size,
1214 color: text.color,
1215 center_display: text.center_display,
1216 offset: text.offset,
1217 wrap_width: text.wrap_width,
1218 background_color: text.background_color,
1219 background_rounding: text.background_rounding,
1220 x_grid: text.x_grid,
1221 y_grid: text.y_grid,
1222 origin_position: text.origin_position,
1223 font: text.font,
1224 selectable: text.selectable,
1225 hyperlink_text: text.hyperlink_text,
1226 size: text.size,
1227 }
1228 }
1229
1230 #[inline]
1231 pub fn content(mut self, content: &str) -> Self {
1232 self.content = content.to_string();
1233 self
1234 }
1235
1236 #[inline]
1237 pub fn font_size(mut self, font_size: f32) -> Self {
1238 self.font_size = font_size;
1239 self
1240 }
1241
1242 #[inline]
1243 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1244 self.color = [r, g, b, a];
1245 self
1246 }
1247
1248 #[inline]
1249 pub fn center_display(
1250 mut self,
1251 horizontal_align: HorizontalAlign,
1252 vertical_align: VerticalAlign,
1253 ) -> Self {
1254 self.center_display = (horizontal_align, vertical_align);
1255 self
1256 }
1257
1258 #[inline]
1259 pub fn offset(mut self, x: f32, y: f32) -> Self {
1260 self.offset = [x, y];
1261 self
1262 }
1263
1264 #[inline]
1265 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1266 self.wrap_width = wrap_width;
1267 self
1268 }
1269
1270 #[inline]
1271 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1272 self.background_color = [r, g, b, a];
1273 self
1274 }
1275
1276 #[inline]
1277 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1278 self.background_rounding = background_rounding;
1279 self
1280 }
1281
1282 #[inline]
1283 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1284 self.x_grid = [fetch, total];
1285 self
1286 }
1287
1288 #[inline]
1289 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1290 self.y_grid = [fetch, total];
1291 self
1292 }
1293
1294 #[inline]
1295 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1296 self.origin_position = [x, y];
1297 self
1298 }
1299
1300 #[inline]
1301 pub fn font(mut self, font: &str) -> Self {
1302 self.font = font.to_string();
1303 self
1304 }
1305
1306 #[inline]
1307 pub fn selectable(mut self, selectable: bool) -> Self {
1308 self.selectable = selectable;
1309 self
1310 }
1311
1312 #[inline]
1313 pub fn hyperlink_text(
1314 mut self,
1315 target_text: &str,
1316 select_method: HyperlinkSelectMethod,
1317 ) -> Self {
1318 self.hyperlink_text
1319 .push((target_text.to_string(), select_method));
1320 self
1321 }
1322}
1323
1324#[derive(Debug, Clone, PartialEq, PartialOrd)]
1326pub struct Text {
1327 pub discern_type: String,
1328 pub name: String,
1329 pub content: String,
1331 pub font_size: f32,
1333 pub color: [u8; 4],
1335 pub position: [f32; 2],
1337 pub center_display: (HorizontalAlign, VerticalAlign),
1339 pub offset: [f32; 2],
1341 pub wrap_width: f32,
1343 pub background_color: [u8; 4],
1345 pub background_rounding: f32,
1347 pub x_grid: [u32; 2],
1349 pub y_grid: [u32; 2],
1351 pub origin_position: [f32; 2],
1353 pub font: String,
1355 pub selection: Option<(usize, usize)>,
1357 pub selectable: bool,
1359 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1361 pub hyperlink_index: Vec<(usize, usize, String)>,
1363 pub last_frame_content: String,
1365 pub size: [f32; 2],
1367}
1368
1369impl RustConstructorResource for Text {
1370 fn name(&self) -> &str {
1371 &self.name
1372 }
1373
1374 fn expose_type(&self) -> &str {
1375 &self.discern_type
1376 }
1377
1378 fn as_any(&self) -> &dyn Any {
1379 self
1380 }
1381
1382 fn as_any_mut(&mut self) -> &mut dyn Any {
1383 self
1384 }
1385}
1386
1387impl BasicFrontResource for Text {
1388 fn position(&self) -> [f32; 2] {
1389 self.position
1390 }
1391
1392 fn size(&self) -> [f32; 2] {
1393 self.size
1394 }
1395
1396 fn modify_position(&mut self, x: f32, y: f32) {
1397 self.origin_position = [x, y];
1398 }
1399
1400 fn modify_size(&mut self, width: f32, height: f32) {
1401 self.wrap_width = width;
1402 self.size = [width, height];
1403 }
1404
1405 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
1406 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
1407 }
1408}
1409
1410impl Default for Text {
1411 fn default() -> Self {
1412 Self {
1413 discern_type: String::from("Text"),
1414 name: String::from("Text"),
1415 content: String::from("Hello world"),
1416 font_size: 16_f32,
1417 color: [255, 255, 255, 255],
1418 position: [0_f32, 0_f32],
1419 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1420 offset: [0_f32, 0_f32],
1421 wrap_width: 200_f32,
1422 background_color: [0, 0, 0, 0],
1423 background_rounding: 2_f32,
1424 x_grid: [0, 0],
1425 y_grid: [0, 0],
1426 origin_position: [0_f32, 0_f32],
1427 font: String::new(),
1428 selection: None,
1429 selectable: true,
1430 hyperlink_text: Vec::new(),
1431 hyperlink_index: Vec::new(),
1432 last_frame_content: String::from(""),
1433 size: [0_f32, 0_f32],
1434 }
1435 }
1436}
1437
1438impl Text {
1439 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1440 self.origin_position = position_config.origin_position;
1441 self.wrap_width = position_config.size[0];
1442 self.x_grid = position_config.x_grid;
1443 self.y_grid = position_config.y_grid;
1444 self.center_display = position_config.center_display;
1445 self.offset = position_config.offset;
1446 self.size = position_config.size;
1447 self
1448 }
1449
1450 pub fn from_config(mut self, config: TextConfig) -> Self {
1451 self.content = config.content;
1452 self.font_size = config.font_size;
1453 self.color = config.color;
1454 self.center_display = config.center_display;
1455 self.offset = config.offset;
1456 self.wrap_width = config.wrap_width;
1457 self.background_color = config.background_color;
1458 self.background_rounding = config.background_rounding;
1459 self.x_grid = config.x_grid;
1460 self.y_grid = config.y_grid;
1461 self.origin_position = config.origin_position;
1462 self.font = config.font;
1463 self.selectable = config.selectable;
1464 self.hyperlink_text = config.hyperlink_text;
1465 self.size = config.size;
1466 self
1467 }
1468
1469 #[inline]
1470 pub fn name(mut self, name: &str) -> Self {
1471 self.name = name.to_string();
1472 self
1473 }
1474
1475 #[inline]
1476 pub fn content(mut self, content: &str) -> Self {
1477 self.content = content.to_string();
1478 self
1479 }
1480
1481 #[inline]
1482 pub fn font_size(mut self, font_size: f32) -> Self {
1483 self.font_size = font_size;
1484 self
1485 }
1486
1487 #[inline]
1488 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1489 self.color = [r, g, b, a];
1490 self
1491 }
1492
1493 #[inline]
1494 pub fn center_display(
1495 mut self,
1496 horizontal_align: HorizontalAlign,
1497 vertical_align: VerticalAlign,
1498 ) -> Self {
1499 self.center_display = (horizontal_align, vertical_align);
1500 self
1501 }
1502
1503 #[inline]
1504 pub fn offset(mut self, x: f32, y: f32) -> Self {
1505 self.offset = [x, y];
1506 self
1507 }
1508
1509 #[inline]
1510 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1511 self.wrap_width = wrap_width;
1512 self
1513 }
1514
1515 #[inline]
1516 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1517 self.background_color = [r, g, b, a];
1518 self
1519 }
1520
1521 #[inline]
1522 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1523 self.background_rounding = background_rounding;
1524 self
1525 }
1526
1527 #[inline]
1528 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1529 self.x_grid = [fetch, total];
1530 self
1531 }
1532
1533 #[inline]
1534 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1535 self.y_grid = [fetch, total];
1536 self
1537 }
1538
1539 #[inline]
1540 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1541 self.origin_position = [x, y];
1542 self
1543 }
1544
1545 #[inline]
1546 pub fn font(mut self, font: &str) -> Self {
1547 self.font = font.to_string();
1548 self
1549 }
1550
1551 #[inline]
1552 pub fn selectable(mut self, selectable: bool) -> Self {
1553 self.selectable = selectable;
1554 self
1555 }
1556
1557 #[inline]
1558 pub fn hyperlink_text(
1559 mut self,
1560 target_text: &str,
1561 select_method: HyperlinkSelectMethod,
1562 ) -> Self {
1563 self.hyperlink_text
1564 .push((target_text.to_string(), select_method));
1565 self
1566 }
1567}
1568
1569#[derive(Debug, Clone, PartialEq, PartialOrd)]
1571pub struct Variable {
1572 pub discern_type: String,
1573 pub name: String,
1574 pub value: Value,
1576}
1577
1578impl RustConstructorResource for Variable {
1579 fn name(&self) -> &str {
1580 &self.name
1581 }
1582
1583 fn expose_type(&self) -> &str {
1584 &self.discern_type
1585 }
1586
1587 fn as_any(&self) -> &dyn Any {
1588 self
1589 }
1590
1591 fn as_any_mut(&mut self) -> &mut dyn Any {
1592 self
1593 }
1594}
1595
1596impl Default for Variable {
1597 fn default() -> Self {
1598 Variable {
1599 discern_type: String::from("Variable"),
1600 name: String::from("Variable"),
1601 value: Value::String(String::from("Hello world")),
1602 }
1603 }
1604}
1605
1606impl Variable {
1607 #[inline]
1608 pub fn name(mut self, name: &str) -> Self {
1609 self.name = name.to_string();
1610 self
1611 }
1612
1613 #[inline]
1614 pub fn value<T: Into<Value>>(mut self, value: T) -> Self {
1615 self.value = value.into();
1616 self
1617 }
1618
1619 pub fn new<T: Into<Value>>(name: &str, value: T) -> Self {
1620 Self {
1621 discern_type: String::from("Variable"),
1622 name: String::from(name),
1623 value: value.into(),
1624 }
1625 }
1626
1627 pub fn from_bool(name: &str, value: bool) -> Self {
1628 Self {
1629 discern_type: String::from("Variable"),
1630 name: String::from(name),
1631 value: Value::Bool(value),
1632 }
1633 }
1634
1635 pub fn from_int(name: &str, value: i32) -> Self {
1636 Self {
1637 discern_type: String::from("Variable"),
1638 name: String::from(name),
1639 value: Value::Int(value),
1640 }
1641 }
1642
1643 pub fn from_uint(name: &str, value: u32) -> Self {
1644 Self {
1645 discern_type: String::from("Variable"),
1646 name: String::from(name),
1647 value: Value::UInt(value),
1648 }
1649 }
1650
1651 pub fn from_float(name: &str, value: f32) -> Self {
1652 Self {
1653 discern_type: String::from("Variable"),
1654 name: String::from(name),
1655 value: Value::Float(value),
1656 }
1657 }
1658
1659 pub fn from_vec(name: &str, value: Vec<Value>) -> Self {
1660 Self {
1661 discern_type: String::from("Variable"),
1662 name: String::from(name),
1663 value: Value::Vec(value),
1664 }
1665 }
1666
1667 pub fn from_string<T: Into<String>>(name: &str, value: T) -> Self {
1668 Self {
1669 discern_type: String::from("Variable"),
1670 name: String::from(name),
1671 value: Value::String(value.into()),
1672 }
1673 }
1674}
1675
1676#[derive(Debug, Clone, PartialEq)]
1678pub struct Font {
1679 pub name: String,
1680 pub discern_type: String,
1681 pub font_definitions: FontDefinitions,
1683 pub path: String,
1685}
1686
1687impl RustConstructorResource for Font {
1688 fn name(&self) -> &str {
1689 &self.name
1690 }
1691
1692 fn expose_type(&self) -> &str {
1693 &self.discern_type
1694 }
1695
1696 fn as_any(&self) -> &dyn Any {
1697 self
1698 }
1699
1700 fn as_any_mut(&mut self) -> &mut dyn Any {
1701 self
1702 }
1703}
1704
1705impl Default for Font {
1706 fn default() -> Self {
1707 Self {
1708 discern_type: String::from("Font"),
1709 name: String::from("Font"),
1710 font_definitions: FontDefinitions::default(),
1711 path: String::from(""),
1712 }
1713 }
1714}
1715
1716impl Font {
1717 #[inline]
1718 pub fn name(mut self, name: &str) -> Self {
1719 self.name = name.to_string();
1720 self
1721 }
1722
1723 #[inline]
1724 pub fn path(mut self, path: &str) -> Self {
1725 self.path = path.to_string();
1726 self
1727 }
1728}
1729
1730#[derive(Debug, Clone, PartialEq, PartialOrd)]
1732pub struct SplitTime {
1733 pub discern_type: String,
1734 pub name: String,
1735 pub time: [f32; 2],
1737}
1738
1739impl RustConstructorResource for SplitTime {
1740 fn name(&self) -> &str {
1741 &self.name
1742 }
1743
1744 fn expose_type(&self) -> &str {
1745 &self.discern_type
1746 }
1747
1748 fn as_any(&self) -> &dyn Any {
1749 self
1750 }
1751
1752 fn as_any_mut(&mut self) -> &mut dyn Any {
1753 self
1754 }
1755}
1756
1757impl Default for SplitTime {
1758 fn default() -> Self {
1759 Self {
1760 discern_type: String::from("SplitTime"),
1761 name: String::from("SplitTime"),
1762 time: [0_f32, 0_f32],
1763 }
1764 }
1765}
1766
1767impl SplitTime {
1768 #[inline]
1769 pub fn name(mut self, name: &str) -> Self {
1770 self.name = name.to_string();
1771 self
1772 }
1773}
1774
1775#[derive(Debug, Clone, PartialEq, PartialOrd)]
1777pub struct SwitchAppearance {
1778 pub image_config: ImageConfig,
1780 pub custom_rect_config: CustomRectConfig,
1782 pub text_config: TextConfig,
1784 pub texture: String,
1786 pub hint_text: String,
1788}
1789
1790#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1792pub struct SwitchClickAction {
1793 pub click_method: PointerButton,
1795 pub action: bool,
1797}
1798
1799#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1801pub struct SwitchData {
1802 pub switched: bool,
1804 pub last_time_clicked_index: usize,
1806 pub state: u32,
1808}
1809
1810#[derive(Debug, Clone, PartialEq)]
1812pub struct Switch {
1813 pub discern_type: String,
1814 pub name: String,
1815 pub appearance: Vec<SwitchAppearance>,
1817 pub fill_resource_name: String,
1819 pub fill_resource_type: String,
1821 pub enable_hover_click_fill_resource: [bool; 2],
1823 pub state: u32,
1825 pub click_method: Vec<SwitchClickAction>,
1827 pub last_time_hovered: bool,
1829 pub last_time_clicked: bool,
1831 pub last_time_clicked_index: usize,
1833 pub animation_count: u32,
1835 pub hint_text_name: String,
1837 pub text_name: String,
1839 pub text_origin_position: [f32; 2],
1841 pub switched: bool,
1843}
1844
1845impl RustConstructorResource for Switch {
1846 fn name(&self) -> &str {
1847 &self.name
1848 }
1849
1850 fn expose_type(&self) -> &str {
1851 &self.discern_type
1852 }
1853
1854 fn as_any(&self) -> &dyn Any {
1855 self
1856 }
1857
1858 fn as_any_mut(&mut self) -> &mut dyn Any {
1859 self
1860 }
1861}
1862
1863impl Default for Switch {
1864 fn default() -> Self {
1865 Self {
1866 discern_type: String::from("Switch"),
1867 name: String::from("Switch"),
1868 appearance: vec![],
1869 fill_resource_name: String::from("FillResource"),
1870 fill_resource_type: String::from("Image"),
1871 enable_hover_click_fill_resource: [false, false],
1872 state: 0,
1873 click_method: vec![],
1874 last_time_hovered: false,
1875 last_time_clicked: false,
1876 last_time_clicked_index: 5,
1877 animation_count: 0,
1878 hint_text_name: String::from("HintText"),
1879 text_name: String::from("Text"),
1880 text_origin_position: [0_f32, 0_f32],
1881 switched: false,
1882 }
1883 }
1884}
1885
1886impl Switch {
1887 #[inline]
1888 pub fn name(mut self, name: &str) -> Self {
1889 self.name = name.to_string();
1890 self
1891 }
1892
1893 #[inline]
1894 pub fn appearance(mut self, appearance: Vec<SwitchAppearance>) -> Self {
1895 self.appearance = appearance;
1896 self
1897 }
1898
1899 #[inline]
1900 pub fn enable_hover_click_fill_resource(
1901 mut self,
1902 enable_hover_fill_resource: bool,
1903 enable_click_fill_resource: bool,
1904 ) -> Self {
1905 self.enable_hover_click_fill_resource =
1906 [enable_hover_fill_resource, enable_click_fill_resource];
1907 self
1908 }
1909
1910 #[inline]
1911 pub fn click_method(mut self, click_method: Vec<SwitchClickAction>) -> Self {
1912 self.click_method = click_method;
1913 self
1914 }
1915}
1916
1917#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1919pub struct RenderResource {
1920 pub discern_type: String,
1921 pub name: String,
1922}
1923
1924#[derive(Debug, Clone, PartialEq, PartialOrd)]
1926pub struct MessageBox {
1927 pub discern_type: String,
1928 pub name: String,
1929 pub size: [f32; 2],
1931 pub content_name: String,
1933 pub title_name: String,
1935 pub image_name: String,
1937 pub keep_existing: bool,
1939 pub existing_time: f32,
1941 pub exist: bool,
1943 pub speed: f32,
1945 pub restore_speed: f32,
1947 pub memory_offset: f32,
1949}
1950
1951impl RustConstructorResource for MessageBox {
1952 fn name(&self) -> &str {
1953 &self.name
1954 }
1955
1956 fn expose_type(&self) -> &str {
1957 &self.discern_type
1958 }
1959
1960 fn as_any(&self) -> &dyn Any {
1961 self
1962 }
1963
1964 fn as_any_mut(&mut self) -> &mut dyn Any {
1965 self
1966 }
1967}
1968
1969impl Default for MessageBox {
1970 fn default() -> Self {
1971 Self {
1972 discern_type: String::from("MessageBox"),
1973 name: String::from("MessageBox"),
1974 size: [100_f32, 100_f32],
1975 content_name: String::from("Content"),
1976 title_name: String::from("Title"),
1977 image_name: String::from("Image"),
1978 keep_existing: false,
1979 existing_time: 3_f32,
1980 exist: true,
1981 speed: 30_f32,
1982 restore_speed: 10_f32,
1983 memory_offset: 0_f32,
1984 }
1985 }
1986}
1987
1988impl MessageBox {
1989 #[inline]
1990 pub fn name(mut self, name: &str) -> Self {
1991 self.name = name.to_string();
1992 self
1993 }
1994
1995 #[inline]
1996 pub fn size(mut self, width: f32, height: f32) -> Self {
1997 self.size = [width, height];
1998 self
1999 }
2000
2001 #[inline]
2002 pub fn keep_existing(mut self, keep_existing: bool) -> Self {
2003 self.keep_existing = keep_existing;
2004 self
2005 }
2006
2007 #[inline]
2008 pub fn existing_time(mut self, existing_time: f32) -> Self {
2009 self.existing_time = existing_time;
2010 self
2011 }
2012
2013 #[inline]
2014 pub fn speed(mut self, speed: f32) -> Self {
2015 self.speed = speed;
2016 self
2017 }
2018
2019 #[inline]
2020 pub fn restore_speed(mut self, restore_speed: f32) -> Self {
2021 self.restore_speed = restore_speed;
2022 self
2023 }
2024}
2025
2026#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2028pub enum MouseDetectorLevel {
2029 Lite,
2031 #[default]
2033 Default,
2034 Pro,
2036}
2037
2038#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
2040pub struct MouseDetectResult {
2041 pub clicked: bool,
2043 pub contains_pointer: bool,
2045 pub secondary_clicked: Option<bool>,
2047 pub middle_clicked: Option<bool>,
2049 pub clicked_by_extra_button: Option<[bool; 2]>,
2051 pub long_touched: Option<bool>,
2053 pub double_clicked: Option<bool>,
2055 pub triple_clicked: Option<bool>,
2057 pub double_clicked_by: Option<[bool; 5]>,
2059 pub triple_clicked_by: Option<[bool; 5]>,
2061 pub clicked_elsewhere: Option<bool>,
2063 pub hovered: Option<bool>,
2065 pub drag_started: Option<bool>,
2067 pub drag_started_by: Option<[bool; 5]>,
2069 pub dragged: Option<bool>,
2071 pub dragged_by: Option<[bool; 5]>,
2073 pub drag_stopped: Option<bool>,
2075 pub deag_stopped_by: Option<[bool; 5]>,
2077 pub drag_delta: Option<[f32; 2]>,
2079 pub total_drag_delta: Option<Option<[f32; 2]>>,
2081 pub drag_motion: Option<[f32; 2]>,
2083 pub interact_pointer_pos: Option<Option<[f32; 2]>>,
2085 pub hover_pos: Option<Option<[f32; 2]>>,
2087 pub is_pointer_button_down_on: Option<bool>,
2089}
2090
2091#[derive(Debug, Clone, PartialEq, PartialOrd)]
2093pub struct MouseDetector {
2094 pub discern_type: String,
2095 pub name: String,
2096 pub position: [f32; 2],
2098 pub origin_position: [f32; 2],
2100 pub size: [f32; 2],
2102 pub x_grid: [u32; 2],
2104 pub y_grid: [u32; 2],
2106 pub center_display: (HorizontalAlign, VerticalAlign),
2108 pub offset: [f32; 2],
2110 pub detect_result: MouseDetectResult,
2112}
2113
2114impl RustConstructorResource for MouseDetector {
2115 fn name(&self) -> &str {
2116 &self.name
2117 }
2118
2119 fn expose_type(&self) -> &str {
2120 &self.discern_type
2121 }
2122
2123 fn as_any(&self) -> &dyn Any {
2124 self
2125 }
2126
2127 fn as_any_mut(&mut self) -> &mut dyn Any {
2128 self
2129 }
2130}
2131
2132impl Default for MouseDetector {
2133 fn default() -> Self {
2134 Self {
2135 discern_type: String::from("MouseDetector"),
2136 name: String::from("MouseDetector"),
2137 position: [0_f32, 0_f32],
2138 origin_position: [0_f32, 0_f32],
2139 size: [100_f32, 100_f32],
2140 x_grid: [0, 0],
2141 y_grid: [0, 0],
2142 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
2143 offset: [0_f32, 0_f32],
2144 detect_result: MouseDetectResult::default(),
2145 }
2146 }
2147}
2148
2149impl MouseDetector {
2150 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
2151 self.origin_position = position_config.origin_position;
2152 self.size = position_config.size;
2153 self.x_grid = position_config.x_grid;
2154 self.y_grid = position_config.y_grid;
2155 self.center_display = position_config.center_display;
2156 self.offset = position_config.offset;
2157 self
2158 }
2159
2160 #[inline]
2161 pub fn name(mut self, name: &str) -> Self {
2162 self.name = name.to_string();
2163 self
2164 }
2165
2166 #[inline]
2167 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
2168 self.origin_position = [x, y];
2169 self
2170 }
2171
2172 #[inline]
2173 pub fn size(mut self, width: f32, height: f32) -> Self {
2174 self.size = [width, height];
2175 self
2176 }
2177
2178 #[inline]
2179 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
2180 self.x_grid = [fetch, total];
2181 self
2182 }
2183
2184 #[inline]
2185 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
2186 self.y_grid = [fetch, total];
2187 self
2188 }
2189
2190 #[inline]
2191 pub fn center_display(
2192 mut self,
2193 horizontal_align: HorizontalAlign,
2194 vertical_align: VerticalAlign,
2195 ) -> Self {
2196 self.center_display = (horizontal_align, vertical_align);
2197 self
2198 }
2199
2200 #[inline]
2201 pub fn offset(mut self, x: f32, y: f32) -> Self {
2202 self.offset = [x, y];
2203 self
2204 }
2205}
2206
2207#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2209pub enum RustConstructorError {
2210 ImageGetFailed { image_path: String },
2212 ImageNotFound { image_name: String },
2214 ImageTextureNotFound { image_texture_name: String },
2216 TextNotFound { text_name: String },
2218 VariableNotFound { variable_name: String },
2220 VariableNotInt { variable_name: String },
2222 VariableNotUInt { variable_name: String },
2224 VariableNotFloat { variable_name: String },
2226 VariableNotVec { variable_name: String },
2228 VariableNotBool { variable_name: String },
2230 VariableNotString { variable_name: String },
2232 SplitTimeNotFound { split_time_name: String },
2234 SwitchAppearanceMismatch { switch_name: String, differ: u32 },
2236 SwitchFillResourceMismatch {
2238 switch_name: String,
2239 fill_resource_name: String,
2240 fill_resource_type: String,
2241 },
2242 SwitchNotFound { switch_name: String },
2244 MessageBoxAlreadyExists { message_box_name: String },
2246 MouseDetectorNotFound { mouse_detector_name: String },
2248 FontGetFailed { font_path: String },
2250 FontNotFound { font_name: String },
2252 RectNotFound { rect_name: String },
2254 ResourceNotFound {
2256 resource_name: String,
2257 resource_type: String,
2258 },
2259 PageNotFound { page_name: String },
2261 CustomError {
2263 error_name: String,
2264 error_message: String,
2265 error_annotation: String,
2266 },
2267}
2268
2269impl Display for RustConstructorError {
2270 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2271 Debug::fmt(self, f)
2272 }
2273}
2274
2275impl Error for RustConstructorError {}
2276
2277impl Default for RustConstructorError {
2278 fn default() -> Self {
2279 RustConstructorError::ImageGetFailed {
2280 image_path: "".to_string(),
2281 }
2282 }
2283}
2284
2285#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2287pub enum HorizontalAlign {
2288 #[default]
2290 Left,
2291 Center,
2293 Right,
2295}
2296
2297#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2299pub enum VerticalAlign {
2300 #[default]
2302 Top,
2303 Center,
2305 Bottom,
2307}
2308
2309#[derive(Debug)]
2311pub struct App {
2312 pub strict_mode: bool,
2314 pub safe_mode: bool,
2316 pub rust_constructor_resource: Vec<Box<dyn RustConstructorResource>>,
2318 pub render_resource_list: Vec<RenderResource>,
2320 pub problem_list: Vec<Problem>,
2322 pub tick_interval: f32,
2324 pub current_page: String,
2326 pub timer: Timer,
2328 pub frame_times: Vec<f32>,
2330 pub last_frame_time: Option<f64>,
2332}
2333
2334impl Default for App {
2335 fn default() -> Self {
2336 App {
2337 strict_mode: false,
2338 safe_mode: true,
2339 rust_constructor_resource: Vec::new(),
2340 render_resource_list: Vec::new(),
2341 problem_list: Vec::new(),
2342 tick_interval: 0.05,
2343 current_page: String::new(),
2344 timer: Timer::default(),
2345 frame_times: Vec::new(),
2346 last_frame_time: None,
2347 }
2348 }
2349}
2350
2351impl App {
2352 #[inline]
2353 pub fn strict_mode(mut self, strict_mode: bool) -> Self {
2354 self.strict_mode = strict_mode;
2355 self
2356 }
2357
2358 #[inline]
2359 pub fn safe_mode(mut self, safe_mode: bool) -> Self {
2360 self.safe_mode = safe_mode;
2361 self
2362 }
2363
2364 #[inline]
2365 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
2366 self.tick_interval = tick_interval;
2367 self
2368 }
2369
2370 #[inline]
2371 pub fn current_page(mut self, current_page: &str) -> Self {
2372 self.current_page = current_page.to_string();
2373 self
2374 }
2375
2376 pub fn page_handler(&mut self, ctx: &Context) {
2378 self.update_frame_stats(ctx);
2380 self.render_resource_list = Vec::new();
2382 self.update_timer();
2384 if let Ok(pd) = self.get_resource::<PageData>(&self.current_page.clone(), "PageData")
2385 && pd.forced_update
2386 {
2387 ctx.request_repaint();
2389 };
2390 }
2391
2392 pub fn add_page(&mut self, mut page_data: PageData) {
2394 page_data.change_page_updated = false;
2395 page_data.enter_page_updated = false;
2396 self.rust_constructor_resource.push(Box::new(page_data));
2397 }
2398
2399 pub fn switch_page(
2401 &mut self,
2402 name: &str,
2403 safe_mode: Option<bool>,
2404 ) -> Result<(), RustConstructorError> {
2405 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2406 && !self.check_resource_exists(name, "PageData")
2407 {
2408 self.problem_report_custom(
2409 RustConstructorError::PageNotFound {
2410 page_name: name.to_string(),
2411 },
2412 SeverityLevel::SevereWarning,
2413 self.problem_list.clone(),
2414 );
2415 return Err(RustConstructorError::PageNotFound {
2416 page_name: name.to_string(),
2417 });
2418 };
2419 self.current_page = name.to_string();
2420 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2421 pd.enter_page_updated = false;
2422 self.timer.start_time = self.timer.total_time;
2423 self.update_timer();
2424 Ok(())
2425 }
2426
2427 pub fn replace_resource_custom<T>(
2429 &self,
2430 name: &str,
2431 discern_type: &str,
2432 resource: T,
2433 mut target: Vec<Box<dyn RustConstructorResource>>,
2434 ) -> Result<(), RustConstructorError>
2435 where
2436 T: RustConstructorResource + 'static,
2437 {
2438 if let Some(index) = self
2439 .rust_constructor_resource
2440 .iter()
2441 .position(|x| x.name() == name && x.expose_type() == discern_type)
2442 {
2443 target[index] = Box::new(resource);
2444 Ok(())
2445 } else {
2446 self.problem_report_custom(
2447 RustConstructorError::ResourceNotFound {
2448 resource_name: name.to_string(),
2449 resource_type: discern_type.to_string(),
2450 },
2451 SeverityLevel::SevereWarning,
2452 self.problem_list.clone(),
2453 );
2454 Err(RustConstructorError::ResourceNotFound {
2455 resource_name: name.to_string(),
2456 resource_type: discern_type.to_string(),
2457 })
2458 }
2459 }
2460
2461 pub fn replace_resource<T>(
2463 &mut self,
2464 name: &str,
2465 discern_type: &str,
2466 resource: T,
2467 ) -> Result<(), RustConstructorError>
2468 where
2469 T: RustConstructorResource + 'static,
2470 {
2471 if let Some(index) = self
2472 .rust_constructor_resource
2473 .iter()
2474 .position(|x| x.name() == name && x.expose_type() == discern_type)
2475 {
2476 self.rust_constructor_resource[index] = Box::new(resource);
2477 Ok(())
2478 } else {
2479 self.problem_report_custom(
2480 RustConstructorError::ResourceNotFound {
2481 resource_name: name.to_string(),
2482 resource_type: discern_type.to_string(),
2483 },
2484 SeverityLevel::SevereWarning,
2485 self.problem_list.clone(),
2486 );
2487 Err(RustConstructorError::ResourceNotFound {
2488 resource_name: name.to_string(),
2489 resource_type: discern_type.to_string(),
2490 })
2491 }
2492 }
2493
2494 pub fn get_resource<T>(
2496 &self,
2497 name: &str,
2498 discern_type: &str,
2499 ) -> Result<&T, RustConstructorError>
2500 where
2501 T: RustConstructorResource + 'static,
2502 {
2503 if self.check_resource_exists(name, discern_type) {
2504 Ok(self
2505 .rust_constructor_resource
2506 .iter()
2507 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2508 .and_then(|resource| resource.as_any().downcast_ref::<T>())
2509 .unwrap())
2510 } else {
2511 self.problem_report_custom(
2512 RustConstructorError::ResourceNotFound {
2513 resource_name: name.to_string(),
2514 resource_type: discern_type.to_string(),
2515 },
2516 SeverityLevel::SevereWarning,
2517 self.problem_list.clone(),
2518 );
2519 Err(RustConstructorError::ResourceNotFound {
2520 resource_name: name.to_string(),
2521 resource_type: discern_type.to_string(),
2522 })
2523 }
2524 }
2525
2526 pub fn get_resource_mut<T>(
2528 &mut self,
2529 name: &str,
2530 discern_type: &str,
2531 ) -> Result<&mut T, RustConstructorError>
2532 where
2533 T: RustConstructorResource + 'static,
2534 {
2535 if self.check_resource_exists(name, discern_type) {
2536 Ok(self
2537 .rust_constructor_resource
2538 .iter_mut()
2539 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2540 .and_then(|resource| resource.as_any_mut().downcast_mut::<T>())
2541 .unwrap())
2542 } else {
2543 self.problem_report_custom(
2544 RustConstructorError::ResourceNotFound {
2545 resource_name: name.to_string(),
2546 resource_type: discern_type.to_string(),
2547 },
2548 SeverityLevel::SevereWarning,
2549 self.problem_list.clone(),
2550 );
2551 Err(RustConstructorError::ResourceNotFound {
2552 resource_name: name.to_string(),
2553 resource_type: discern_type.to_string(),
2554 })
2555 }
2556 }
2557
2558 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> bool {
2560 self.rust_constructor_resource
2561 .iter()
2562 .any(|x| x.name() == name && x.expose_type() == discern_type)
2563 }
2564
2565 pub fn add_fonts(&mut self, mut font: Font) -> Result<(), RustConstructorError> {
2567 let mut fonts = FontDefinitions::default();
2568 if let Ok(font_read_data) = read(font.path.clone()) {
2569 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
2570 fonts.font_data.insert(
2571 font.name.to_owned(),
2572 Arc::new(FontData::from_owned(
2573 Arc::try_unwrap(font_data).ok().unwrap(),
2574 )),
2575 );
2576
2577 fonts
2579 .families
2580 .entry(FontFamily::Proportional)
2581 .or_default()
2582 .insert(0, font.name.to_owned());
2583
2584 fonts
2585 .families
2586 .entry(FontFamily::Monospace)
2587 .or_default()
2588 .insert(0, font.name.to_owned());
2589
2590 font.font_definitions = fonts;
2591 self.rust_constructor_resource.push(Box::new(font));
2592 Ok(())
2593 } else {
2594 self.problem_report_custom(
2595 RustConstructorError::FontGetFailed {
2596 font_path: font.path.to_string(),
2597 },
2598 SeverityLevel::SevereWarning,
2599 self.problem_list.clone(),
2600 );
2601 Err(RustConstructorError::FontGetFailed {
2602 font_path: font.path.to_string(),
2603 })
2604 }
2605 }
2606
2607 pub fn font(
2609 &mut self,
2610 name: &str,
2611 safe_mode: Option<bool>,
2612 ) -> Result<FontDefinitions, RustConstructorError> {
2613 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2614 && !self.check_resource_exists(name, "Font")
2615 {
2616 self.problem_report_custom(
2617 RustConstructorError::FontNotFound {
2618 font_name: name.to_string(),
2619 },
2620 SeverityLevel::SevereWarning,
2621 self.problem_list.clone(),
2622 );
2623 return Err(RustConstructorError::FontNotFound {
2624 font_name: name.to_string(),
2625 });
2626 };
2627 let f = self.get_resource::<Font>(name, "Font").unwrap();
2628 Ok(f.font_definitions.clone())
2629 }
2630
2631 pub fn register_all_fonts(&mut self, ctx: &Context, safe_mode: Option<bool>) {
2633 let mut font_definitions = FontDefinitions::default();
2634 let mut font_resources = Vec::new();
2635 for i in 0..self.rust_constructor_resource.len() {
2636 if let Some(f) = self.rust_constructor_resource[i]
2637 .as_any()
2638 .downcast_ref::<Font>()
2639 {
2640 font_resources.push(f.clone());
2641 };
2642 }
2643 for i in &font_resources {
2644 let font_name = i.name.clone();
2645 if let Ok(font_def) = self.font(&font_name, safe_mode) {
2647 if let Some(font_data) = font_def.font_data.get(&font_name) {
2649 font_definitions
2650 .font_data
2651 .insert(font_name.clone(), Arc::clone(font_data));
2652 font_definitions
2653 .families
2654 .entry(FontFamily::Name(font_name.clone().into()))
2655 .or_default()
2656 .push(font_name.clone());
2657 };
2658
2659 font_definitions
2661 .families
2662 .entry(FontFamily::Proportional)
2663 .or_default()
2664 .insert(0, font_name.to_owned());
2665
2666 font_definitions
2667 .families
2668 .entry(FontFamily::Monospace)
2669 .or_default()
2670 .insert(0, font_name.to_owned());
2671 };
2672 }
2673 ctx.set_fonts(font_definitions);
2674 }
2675
2676 pub fn problem_report(
2678 &mut self,
2679 problem_type: RustConstructorError,
2680 severity_level: SeverityLevel,
2681 ) {
2682 let (problem, annotation) = match problem_type.clone() {
2683 RustConstructorError::FontGetFailed { font_path } => (
2684 format!("Font get failed: {}", font_path,),
2685 "Please check if the font file exists and the path is correct.".to_string(),
2686 ),
2687 RustConstructorError::FontNotFound { font_name } => (
2688 format!("Font not found: {}", font_name,),
2689 "Please check whether the font has been added.".to_string(),
2690 ),
2691 RustConstructorError::ImageGetFailed { image_path } => (
2692 format!("Image get failed: {}", image_path,),
2693 "Please check whether the image path is correct and whether the image has been added.".to_string(),
2694 ),
2695 RustConstructorError::ImageNotFound { image_name } => (
2696 format!("Image not found: {}", image_name,),
2697 "Please check whether the image has been added.".to_string(),
2698 ),
2699 RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2700 format!("Image texture not found: {}", image_texture_name,),
2701 "Please check whether the image texture has been added.".to_string(),
2702 ),
2703 RustConstructorError::TextNotFound { text_name } => (
2704 format!("Text not found: {}", text_name,),
2705 "Please check whether the text has been added.".to_string(),
2706 ),
2707 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2708 format!("Message box already exists: {}", message_box_name,),
2709 "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2710 ),
2711 RustConstructorError::MouseDetectorNotFound { mouse_detector_name } => (
2712 format!("Mouse detector not found: {}", mouse_detector_name,),
2713 "Please check whether the mouse detector has been added.".to_string(),
2714 ),
2715 RustConstructorError::SplitTimeNotFound { split_time_name } => (
2716 format!("Split time not found: {}", split_time_name,),
2717 "Please check whether the split time has been added.".to_string(),
2718 ),
2719 RustConstructorError::SwitchAppearanceMismatch {
2720 switch_name,
2721 differ,
2722 } => (
2723 format!(
2724 "Switch appearance list's number of items is large / small {} more: {}",
2725 differ, switch_name
2726 ),
2727 "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2728 ),
2729 RustConstructorError::SwitchNotFound { switch_name } => (
2730 format!("Switch not found: {}", switch_name,),
2731 "Please check whether the switch has been added.".to_string(),
2732 ),
2733 RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2734 format!("Switch fill resource mismatch: Resource {} of switch {} is not of type {}", fill_resource_name, switch_name, fill_resource_type,),
2735 "Please check whether the imported fill resource is correctly typed.".to_string(),
2736 ),
2737 RustConstructorError::PageNotFound { page_name } => (
2738 format!("Page not found: {}", page_name,),
2739 "Please check whether the page has been added.".to_string(),
2740 ),
2741 RustConstructorError::VariableNotFound { variable_name } => (
2742 format!("Variable not found: {}", variable_name,),
2743 "Please check whether the variable has been added.".to_string(),
2744 ),
2745 RustConstructorError::VariableNotBool { variable_name } => (
2746 format!("Variable is not bool: {}", variable_name,),
2747 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2748 ),
2749 RustConstructorError::VariableNotFloat { variable_name } => (
2750 format!("Variable is not f32: {}", variable_name,),
2751 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2752 ),
2753 RustConstructorError::VariableNotInt { variable_name } => (
2754 format!("Variable is not int: {}", variable_name,),
2755 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2756 ),
2757 RustConstructorError::VariableNotString { variable_name } => (
2758 format!("Variable is not string: {}", variable_name,),
2759 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2760 ),
2761 RustConstructorError::VariableNotUInt { variable_name } => (
2762 format!("Variable is not uint: {}", variable_name,),
2763 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2764 ),
2765 RustConstructorError::VariableNotVec { variable_name } => (
2766 format!("Variable is not vec: {}", variable_name,),
2767 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2768 ),
2769 RustConstructorError::RectNotFound { rect_name } => (
2770 format!("Rect not found: {}", rect_name,),
2771 "Please check whether the rect has been added.".to_string(),
2772 ),
2773 RustConstructorError::ResourceNotFound {
2774 resource_name,
2775 resource_type,
2776 } => (
2777 format!(
2778 "Resource not found: {}(\"{}\")",
2779 resource_type, resource_name,
2780 ),
2781 "Please check whether the resource has been added.".to_string(),
2782 ),
2783 RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2784 format!("Custom error({}): {}", error_name, error_message),
2785 error_annotation
2786 )
2787 };
2788 if self.strict_mode {
2790 panic!(
2791 "Rust Constructor Error({:#?}): {}\n{}",
2792 problem_type, problem, annotation
2793 );
2794 };
2795 self.problem_list.push(Problem {
2796 severity_level,
2797 problem,
2798 annotation,
2799 report_state: ReportState {
2800 current_page: self.current_page.clone(),
2801 current_total_runtime: self.timer.total_time,
2802 current_page_runtime: self.timer.now_time,
2803 },
2804 problem_type: problem_type.clone(),
2805 });
2806 }
2807
2808 pub fn problem_report_custom(
2810 &self,
2811 problem_type: RustConstructorError,
2812 severity_level: SeverityLevel,
2813 mut problem_storage: Vec<Problem>,
2814 ) {
2815 let (problem, annotation) = match problem_type.clone() {
2816 RustConstructorError::FontGetFailed { font_path } => (
2817 format!("Font get failed: {}", font_path,),
2818 "Please check if the font file exists and the path is correct.".to_string(),
2819 ),
2820 RustConstructorError::FontNotFound { font_name } => (
2821 format!("Font not found: {}", font_name,),
2822 "Please check whether the font has been added.".to_string(),
2823 ),
2824 RustConstructorError::ImageGetFailed { image_path } => (
2825 format!("Image get failed: {}", image_path,),
2826 "Please check whether the image path is correct and whether the image has been added.".to_string(),
2827 ),
2828 RustConstructorError::ImageNotFound { image_name } => (
2829 format!("Image not found: {}", image_name,),
2830 "Please check whether the image has been added.".to_string(),
2831 ),
2832 RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2833 format!("Image texture not found: {}", image_texture_name,),
2834 "Please check whether the image texture has been added.".to_string(),
2835 ),
2836 RustConstructorError::TextNotFound { text_name } => (
2837 format!("Text not found: {}", text_name,),
2838 "Please check whether the text has been added.".to_string(),
2839 ),
2840 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2841 format!("Message box already exists: {}", message_box_name,),
2842 "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2843 ),
2844 RustConstructorError::MouseDetectorNotFound { mouse_detector_name } => (
2845 format!("Mouse detector not found: {}", mouse_detector_name,),
2846 "Please check whether the mouse detector has been added.".to_string(),
2847 ),
2848 RustConstructorError::SplitTimeNotFound { split_time_name } => (
2849 format!("Split time not found: {}", split_time_name,),
2850 "Please check whether the split time has been added.".to_string(),
2851 ),
2852 RustConstructorError::SwitchAppearanceMismatch {
2853 switch_name,
2854 differ,
2855 } => (
2856 format!(
2857 "Switch appearance list's number of items is large / small {} more: {}",
2858 differ, switch_name
2859 ),
2860 "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2861 ),
2862 RustConstructorError::SwitchNotFound { switch_name } => (
2863 format!("Switch not found: {}", switch_name,),
2864 "Please check whether the switch has been added.".to_string(),
2865 ),
2866 RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2867 format!("Switch fill resource mismatch: Resource {} of switch {} is not of type {}", fill_resource_name, switch_name, fill_resource_type,),
2868 "Please check whether the imported fill resource is correctly typed.".to_string(),
2869 ),
2870 RustConstructorError::PageNotFound { page_name } => (
2871 format!("Page not found: {}", page_name,),
2872 "Please check whether the page has been added.".to_string(),
2873 ),
2874 RustConstructorError::VariableNotFound { variable_name } => (
2875 format!("Variable not found: {}", variable_name,),
2876 "Please check whether the variable has been added.".to_string(),
2877 ),
2878 RustConstructorError::VariableNotBool { variable_name } => (
2879 format!("Variable is not bool: {}", variable_name,),
2880 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2881 ),
2882 RustConstructorError::VariableNotFloat { variable_name } => (
2883 format!("Variable is not f32: {}", variable_name,),
2884 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2885 ),
2886 RustConstructorError::VariableNotInt { variable_name } => (
2887 format!("Variable is not int: {}", variable_name,),
2888 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2889 ),
2890 RustConstructorError::VariableNotString { variable_name } => (
2891 format!("Variable is not string: {}", variable_name,),
2892 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2893 ),
2894 RustConstructorError::VariableNotUInt { variable_name } => (
2895 format!("Variable is not uint: {}", variable_name,),
2896 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2897 ),
2898 RustConstructorError::VariableNotVec { variable_name } => (
2899 format!("Variable is not vec: {}", variable_name,),
2900 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2901 ),
2902 RustConstructorError::RectNotFound { rect_name } => (
2903 format!("Rect not found: {}", rect_name,),
2904 "Please check whether the rect has been added.".to_string(),
2905 ),
2906 RustConstructorError::ResourceNotFound {
2907 resource_name,
2908 resource_type,
2909 } => (
2910 format!(
2911 "Resource not found: {}(\"{}\")",
2912 resource_type, resource_name,
2913 ),
2914 "Please check whether the resource has been added.".to_string(),
2915 ),
2916 RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2917 format!("Custom error({}): {}", error_name, error_message),
2918 error_annotation
2919 )
2920 };
2921 if self.strict_mode {
2923 panic!(
2924 "Rust Constructor Error({:#?}): {}\n{}",
2925 problem_type, problem, annotation
2926 );
2927 };
2928 problem_storage.push(Problem {
2929 severity_level,
2930 problem,
2931 annotation,
2932 report_state: ReportState {
2933 current_page: self.current_page.clone(),
2934 current_total_runtime: self.timer.total_time,
2935 current_page_runtime: self.timer.now_time,
2936 },
2937 problem_type: problem_type.clone(),
2938 });
2939 }
2940
2941 pub fn check_updated(
2943 &mut self,
2944 name: &str,
2945 safe_mode: Option<bool>,
2946 ) -> Result<bool, RustConstructorError> {
2947 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2948 && !self.check_resource_exists(name, "PageData")
2949 {
2950 self.problem_report_custom(
2951 RustConstructorError::PageNotFound {
2952 page_name: name.to_string(),
2953 },
2954 SeverityLevel::SevereWarning,
2955 self.problem_list.clone(),
2956 );
2957 return Err(RustConstructorError::PageNotFound {
2958 page_name: name.to_string(),
2959 });
2960 };
2961 let pd = self
2962 .get_resource::<PageData>(name, "PageData")
2963 .unwrap()
2964 .clone();
2965 if !pd.change_page_updated {
2966 self.new_page_update(name, safe_mode).unwrap();
2967 };
2968 Ok(pd.change_page_updated)
2969 }
2970
2971 pub fn check_enter_updated(
2973 &mut self,
2974 name: &str,
2975 safe_mode: Option<bool>,
2976 ) -> Result<bool, RustConstructorError> {
2977 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2978 && !self.check_resource_exists(name, "PageData")
2979 {
2980 self.problem_report_custom(
2981 RustConstructorError::PageNotFound {
2982 page_name: name.to_string(),
2983 },
2984 SeverityLevel::SevereWarning,
2985 self.problem_list.clone(),
2986 );
2987 return Err(RustConstructorError::PageNotFound {
2988 page_name: name.to_string(),
2989 });
2990 };
2991 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2992 let return_value = pd.enter_page_updated;
2993 pd.enter_page_updated = true;
2994 Ok(return_value)
2995 }
2996
2997 pub fn new_page_update(
2999 &mut self,
3000 name: &str,
3001 safe_mode: Option<bool>,
3002 ) -> Result<(), RustConstructorError> {
3003 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3004 && !self.check_resource_exists(name, "PageData")
3005 {
3006 self.problem_report_custom(
3007 RustConstructorError::PageNotFound {
3008 page_name: name.to_string(),
3009 },
3010 SeverityLevel::SevereWarning,
3011 self.problem_list.clone(),
3012 );
3013 return Err(RustConstructorError::PageNotFound {
3014 page_name: name.to_string(),
3015 });
3016 }
3017 self.timer.start_time = self.timer.total_time;
3018 self.update_timer();
3019 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
3020 pd.change_page_updated = true;
3021 Ok(())
3022 }
3023
3024 pub fn update_frame_stats(&mut self, ctx: &Context) {
3026 let current_time = ctx.input(|i| i.time);
3027 if let Some(last) = self.last_frame_time {
3028 let delta = (current_time - last) as f32;
3029 self.frame_times.push(delta);
3030 const MAX_SAMPLES: usize = 120;
3031 if self.frame_times.len() > MAX_SAMPLES {
3032 let remove_count = self.frame_times.len() - MAX_SAMPLES;
3033 self.frame_times.drain(0..remove_count);
3034 }
3035 }
3036 self.last_frame_time = Some(current_time);
3037 }
3038
3039 pub fn current_fps(&self) -> f32 {
3041 if self.frame_times.is_empty() {
3042 0.0
3043 } else {
3044 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
3045 }
3046 }
3047
3048 pub fn add_split_time(&mut self, mut split_time: SplitTime) {
3050 split_time.time = [self.timer.now_time, self.timer.total_time];
3051 self.rust_constructor_resource.push(Box::new(split_time));
3052 }
3053
3054 pub fn reset_split_time(
3056 &mut self,
3057 name: &str,
3058 safe_mode: Option<bool>,
3059 ) -> Result<(), RustConstructorError> {
3060 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3061 && !self.check_resource_exists(name, "SplitTime")
3062 {
3063 self.problem_report_custom(
3064 RustConstructorError::SplitTimeNotFound {
3065 split_time_name: name.to_string(),
3066 },
3067 SeverityLevel::SevereWarning,
3068 self.problem_list.clone(),
3069 );
3070 return Err(RustConstructorError::SplitTimeNotFound {
3071 split_time_name: name.to_string(),
3072 });
3073 };
3074 let new_time = [self.timer.now_time, self.timer.total_time];
3075 let st = self
3076 .get_resource_mut::<SplitTime>(name, "SplitTime")
3077 .unwrap();
3078 st.time = new_time;
3079 Ok(())
3080 }
3081
3082 pub fn split_time(
3084 &self,
3085 name: &str,
3086 safe_mode: Option<bool>,
3087 ) -> Result<[f32; 2], RustConstructorError> {
3088 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3089 && !self.check_resource_exists(name, "SplitTime")
3090 {
3091 self.problem_report_custom(
3092 RustConstructorError::SplitTimeNotFound {
3093 split_time_name: name.to_string(),
3094 },
3095 SeverityLevel::SevereWarning,
3096 self.problem_list.clone(),
3097 );
3098 return Err(RustConstructorError::SplitTimeNotFound {
3099 split_time_name: name.to_string(),
3100 });
3101 };
3102 let st = self.get_resource::<SplitTime>(name, "SplitTime").unwrap();
3103 Ok(st.time)
3104 }
3105
3106 pub fn update_timer(&mut self) {
3108 let elapsed = self.timer.timer.elapsed();
3109 let seconds = elapsed.as_secs();
3110 let milliseconds = elapsed.subsec_millis();
3111 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
3112 self.timer.now_time = self.timer.total_time - self.timer.start_time
3113 }
3114
3115 pub fn add_custom_rect(&mut self, custom_rect: CustomRect) {
3117 self.rust_constructor_resource.push(Box::new(custom_rect));
3118 }
3119
3120 pub fn custom_rect(
3122 &mut self,
3123 name: &str,
3124 ui: &mut Ui,
3125 ctx: &Context,
3126 safe_mode: Option<bool>,
3127 ) -> Result<(), RustConstructorError> {
3128 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3129 && !self.check_resource_exists(name, "CustomRect")
3130 {
3131 self.problem_report_custom(
3132 RustConstructorError::RectNotFound {
3133 rect_name: name.to_string(),
3134 },
3135 SeverityLevel::SevereWarning,
3136 self.problem_list.clone(),
3137 );
3138 return Err(RustConstructorError::RectNotFound {
3139 rect_name: name.to_string(),
3140 });
3141 };
3142 let render_resource_list = &mut self.render_resource_list.clone();
3143 let cr = self
3144 .get_resource_mut::<CustomRect>(name, "CustomRect")
3145 .unwrap();
3146 cr.reg_render_resource(render_resource_list);
3147 cr.position[0] = match cr.x_grid[1] {
3148 0 => cr.origin_position[0],
3149 _ => {
3150 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64 * cr.x_grid[0] as f64)
3151 as f32
3152 + cr.origin_position[0]
3153 }
3154 };
3155 cr.position[1] = match cr.y_grid[1] {
3156 0 => cr.origin_position[1],
3157 _ => {
3158 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64 * cr.y_grid[0] as f64)
3159 as f32
3160 + cr.origin_position[1]
3161 }
3162 };
3163 match cr.center_display.0 {
3164 HorizontalAlign::Left => {}
3165 HorizontalAlign::Center => cr.position[0] -= cr.size[0] / 2.0,
3166 HorizontalAlign::Right => cr.position[0] -= cr.size[0],
3167 };
3168 match cr.center_display.1 {
3169 VerticalAlign::Top => {}
3170 VerticalAlign::Center => cr.position[1] -= cr.size[1] / 2.0,
3171 VerticalAlign::Bottom => cr.position[1] -= cr.size[1],
3172 };
3173 cr.position[0] += cr.offset[0];
3174 cr.position[1] += cr.offset[1];
3175 ui.painter().rect(
3176 Rect::from_min_max(
3177 Pos2::new(cr.position[0], cr.position[1]),
3178 Pos2::new(cr.position[0] + cr.size[0], cr.position[1] + cr.size[1]),
3179 ),
3180 cr.rounding,
3181 Color32::from_rgba_unmultiplied(cr.color[0], cr.color[1], cr.color[2], cr.color[3]),
3182 Stroke {
3183 width: cr.border_width,
3184 color: Color32::from_rgba_unmultiplied(
3185 cr.border_color[0],
3186 cr.border_color[1],
3187 cr.border_color[2],
3188 cr.border_color[3],
3189 ),
3190 },
3191 StrokeKind::Inside,
3192 );
3193 Ok(())
3194 }
3195
3196 pub fn add_text(&mut self, text: Text) {
3198 self.rust_constructor_resource.push(Box::new(text));
3199 }
3200
3201 pub fn text(
3203 &mut self,
3204 name: &str,
3205 ui: &mut Ui,
3206 ctx: &Context,
3207 safe_mode: Option<bool>,
3208 ) -> Result<(), RustConstructorError> {
3209 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3210 && !self.check_resource_exists(name, "Text")
3211 {
3212 self.problem_report_custom(
3213 RustConstructorError::TextNotFound {
3214 text_name: name.to_string(),
3215 },
3216 SeverityLevel::SevereWarning,
3217 self.problem_list.clone(),
3218 );
3219 return Err(RustConstructorError::TextNotFound {
3220 text_name: name.to_string(),
3221 });
3222 };
3223 let mut t = self.get_resource::<Text>(name, "Text").unwrap().clone();
3224 t.reg_render_resource(&mut self.render_resource_list);
3225 let galley: Arc<Galley> = ui.fonts_mut(|f| {
3227 f.layout(
3228 t.content.to_string(),
3229 if !t.font.is_empty() {
3230 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3231 && !self.check_resource_exists(&t.font.clone(), "Font")
3232 {
3233 self.problem_report_custom(
3234 RustConstructorError::FontNotFound {
3235 font_name: t.font.clone(),
3236 },
3237 SeverityLevel::MildWarning,
3238 self.problem_list.clone(),
3239 );
3240 FontId::new(t.font_size, FontFamily::Name(t.font.clone().into()))
3241 } else {
3242 FontId::proportional(t.font_size)
3243 }
3244 } else {
3245 FontId::proportional(t.font_size)
3246 },
3247 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]),
3248 t.wrap_width,
3249 )
3250 });
3251 t.size = [galley.size().x, galley.size().y];
3252 t.position[0] = match t.x_grid[1] {
3253 0 => t.origin_position[0],
3254 _ => {
3255 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64 * t.x_grid[0] as f64)
3256 as f32
3257 + t.origin_position[0]
3258 }
3259 };
3260 t.position[1] = match t.y_grid[1] {
3261 0 => t.origin_position[1],
3262 _ => {
3263 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64 * t.y_grid[0] as f64)
3264 as f32
3265 + t.origin_position[1]
3266 }
3267 };
3268 let pos_x = match t.center_display.0 {
3269 HorizontalAlign::Left => t.position[0],
3270 HorizontalAlign::Center => t.position[0] - t.size[0] / 2.0,
3271 HorizontalAlign::Right => t.position[0] - t.size[0],
3272 };
3273 let pos_y = match t.center_display.1 {
3274 VerticalAlign::Top => t.position[1],
3275 VerticalAlign::Center => t.position[1] - t.size[1] / 2.0,
3276 VerticalAlign::Bottom => t.position[1] - t.size[1],
3277 };
3278 t.position[0] += t.offset[0];
3279 t.position[1] += t.offset[1];
3280 let position = Pos2::new(pos_x, pos_y);
3282
3283 let rect = Rect::from_min_size(position, t.size.into());
3284 ui.painter().rect_filled(
3286 rect,
3287 t.background_rounding,
3288 Color32::from_rgba_unmultiplied(
3289 t.background_color[0],
3290 t.background_color[1],
3291 t.background_color[2],
3292 t.background_color[3],
3293 ),
3294 ); ui.painter().galley(
3297 position,
3298 galley.clone(),
3299 Color32::from_rgba_unmultiplied(
3300 t.color[0], t.color[1], t.color[2], t.color[3], ),
3302 );
3303
3304 if t.last_frame_content != t.content {
3306 t.hyperlink_index.clear();
3307
3308 let byte_to_char_map: std::collections::HashMap<usize, usize> = t
3310 .content
3311 .char_indices()
3312 .enumerate()
3313 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
3314 .collect();
3315
3316 for (text, method) in &t.hyperlink_text {
3317 let matches: Vec<(usize, &str)> = t.content.match_indices(text).collect();
3318 let text_char_count = text.chars().count();
3319
3320 if let HyperlinkSelectMethod::All(url) = method {
3321 for (byte_index, _) in matches {
3322 if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3323 t.hyperlink_index.push((
3324 start_char_index,
3325 start_char_index + text_char_count,
3326 url.clone(),
3327 ));
3328 };
3329 }
3330 } else if let HyperlinkSelectMethod::Segment(list) = method {
3331 for (index, url) in list {
3332 if *index >= matches.len() {
3333 continue;
3334 };
3335 let (byte_index, _) = matches[*index];
3336 if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3337 t.hyperlink_index.push((
3338 start_char_index,
3339 start_char_index + text_char_count,
3340 url.clone(),
3341 ));
3342 };
3343 }
3344 };
3345 }
3346 };
3347
3348 for (start, end, _) in &t.hyperlink_index {
3350 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3352 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3353
3354 let start_pos = start_cursor.left_top();
3355 let end_pos = end_cursor.right_top();
3356 if start_cursor.min.y == end_cursor.min.y {
3359 let underline_y =
3361 position.y + start_pos.y + galley.rows.first().map_or(14.0, |row| row.height())
3362 - 2.0;
3363
3364 let color =
3366 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]);
3367
3368 ui.painter().line_segment(
3369 [
3370 Pos2::new(position.x + start_pos.x, underline_y),
3371 Pos2::new(position.x + end_pos.x, underline_y),
3372 ],
3373 Stroke::new(t.font_size / 10_f32, color),
3374 );
3375 } else {
3376 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
3381 let end_row = (end_pos.y / row_height).round() as usize;
3382
3383 for row in start_row..=end_row {
3384 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
3388 let row_rect = current_row.rect();
3389
3390 let color = Color32::from_rgba_unmultiplied(
3391 t.color[0], t.color[1], t.color[2], t.color[3],
3392 );
3393
3394 if row == start_row {
3395 ui.painter().line_segment(
3397 [
3398 Pos2::new(position.x + start_pos.x, row_y),
3399 Pos2::new(position.x + row_rect.max.x, row_y),
3400 ],
3401 Stroke::new(t.font_size / 10_f32, color),
3402 );
3403 } else if row == end_row {
3404 ui.painter().line_segment(
3406 [
3407 Pos2::new(position.x + row_rect.min.x, row_y),
3408 Pos2::new(position.x + end_pos.x, row_y),
3409 ],
3410 Stroke::new(t.font_size / 10_f32, color),
3411 );
3412 } else {
3413 ui.painter().line_segment(
3415 [
3416 Pos2::new(position.x + row_rect.min.x, row_y),
3417 Pos2::new(position.x + row_rect.max.x, row_y),
3418 ],
3419 Stroke::new(t.font_size / 10_f32, color),
3420 );
3421 };
3422 };
3423 }
3424 };
3425 }
3426
3427 if t.selectable {
3428 if !self.check_resource_exists(&t.name, "MouseDetector") {
3429 self.add_mouse_detector(
3430 MouseDetector::default()
3431 .name(&t.name)
3432 .from_position_config(PositionConfig::from_text(t.clone()))
3433 .offset(-20_f32, -5_f32)
3434 .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3435 );
3436 } else {
3437 self.replace_resource(
3438 &t.name,
3439 "MouseDetector",
3440 MouseDetector::default()
3441 .name(&t.name)
3442 .from_position_config(PositionConfig::from_text(t.clone()))
3443 .offset(-20_f32, -5_f32)
3444 .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3445 )
3446 .unwrap();
3447 };
3448
3449 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
3451 let relative_pos = pointer_pos - position.to_vec2();
3452 let cursor = galley.cursor_from_pos(relative_pos);
3453 cursor.index
3454 };
3455
3456 self.mouse_detector(&t.name, ui, ctx, MouseDetectorLevel::Default, safe_mode)
3457 .unwrap();
3458 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
3459 let detect_result = self.check_mouse_detect_result(&t.name, safe_mode).unwrap();
3460 if !detect_result.clicked
3461 && (fullscreen_detect_result.any_click() || fullscreen_detect_result.any_pressed())
3462 {
3463 t.selection = None;
3464 };
3465
3466 if (detect_result.clicked || detect_result.drag_started.unwrap())
3467 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3468 {
3469 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3470 t.selection = Some((cursor, cursor));
3471 };
3472
3473 if detect_result.dragged.unwrap()
3474 && t.selection.is_some()
3475 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3476 {
3477 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3478 if let Some((start, _)) = t.selection {
3479 t.selection = Some((start, cursor));
3480 };
3481 };
3482
3483 if t.selection.is_some()
3484 && ui.input(|input| input.key_released(Key::A) && input.modifiers.command)
3485 {
3486 t.selection = Some((0, t.content.chars().count()));
3487 };
3488
3489 let copy_triggered = ui.input(|input| {
3491 let c_released = input.key_released(Key::C);
3492 let cmd_pressed = input.modifiers.command;
3493 c_released && cmd_pressed
3494 });
3495 if copy_triggered && let Some((start, end)) = t.selection {
3496 let (start, end) = (start.min(end), start.max(end));
3497 let chars: Vec<char> = t.content.chars().collect();
3498 if start <= chars.len() && end <= chars.len() && start < end {
3499 let selected_text: String = chars[start..end].iter().collect();
3500 ui.ctx().copy_text(selected_text);
3501 };
3502 };
3503
3504 if let Some((start, end)) = t.selection {
3506 let (start, end) = (start.min(end), start.max(end));
3507 if start != end {
3508 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
3510 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3511
3512 let start_pos = start_cursor.left_top();
3513 let end_pos = end_cursor.right_top();
3514 if start_pos.y == end_pos.y {
3516 let rows = &galley.rows;
3518 let row_height = if !rows.is_empty() {
3519 if let Some(row) = rows.first() {
3521 row.height()
3522 } else {
3523 t.size[1] / t.content.lines().count() as f32
3524 }
3525 } else {
3526 t.size[1] / t.content.lines().count() as f32
3527 };
3528
3529 let selection_rect = Rect::from_min_max(
3530 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3531 Pos2::new(
3532 position.x + end_pos.x,
3533 position.y + start_pos.y + row_height,
3534 ),
3535 );
3536 ui.painter().rect_filled(
3537 selection_rect,
3538 0.0,
3539 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3540 );
3541 } else {
3542 let rows = &galley.rows;
3544 let row_height = if !rows.is_empty() {
3545 rows[0].height()
3546 } else {
3547 t.size[1] / t.content.lines().count() as f32
3548 };
3549
3550 let selection_top = position.y + start_pos.y.min(end_pos.y);
3552 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
3553
3554 let start_row_index = (start_pos.y / row_height).floor() as usize;
3556 let end_row_index = (end_pos.y / row_height).floor() as usize;
3557 let (first_row_index, last_row_index) = if start_row_index <= end_row_index
3558 {
3559 (start_row_index, end_row_index)
3560 } else {
3561 (end_row_index, start_row_index)
3562 };
3563
3564 for (i, row) in rows.iter().enumerate() {
3565 let row_y = position.y + row_height * i as f32;
3566 let row_bottom = row_y + row_height;
3567 if row_bottom > selection_top && row_y <= selection_bottom {
3569 let left = if i == first_row_index {
3570 position.x + start_pos.x
3572 } else {
3573 position.x + row.rect().min.x
3575 };
3576
3577 let right = if i == last_row_index {
3578 position.x + end_pos.x
3580 } else {
3581 position.x + row.rect().max.x
3583 };
3584
3585 let selection_rect = Rect::from_min_max(
3586 Pos2::new(left, row_y),
3587 Pos2::new(right, row_bottom),
3588 );
3589
3590 if selection_rect.width() > 0.0 && selection_rect.height() > 0.0 {
3592 ui.painter().rect_filled(
3593 selection_rect,
3594 0.0,
3595 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3596 );
3597 };
3598 };
3599 }
3600 };
3601 };
3602 };
3603 };
3604
3605 for (start, end, url) in &t.hyperlink_index {
3607 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3609 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3610
3611 let start_pos = start_cursor.left_top();
3612 let end_pos = end_cursor.right_top();
3613
3614 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3615
3616 let link_responses = if start_cursor.min.y == end_cursor.min.y {
3618 let link_rect = Rect::from_min_max(
3620 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3621 Pos2::new(
3622 position.x + end_pos.x,
3623 position.y + start_pos.y + row_height,
3624 ),
3625 );
3626 vec![ui.interact(
3627 link_rect,
3628 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
3629 egui::Sense::click(),
3630 )]
3631 } else {
3632 let start_row = (start_pos.y / row_height).round() as usize;
3634 let end_row = (end_pos.y / row_height).round() as usize;
3635 let mut responses = Vec::new();
3636
3637 for row in start_row..=end_row {
3638 if let Some(current_row) = galley.rows.get(row) {
3639 let row_rect = current_row.rect();
3640 let row_y = position.y + row as f32 * row_height;
3641
3642 let link_rect = if row == start_row {
3643 Rect::from_min_max(
3645 Pos2::new(position.x + start_pos.x, row_y),
3646 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3647 )
3648 } else if row == end_row {
3649 Rect::from_min_max(
3651 Pos2::new(position.x + row_rect.min.x, row_y),
3652 Pos2::new(position.x + end_pos.x, row_y + row_height),
3653 )
3654 } else {
3655 Rect::from_min_max(
3657 Pos2::new(position.x + row_rect.min.x, row_y),
3658 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3659 )
3660 };
3661
3662 responses.push(ui.interact(
3663 link_rect,
3664 Id::new(format!("link_{}_{}_{}_row_{}", t.name, start, end, row)),
3665 Sense::click(),
3666 ));
3667 };
3668 }
3669 responses
3670 };
3671
3672 let mut is_pressing_link = false;
3674 for link_response in &link_responses {
3675 if link_response.is_pointer_button_down_on() && !link_response.drag_started() {
3676 t.selection = None;
3677 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
3678 let relative_pos = pointer_pos - position.to_vec2();
3679 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3680 if cursor.index >= *start && cursor.index <= *end {
3681 is_pressing_link = true;
3682 break;
3683 };
3684 };
3685 };
3686 }
3687
3688 let mut clicked_on_link = false;
3690 for link_response in &link_responses {
3691 if link_response.clicked()
3692 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3693 {
3694 let relative_pos = pointer_pos - position.to_vec2();
3695 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3696 if cursor.index >= *start && cursor.index <= *end {
3697 clicked_on_link = true;
3698 break;
3699 };
3700 };
3701 }
3702
3703 if clicked_on_link {
3704 if !url.is_empty() {
3706 ui.ctx().open_url(OpenUrl::new_tab(url));
3707 };
3708 };
3709
3710 if is_pressing_link {
3712 if start_cursor.min.y == end_cursor.min.y {
3713 let selection_rect = Rect::from_min_max(
3715 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3716 Pos2::new(
3717 position.x + end_pos.x,
3718 position.y
3719 + start_pos.y
3720 + galley.rows.first().map_or(14.0, |row| row.height()),
3721 ),
3722 );
3723 ui.painter().rect_filled(
3724 selection_rect,
3725 0.0,
3726 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3727 );
3728 } else {
3729 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3731 let start_row = (start_pos.y / row_height).round() as usize;
3732 let end_row = (end_pos.y / row_height).round() as usize;
3733
3734 for row in start_row..=end_row {
3735 if let Some(current_row) = galley.rows.get(row) {
3736 let row_rect = current_row.rect();
3737
3738 if row == start_row {
3739 let selection_rect = Rect::from_min_max(
3741 Pos2::new(
3742 position.x + start_pos.x,
3743 position.y + row as f32 * row_height,
3744 ),
3745 Pos2::new(
3746 position.x + row_rect.max.x,
3747 position.y + row as f32 * row_height + row_height,
3748 ),
3749 );
3750 ui.painter().rect_filled(
3751 selection_rect,
3752 0.0,
3753 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3754 );
3755 } else if row == end_row {
3756 let selection_rect = Rect::from_min_max(
3758 Pos2::new(
3759 position.x + row_rect.min.x,
3760 position.y + row as f32 * row_height,
3761 ),
3762 Pos2::new(
3763 position.x + end_pos.x,
3764 position.y + row as f32 * row_height + row_height,
3765 ),
3766 );
3767 ui.painter().rect_filled(
3768 selection_rect,
3769 0.0,
3770 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3771 );
3772 } else {
3773 let selection_rect = Rect::from_min_max(
3775 Pos2::new(
3776 position.x + row_rect.min.x,
3777 position.y + row as f32 * row_height,
3778 ),
3779 Pos2::new(
3780 position.x + row_rect.max.x,
3781 position.y + row as f32 * row_height + row_height,
3782 ),
3783 );
3784 ui.painter().rect_filled(
3785 selection_rect,
3786 0.0,
3787 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3788 );
3789 };
3790 };
3791 }
3792 };
3793 };
3794 }
3795 t.last_frame_content = t.content.clone();
3796 self.replace_resource(name, "Text", t).unwrap();
3797 Ok(())
3798 }
3799
3800 pub fn add_var(&mut self, variable: Variable) {
3802 self.rust_constructor_resource.push(Box::new(variable));
3803 }
3804
3805 pub fn modify_var<T: Into<Value>>(
3807 &mut self,
3808 name: &str,
3809 value: T,
3810 safe_mode: Option<bool>,
3811 ) -> Result<(), RustConstructorError> {
3812 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3813 && !self.check_resource_exists(name, "Variable")
3814 {
3815 self.problem_report_custom(
3816 RustConstructorError::VariableNotFound {
3817 variable_name: name.to_string(),
3818 },
3819 SeverityLevel::SevereWarning,
3820 self.problem_list.clone(),
3821 );
3822 return Err(RustConstructorError::VariableNotFound {
3823 variable_name: name.to_string(),
3824 });
3825 };
3826 let v = self.get_resource_mut::<Variable>(name, "Variable").unwrap();
3827 v.value = value.into();
3828 Ok(())
3829 }
3830
3831 pub fn var(&self, name: &str, safe_mode: Option<bool>) -> Result<Value, RustConstructorError> {
3833 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3834 && !self.check_resource_exists(name, "Variable")
3835 {
3836 self.problem_report_custom(
3837 RustConstructorError::VariableNotFound {
3838 variable_name: name.to_string(),
3839 },
3840 SeverityLevel::SevereWarning,
3841 self.problem_list.clone(),
3842 );
3843 return Err(RustConstructorError::VariableNotFound {
3844 variable_name: name.to_string(),
3845 });
3846 };
3847 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3848 Ok(v.value.clone())
3849 }
3850
3851 pub fn var_i(&self, name: &str, safe_mode: Option<bool>) -> Result<i32, RustConstructorError> {
3853 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3854 && !self.check_resource_exists(name, "Variable")
3855 {
3856 self.problem_report_custom(
3857 RustConstructorError::VariableNotFound {
3858 variable_name: name.to_string(),
3859 },
3860 SeverityLevel::SevereWarning,
3861 self.problem_list.clone(),
3862 );
3863 return Err(RustConstructorError::VariableNotFound {
3864 variable_name: name.to_string(),
3865 });
3866 };
3867 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3868 match &v.value {
3869 Value::Int(i) => Ok(*i),
3871 _ => {
3872 self.problem_report_custom(
3873 RustConstructorError::VariableNotInt {
3874 variable_name: name.to_string(),
3875 },
3876 SeverityLevel::SevereWarning,
3877 self.problem_list.clone(),
3878 );
3879 Err(RustConstructorError::VariableNotInt {
3880 variable_name: name.to_string(),
3881 })
3882 }
3883 }
3884 }
3885
3886 pub fn var_u(&self, name: &str, safe_mode: Option<bool>) -> Result<u32, RustConstructorError> {
3888 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3889 && !self.check_resource_exists(name, "Variable")
3890 {
3891 self.problem_report_custom(
3892 RustConstructorError::VariableNotFound {
3893 variable_name: name.to_string(),
3894 },
3895 SeverityLevel::SevereWarning,
3896 self.problem_list.clone(),
3897 );
3898 return Err(RustConstructorError::VariableNotFound {
3899 variable_name: name.to_string(),
3900 });
3901 };
3902 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3903 match &v.value {
3904 Value::UInt(u) => Ok(*u),
3906 _ => {
3907 self.problem_report_custom(
3908 RustConstructorError::VariableNotUInt {
3909 variable_name: name.to_string(),
3910 },
3911 SeverityLevel::SevereWarning,
3912 self.problem_list.clone(),
3913 );
3914 Err(RustConstructorError::VariableNotUInt {
3915 variable_name: name.to_string(),
3916 })
3917 }
3918 }
3919 }
3920
3921 pub fn var_f(&self, name: &str, safe_mode: Option<bool>) -> Result<f32, RustConstructorError> {
3923 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3924 && !self.check_resource_exists(name, "Variable")
3925 {
3926 self.problem_report_custom(
3927 RustConstructorError::VariableNotFound {
3928 variable_name: name.to_string(),
3929 },
3930 SeverityLevel::SevereWarning,
3931 self.problem_list.clone(),
3932 );
3933 return Err(RustConstructorError::VariableNotFound {
3934 variable_name: name.to_string(),
3935 });
3936 };
3937 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3938 match &v.value {
3939 Value::Float(f) => Ok(*f),
3941 _ => {
3942 self.problem_report_custom(
3943 RustConstructorError::VariableNotFloat {
3944 variable_name: name.to_string(),
3945 },
3946 SeverityLevel::SevereWarning,
3947 self.problem_list.clone(),
3948 );
3949 Err(RustConstructorError::VariableNotFloat {
3950 variable_name: name.to_string(),
3951 })
3952 }
3953 }
3954 }
3955
3956 pub fn var_b(&self, name: &str, safe_mode: Option<bool>) -> Result<bool, RustConstructorError> {
3958 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3959 && !self.check_resource_exists(name, "Variable")
3960 {
3961 self.problem_report_custom(
3962 RustConstructorError::VariableNotFound {
3963 variable_name: name.to_string(),
3964 },
3965 SeverityLevel::SevereWarning,
3966 self.problem_list.clone(),
3967 );
3968 return Err(RustConstructorError::VariableNotFound {
3969 variable_name: name.to_string(),
3970 });
3971 };
3972 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3973 match &v.value {
3974 Value::Bool(b) => Ok(*b),
3976 _ => {
3977 self.problem_report_custom(
3978 RustConstructorError::VariableNotBool {
3979 variable_name: name.to_string(),
3980 },
3981 SeverityLevel::SevereWarning,
3982 self.problem_list.clone(),
3983 );
3984 Err(RustConstructorError::VariableNotBool {
3985 variable_name: name.to_string(),
3986 })
3987 }
3988 }
3989 }
3990
3991 pub fn var_v(
3993 &self,
3994 name: &str,
3995 safe_mode: Option<bool>,
3996 ) -> Result<Vec<Value>, RustConstructorError> {
3997 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3998 && !self.check_resource_exists(name, "Variable")
3999 {
4000 self.problem_report_custom(
4001 RustConstructorError::VariableNotFound {
4002 variable_name: name.to_string(),
4003 },
4004 SeverityLevel::SevereWarning,
4005 self.problem_list.clone(),
4006 );
4007 return Err(RustConstructorError::VariableNotFound {
4008 variable_name: name.to_string(),
4009 });
4010 };
4011 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
4012 match &v.value {
4013 Value::Vec(v) => Ok(v.clone()),
4015 _ => {
4016 self.problem_report_custom(
4017 RustConstructorError::VariableNotVec {
4018 variable_name: name.to_string(),
4019 },
4020 SeverityLevel::SevereWarning,
4021 self.problem_list.clone(),
4022 );
4023 Err(RustConstructorError::VariableNotVec {
4024 variable_name: name.to_string(),
4025 })
4026 }
4027 }
4028 }
4029
4030 pub fn var_s(
4032 &self,
4033 name: &str,
4034 safe_mode: Option<bool>,
4035 ) -> Result<String, RustConstructorError> {
4036 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4037 && !self.check_resource_exists(name, "Variable")
4038 {
4039 self.problem_report_custom(
4040 RustConstructorError::VariableNotFound {
4041 variable_name: name.to_string(),
4042 },
4043 SeverityLevel::SevereWarning,
4044 self.problem_list.clone(),
4045 );
4046 return Err(RustConstructorError::VariableNotFound {
4047 variable_name: name.to_string(),
4048 });
4049 };
4050 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
4051 match &v.value {
4052 Value::String(s) => Ok(s.clone()),
4054 _ => {
4055 self.problem_report_custom(
4056 RustConstructorError::VariableNotString {
4057 variable_name: name.to_string(),
4058 },
4059 SeverityLevel::SevereWarning,
4060 self.problem_list.clone(),
4061 );
4062 Err(RustConstructorError::VariableNotString {
4063 variable_name: name.to_string(),
4064 })
4065 }
4066 }
4067 }
4068
4069 pub fn var_decode_b(&self, target: Value) -> Result<bool, RustConstructorError> {
4071 match target {
4072 Value::Bool(b) => {
4073 Ok(b)
4075 }
4076 _ => {
4077 self.problem_report_custom(
4078 RustConstructorError::VariableNotBool {
4079 variable_name: format!("{:?}", target),
4080 },
4081 SeverityLevel::SevereWarning,
4082 self.problem_list.clone(),
4083 );
4084 Err(RustConstructorError::VariableNotBool {
4085 variable_name: format!("{:?}", target),
4086 })
4087 }
4088 }
4089 }
4090
4091 pub fn var_decode_i(&self, target: Value) -> Result<i32, RustConstructorError> {
4093 match target {
4094 Value::Int(i) => {
4095 Ok(i)
4097 }
4098 _ => {
4099 self.problem_report_custom(
4100 RustConstructorError::VariableNotInt {
4101 variable_name: format!("{:?}", target),
4102 },
4103 SeverityLevel::SevereWarning,
4104 self.problem_list.clone(),
4105 );
4106 Err(RustConstructorError::VariableNotInt {
4107 variable_name: format!("{:?}", target),
4108 })
4109 }
4110 }
4111 }
4112
4113 pub fn var_decode_u(&self, target: Value) -> Result<u32, RustConstructorError> {
4115 match target {
4116 Value::UInt(u) => {
4117 Ok(u)
4119 }
4120 _ => {
4121 self.problem_report_custom(
4122 RustConstructorError::VariableNotUInt {
4123 variable_name: format!("{:?}", target),
4124 },
4125 SeverityLevel::SevereWarning,
4126 self.problem_list.clone(),
4127 );
4128 Err(RustConstructorError::VariableNotUInt {
4129 variable_name: format!("{:?}", target),
4130 })
4131 }
4132 }
4133 }
4134
4135 pub fn var_decode_f(&self, target: Value) -> Result<f32, RustConstructorError> {
4137 match target {
4138 Value::Float(f) => {
4139 Ok(f)
4141 }
4142 _ => {
4143 self.problem_report_custom(
4144 RustConstructorError::VariableNotFloat {
4145 variable_name: format!("{:?}", target),
4146 },
4147 SeverityLevel::SevereWarning,
4148 self.problem_list.clone(),
4149 );
4150 Err(RustConstructorError::VariableNotFloat {
4151 variable_name: format!("{:?}", target),
4152 })
4153 }
4154 }
4155 }
4156
4157 pub fn var_decode_s(&self, target: Value) -> Result<String, RustConstructorError> {
4159 match target {
4160 Value::String(s) => {
4161 Ok(s)
4163 }
4164 _ => {
4165 self.problem_report_custom(
4166 RustConstructorError::VariableNotString {
4167 variable_name: format!("{:?}", target),
4168 },
4169 SeverityLevel::SevereWarning,
4170 self.problem_list.clone(),
4171 );
4172 Err(RustConstructorError::VariableNotString {
4173 variable_name: format!("{:?}", target),
4174 })
4175 }
4176 }
4177 }
4178
4179 pub fn var_decode_v(&self, target: Value) -> Result<Vec<Value>, RustConstructorError> {
4181 match target {
4182 Value::Vec(v) => {
4183 Ok(v)
4185 }
4186 _ => {
4187 self.problem_report_custom(
4188 RustConstructorError::VariableNotVec {
4189 variable_name: format!("{:?}", target),
4190 },
4191 SeverityLevel::SevereWarning,
4192 self.problem_list.clone(),
4193 );
4194 Err(RustConstructorError::VariableNotVec {
4195 variable_name: format!("{:?}", target),
4196 })
4197 }
4198 }
4199 }
4200
4201 pub fn add_image_texture(
4203 &mut self,
4204 mut image_texture: ImageTexture,
4205 path: &str,
4206 flip: [bool; 2],
4207 ctx: &Context,
4208 ) {
4209 if let Ok(mut file) = File::open(path) {
4210 let mut buffer = Vec::new();
4211 file.read_to_end(&mut buffer).unwrap();
4212 let img_bytes = buffer;
4213 let img = image::load_from_memory(&img_bytes).unwrap();
4214 let color_data = match flip {
4215 [true, true] => img.fliph().flipv().into_rgba8(),
4216 [true, false] => img.fliph().into_rgba8(),
4217 [false, true] => img.flipv().into_rgba8(),
4218 _ => img.into_rgba8(),
4219 };
4220 let (w, h) = (color_data.width(), color_data.height());
4221 let raw_data: Vec<u8> = color_data.into_raw();
4222
4223 let color_image =
4224 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
4225 let loaded_image_texture = ctx.load_texture(
4226 image_texture.name.clone(),
4227 color_image,
4228 TextureOptions::LINEAR,
4229 );
4230 image_texture.texture = Some(DebugTextureHandle::new(loaded_image_texture));
4231 image_texture.cite_path = path.to_string();
4232 self.rust_constructor_resource.push(Box::new(image_texture));
4233 } else {
4234 self.problem_report_custom(
4235 RustConstructorError::ImageGetFailed {
4236 image_path: path.to_string(),
4237 },
4238 SeverityLevel::SevereWarning,
4239 self.problem_list.clone(),
4240 );
4241 };
4242 }
4243
4244 pub fn image_texture(
4246 &self,
4247 name: &str,
4248 safe_mode: Option<bool>,
4249 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
4250 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4251 && !self.check_resource_exists(name, "ImageTexture")
4252 {
4253 self.problem_report_custom(
4254 RustConstructorError::ImageNotFound {
4255 image_name: name.to_string(),
4256 },
4257 SeverityLevel::SevereWarning,
4258 self.problem_list.clone(),
4259 );
4260 return Err(RustConstructorError::ImageNotFound {
4261 image_name: name.to_string(),
4262 });
4263 };
4264 let it = self
4265 .get_resource::<ImageTexture>(name, "ImageTexture")
4266 .unwrap();
4267 Ok(it.texture.clone())
4268 }
4269
4270 pub fn reset_image_texture(
4272 &mut self,
4273 name: &str,
4274 path: &str,
4275 flip: [bool; 2],
4276 ctx: &Context,
4277 safe_mode: Option<bool>,
4278 ) -> Result<(), RustConstructorError> {
4279 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4280 && !self.check_resource_exists(name, "ImageTexture")
4281 {
4282 self.problem_report_custom(
4283 RustConstructorError::ImageTextureNotFound {
4284 image_texture_name: name.to_string(),
4285 },
4286 SeverityLevel::SevereWarning,
4287 self.problem_list.clone(),
4288 );
4289 return Err(RustConstructorError::ImageTextureNotFound {
4290 image_texture_name: name.to_string(),
4291 });
4292 };
4293 let it = self
4294 .get_resource_mut::<ImageTexture>(name, "ImageTexture")
4295 .unwrap();
4296 if let Ok(mut file) = File::open(path) {
4297 let mut buffer = Vec::new();
4298 file.read_to_end(&mut buffer).unwrap();
4299 let img_bytes = buffer;
4300 let img = image::load_from_memory(&img_bytes).unwrap();
4301 let color_data = match flip {
4302 [true, true] => img.fliph().flipv().into_rgba8(),
4303 [true, false] => img.fliph().into_rgba8(),
4304 [false, true] => img.flipv().into_rgba8(),
4305 _ => img.into_rgba8(),
4306 };
4307 let (w, h) = (color_data.width(), color_data.height());
4308 let raw_data: Vec<u8> = color_data.into_raw();
4309
4310 let color_image =
4311 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
4312 let image_texture =
4313 ctx.load_texture(it.name.clone(), color_image, TextureOptions::LINEAR);
4314 it.texture = Some(DebugTextureHandle::new(image_texture));
4315 it.cite_path = path.to_string();
4316 } else {
4317 self.problem_report_custom(
4318 RustConstructorError::ImageGetFailed {
4319 image_path: path.to_string(),
4320 },
4321 SeverityLevel::SevereWarning,
4322 self.problem_list.clone(),
4323 );
4324 };
4325 Ok(())
4326 }
4327
4328 pub fn add_image(
4330 &mut self,
4331 mut image: Image,
4332 image_texture_name: &str,
4333 safe_mode: Option<bool>,
4334 ) -> Result<(), RustConstructorError> {
4335 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4336 && !self.check_resource_exists(image_texture_name, "ImageTexture")
4337 {
4338 self.problem_report_custom(
4339 RustConstructorError::ImageTextureNotFound {
4340 image_texture_name: image_texture_name.to_string(),
4341 },
4342 SeverityLevel::SevereWarning,
4343 self.problem_list.clone(),
4344 );
4345 return Err(RustConstructorError::ImageTextureNotFound {
4346 image_texture_name: image_texture_name.to_string(),
4347 });
4348 };
4349 let it = self
4350 .get_resource::<ImageTexture>(image_texture_name, "ImageTexture")
4351 .unwrap();
4352 image.texture = it.texture.clone();
4353 image.cite_texture = it.name.clone();
4354 image.last_frame_cite_texture = it.name.clone();
4355 self.rust_constructor_resource.push(Box::new(image));
4356 Ok(())
4357 }
4358
4359 pub fn image(
4361 &mut self,
4362 name: &str,
4363 ui: &mut Ui,
4364 ctx: &Context,
4365 safe_mode: Option<bool>,
4366 ) -> Result<(), RustConstructorError> {
4367 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4368 && !self.check_resource_exists(name, "Image")
4369 {
4370 self.problem_report_custom(
4371 RustConstructorError::ImageNotFound {
4372 image_name: name.to_string(),
4373 },
4374 SeverityLevel::SevereWarning,
4375 self.problem_list.clone(),
4376 );
4377 return Err(RustConstructorError::ImageNotFound {
4378 image_name: name.to_string(),
4379 });
4380 };
4381 let mut im = self
4382 .get_resource_mut::<Image>(name, "Image")
4383 .unwrap()
4384 .clone();
4385 if im.cite_texture != im.last_frame_cite_texture {
4386 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4387 && !self.check_resource_exists(&im.cite_texture, "ImageTexture")
4388 {
4389 self.problem_report_custom(
4390 RustConstructorError::ImageTextureNotFound {
4391 image_texture_name: im.cite_texture.clone(),
4392 },
4393 SeverityLevel::MildWarning,
4394 self.problem_list.clone(),
4395 );
4396 } else {
4397 let it = self
4398 .get_resource::<ImageTexture>(&im.cite_texture, "ImageTexture")
4399 .unwrap();
4400 im.texture = it.texture.clone();
4401 };
4402 };
4403 im.reg_render_resource(&mut self.render_resource_list);
4404 im.position[0] = match im.x_grid[1] {
4405 0 => im.origin_position[0],
4406 _ => {
4407 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64 * im.x_grid[0] as f64)
4408 as f32
4409 + im.origin_position[0]
4410 }
4411 };
4412 im.position[1] = match im.y_grid[1] {
4413 0 => im.origin_position[1],
4414 _ => {
4415 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64 * im.y_grid[0] as f64)
4416 as f32
4417 + im.origin_position[1]
4418 }
4419 };
4420 match im.center_display.0 {
4421 HorizontalAlign::Left => {}
4422 HorizontalAlign::Center => im.position[0] -= im.size[0] / 2.0,
4423 HorizontalAlign::Right => im.position[0] -= im.size[0],
4424 };
4425 match im.center_display.1 {
4426 VerticalAlign::Top => {}
4427 VerticalAlign::Center => im.position[1] -= im.size[1] / 2.0,
4428 VerticalAlign::Bottom => im.position[1] -= im.size[1],
4429 };
4430 im.position[0] += im.offset[0];
4431 im.position[1] += im.offset[1];
4432 if let Some(texture) = &im.texture {
4433 let rect = Rect::from_min_size(
4434 Pos2::new(im.position[0], im.position[1]),
4435 Vec2::new(im.size[0], im.size[1]),
4436 );
4437
4438 egui::Image::new(ImageSource::Texture((&texture.0).into()))
4440 .tint(Color32::from_rgba_unmultiplied(
4441 im.overlay_color[0],
4442 im.overlay_color[1],
4443 im.overlay_color[2],
4444 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
4446 ))
4447 .bg_fill(Color32::from_rgba_unmultiplied(
4448 im.background_color[0],
4449 im.background_color[1],
4450 im.background_color[2],
4451 im.background_color[3],
4452 ))
4453 .rotate(
4454 im.rotate_angle,
4455 [
4456 im.rotate_center[0] / im.size[0],
4457 im.rotate_center[1] / im.size[1],
4458 ]
4459 .into(),
4460 )
4461 .paint_at(ui, rect)
4462 };
4463 im.last_frame_cite_texture = im.cite_texture.clone();
4464 self.replace_resource(name, "Image", im).unwrap();
4465 Ok(())
4466 }
4467
4468 #[allow(clippy::too_many_arguments)]
4470 pub fn add_message_box(
4471 &mut self,
4472 mut message_box: MessageBox,
4473 title_name: &str,
4474 content_name: &str,
4475 image_name: &str,
4476 close_switch_fill_resource_name: &str,
4477 close_switch_fill_resource_type: &str,
4478 safe_mode: Option<bool>,
4479 ) -> Result<(), RustConstructorError> {
4480 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4481 && self.check_resource_exists(&message_box.name, "MessageBox")
4482 {
4483 self.problem_report_custom(
4484 RustConstructorError::MessageBoxAlreadyExists {
4485 message_box_name: message_box.name.to_string(),
4486 },
4487 SeverityLevel::SevereWarning,
4488 self.problem_list.clone(),
4489 );
4490 return Err(RustConstructorError::MessageBoxAlreadyExists {
4491 message_box_name: message_box.name.to_string(),
4492 });
4493 };
4494 message_box.exist = true;
4495 message_box.memory_offset = 0_f32;
4496
4497 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4498 && !self.check_resource_exists(image_name, "Image")
4499 {
4500 self.problem_report_custom(
4501 RustConstructorError::ImageNotFound {
4502 image_name: image_name.to_string(),
4503 },
4504 SeverityLevel::SevereWarning,
4505 self.problem_list.clone(),
4506 );
4507 return Err(RustConstructorError::ImageNotFound {
4508 image_name: image_name.to_string(),
4509 });
4510 };
4511 let im = self.get_resource_mut::<Image>(image_name, "Image").unwrap();
4512 im.size = [message_box.size[1] - 15_f32, message_box.size[1] - 15_f32];
4513 im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
4514 im.x_grid = [1, 1];
4515 im.y_grid = [0, 1];
4516 im.name = format!("MessageBox{}", im.name);
4517 message_box.image_name = im.name.to_string();
4518
4519 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4520 && !self.check_resource_exists(title_name, "Text")
4521 {
4522 self.problem_report_custom(
4523 RustConstructorError::TextNotFound {
4524 text_name: title_name.to_string(),
4525 },
4526 SeverityLevel::SevereWarning,
4527 self.problem_list.clone(),
4528 );
4529 return Err(RustConstructorError::TextNotFound {
4530 text_name: title_name.to_string(),
4531 });
4532 };
4533 let t = self.get_resource_mut::<Text>(title_name, "Text").unwrap();
4534 t.x_grid = [1, 1];
4535 t.y_grid = [0, 1];
4536 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
4537 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
4538 t.name = format!("MessageBox{}", t.name);
4539 message_box.title_name = t.name.to_string();
4540
4541 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4542 && !self.check_resource_exists(content_name, "Text")
4543 {
4544 self.problem_report_custom(
4545 RustConstructorError::TextNotFound {
4546 text_name: content_name.to_string(),
4547 },
4548 SeverityLevel::SevereWarning,
4549 self.problem_list.clone(),
4550 );
4551 return Err(RustConstructorError::TextNotFound {
4552 text_name: content_name.to_string(),
4553 });
4554 };
4555 let t = self.get_resource_mut::<Text>(content_name, "Text").unwrap();
4556 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
4557 t.x_grid = [1, 1];
4558 t.y_grid = [0, 1];
4559 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
4560 t.name = format!("MessageBox{}", t.name);
4561 message_box.content_name = t.name.to_string();
4562
4563 if !message_box.keep_existing {
4564 self.add_split_time(
4565 SplitTime::default().name(&format!("MessageBox{}", message_box.name)),
4566 );
4567 };
4568
4569 self.add_split_time(
4570 SplitTime::default().name(&format!("MessageBox{}Animation", message_box.name)),
4571 );
4572
4573 self.add_custom_rect(
4574 CustomRect::default()
4575 .name(&format!("MessageBox{}", message_box.name))
4576 .origin_position(0_f32, 0_f32)
4577 .size(message_box.size[0], message_box.size[1])
4578 .rounding(20_f32)
4579 .x_grid(1, 1)
4580 .y_grid(0, 1)
4581 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4582 .color(100, 100, 100, 125)
4583 .border_width(0_f32),
4584 );
4585
4586 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4587 match close_switch_fill_resource_type {
4588 "Image" | "CustomRect" => {}
4589 &_ => {
4590 self.problem_report_custom(
4591 RustConstructorError::SwitchFillResourceMismatch {
4592 switch_name: format!("MessageBox{}Close", message_box.name),
4593 fill_resource_name: close_switch_fill_resource_name.to_string(),
4594 fill_resource_type: close_switch_fill_resource_type.to_string(),
4595 },
4596 SeverityLevel::SevereWarning,
4597 self.problem_list.clone(),
4598 );
4599 return Err(RustConstructorError::SwitchFillResourceMismatch {
4600 switch_name: format!("MessageBox{}Close", message_box.name),
4601 fill_resource_name: close_switch_fill_resource_name.to_string(),
4602 fill_resource_type: close_switch_fill_resource_type.to_string(),
4603 });
4604 }
4605 };
4606 };
4607
4608 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4609 && !self.check_resource_exists(
4610 close_switch_fill_resource_name,
4611 close_switch_fill_resource_type,
4612 )
4613 {
4614 self.problem_report_custom(
4615 RustConstructorError::ResourceNotFound {
4616 resource_name: close_switch_fill_resource_name.to_string(),
4617 resource_type: close_switch_fill_resource_type.to_string(),
4618 },
4619 SeverityLevel::SevereWarning,
4620 self.problem_list.clone(),
4621 );
4622 return Err(RustConstructorError::ResourceNotFound {
4623 resource_name: close_switch_fill_resource_name.to_string(),
4624 resource_type: close_switch_fill_resource_type.to_string(),
4625 });
4626 };
4627
4628 let (texture, image_config, custom_rect_config, color, border_color) =
4629 match close_switch_fill_resource_type {
4630 "Image" => {
4631 let im = self
4632 .get_resource_mut::<Image>(close_switch_fill_resource_name, "Image")
4633 .unwrap();
4634 im.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4635 (
4636 im.cite_texture.clone(),
4637 ImageConfig::from_image(im.clone())
4638 .size(30_f32, 30_f32)
4639 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4640 CustomRectConfig::default(),
4641 im.overlay_color,
4642 [0, 0, 0, 0],
4643 )
4644 }
4645 "CustomRect" => {
4646 let cr = self
4647 .get_resource_mut::<CustomRect>(
4648 close_switch_fill_resource_name,
4649 "CustomRect",
4650 )
4651 .unwrap();
4652 cr.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4653 (
4654 String::new(),
4655 ImageConfig::default(),
4656 CustomRectConfig::from_custom_rect(cr.clone())
4657 .size(30_f32, 30_f32)
4658 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4659 cr.color,
4660 cr.border_color,
4661 )
4662 }
4663 &_ => {
4664 self.problem_report_custom(
4665 RustConstructorError::SwitchFillResourceMismatch {
4666 switch_name: format!("MessageBox{}Close", message_box.name),
4667 fill_resource_name: close_switch_fill_resource_name.to_string(),
4668 fill_resource_type: close_switch_fill_resource_type.to_string(),
4669 },
4670 SeverityLevel::SevereWarning,
4671 self.problem_list.clone(),
4672 );
4673 return Err(RustConstructorError::SwitchFillResourceMismatch {
4674 switch_name: format!("MessageBox{}Close", message_box.name),
4675 fill_resource_name: close_switch_fill_resource_name.to_string(),
4676 fill_resource_type: close_switch_fill_resource_type.to_string(),
4677 });
4678 }
4679 };
4680
4681 self.add_switch(
4682 Switch::default()
4683 .name(&format!("MessageBox{}Close", message_box.name))
4684 .appearance(vec![
4685 SwitchAppearance {
4686 image_config: image_config
4687 .clone()
4688 .overlay_color(color[0], color[1], color[2], 0),
4689 custom_rect_config: custom_rect_config
4690 .clone()
4691 .color(color[0], color[1], color[2], 0)
4692 .border_color(border_color[0], border_color[1], border_color[2], 0),
4693 text_config: TextConfig::default(),
4694 texture: texture.clone(),
4695 hint_text: String::new(),
4696 },
4697 SwitchAppearance {
4698 image_config: image_config.clone().overlay_color(
4699 (color[0] as u32 * 180 / 255) as u8,
4700 (color[1] as u32 * 180 / 255) as u8,
4701 (color[2] as u32 * 180 / 255) as u8,
4702 255,
4703 ),
4704 custom_rect_config: custom_rect_config
4705 .clone()
4706 .color(
4707 (color[0] as u32 * 180 / 255) as u8,
4708 (color[1] as u32 * 180 / 255) as u8,
4709 (color[2] as u32 * 180 / 255) as u8,
4710 255,
4711 )
4712 .border_color(
4713 (border_color[0] as u32 * 180 / 255) as u8,
4714 (border_color[1] as u32 * 180 / 255) as u8,
4715 (border_color[2] as u32 * 180 / 255) as u8,
4716 255,
4717 ),
4718 text_config: TextConfig::default(),
4719 texture: texture.clone(),
4720 hint_text: String::new(),
4721 },
4722 SwitchAppearance {
4723 image_config: image_config.clone().overlay_color(0, 0, 0, 0),
4724 custom_rect_config: custom_rect_config
4725 .clone()
4726 .color(0, 0, 0, 0)
4727 .border_color(0, 0, 0, 0),
4728 text_config: TextConfig::default(),
4729 texture: texture.clone(),
4730 hint_text: String::new(),
4731 },
4732 SwitchAppearance {
4733 image_config: image_config.overlay_color(0, 0, 0, 0),
4734 custom_rect_config: custom_rect_config
4735 .color(0, 0, 0, 0)
4736 .border_color(0, 0, 0, 0),
4737 text_config: TextConfig::default(),
4738 texture,
4739 hint_text: String::new(),
4740 },
4741 ])
4742 .enable_hover_click_fill_resource(false, true)
4743 .click_method(vec![SwitchClickAction {
4744 click_method: PointerButton::Primary,
4745 action: true,
4746 }]),
4747 &format!("MessageBox{}Close", close_switch_fill_resource_name),
4748 close_switch_fill_resource_type,
4749 "",
4750 )
4751 .unwrap();
4752 self.rust_constructor_resource
4753 .push(Box::new(message_box.clone()));
4754 Ok(())
4755 }
4756
4757 pub fn message_box_display(&mut self, ctx: &Context, ui: &mut Ui, safe_mode: Option<bool>) {
4759 let mut offset = 0_f32;
4760 let mut delete_count = 0;
4761 let mut index_list = Vec::new();
4762 for i in 0..self.rust_constructor_resource.len() {
4763 if self.rust_constructor_resource[i]
4764 .as_any()
4765 .downcast_ref::<MessageBox>()
4766 .is_some()
4767 {
4768 index_list.push(i);
4769 };
4770 }
4771 for u in 0..index_list.len() {
4772 let mut deleted = false;
4773 let i = u - delete_count;
4774 let mut mb = self.rust_constructor_resource[index_list[i]]
4775 .as_any()
4776 .downcast_ref::<MessageBox>()
4777 .unwrap()
4778 .clone();
4779 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4780 if !self.check_resource_exists(&mb.image_name, "Image") {
4781 self.problem_report_custom(
4782 RustConstructorError::ImageNotFound {
4783 image_name: mb.image_name,
4784 },
4785 SeverityLevel::SevereWarning,
4786 self.problem_list.clone(),
4787 );
4788 continue;
4789 };
4790 if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "CustomRect") {
4791 self.problem_report_custom(
4792 RustConstructorError::RectNotFound {
4793 rect_name: format!("MessageBox{}", mb.name),
4794 },
4795 SeverityLevel::SevereWarning,
4796 self.problem_list.clone(),
4797 );
4798 continue;
4799 };
4800 if !self.check_resource_exists(&mb.title_name, "Text") {
4801 self.problem_report_custom(
4802 RustConstructorError::TextNotFound {
4803 text_name: mb.title_name,
4804 },
4805 SeverityLevel::SevereWarning,
4806 self.problem_list.clone(),
4807 );
4808 continue;
4809 };
4810 if !self.check_resource_exists(&mb.content_name, "Text") {
4811 self.problem_report_custom(
4812 RustConstructorError::TextNotFound {
4813 text_name: mb.content_name,
4814 },
4815 SeverityLevel::SevereWarning,
4816 self.problem_list.clone(),
4817 );
4818 continue;
4819 };
4820 if !self.check_resource_exists(&format!("MessageBox{}Close", mb.name), "Switch") {
4821 self.problem_report_custom(
4822 RustConstructorError::SwitchNotFound {
4823 switch_name: format!("MessageBox{}Close", mb.name),
4824 },
4825 SeverityLevel::SevereWarning,
4826 self.problem_list.clone(),
4827 );
4828 continue;
4829 };
4830 if !self
4831 .check_resource_exists(&format!("MessageBox{}Animation", mb.name), "SplitTime")
4832 {
4833 self.problem_report_custom(
4834 RustConstructorError::SplitTimeNotFound {
4835 split_time_name: format!("MessageBox{}Animation", mb.name),
4836 },
4837 SeverityLevel::SevereWarning,
4838 self.problem_list.clone(),
4839 );
4840 continue;
4841 };
4842 if !mb.keep_existing
4843 && !self.check_resource_exists(&format!("MessageBox{}", mb.name), "SplitTime")
4844 {
4845 self.problem_report_custom(
4846 RustConstructorError::SplitTimeNotFound {
4847 split_time_name: format!("MessageBox{}", mb.name),
4848 },
4849 SeverityLevel::SevereWarning,
4850 self.problem_list.clone(),
4851 );
4852 continue;
4853 };
4854 };
4855 let mut im1 = self
4856 .get_resource::<Image>(&mb.image_name, "Image")
4857 .unwrap()
4858 .clone();
4859 let mut cr = self
4860 .get_resource::<CustomRect>(&format!("MessageBox{}", mb.name), "CustomRect")
4861 .unwrap()
4862 .clone();
4863 let mut t1 = self
4864 .get_resource::<Text>(&mb.title_name, "Text")
4865 .unwrap()
4866 .clone();
4867 let mut t2 = self
4868 .get_resource::<Text>(&mb.content_name, "Text")
4869 .unwrap()
4870 .clone();
4871 let mut s = self
4872 .get_resource::<Switch>(&format!("MessageBox{}Close", mb.name), "Switch")
4873 .unwrap()
4874 .clone();
4875 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4876 && !self.check_resource_exists(&s.fill_resource_name, &s.fill_resource_type)
4877 {
4878 self.problem_report_custom(
4879 RustConstructorError::ResourceNotFound {
4880 resource_name: s.fill_resource_name,
4881 resource_type: s.fill_resource_type,
4882 },
4883 SeverityLevel::SevereWarning,
4884 self.problem_list.clone(),
4885 );
4886 continue;
4887 };
4888 let fr: Box<dyn BasicFrontResource> = match s.fill_resource_type.as_str() {
4889 "Image" => Box::new(
4890 self.get_resource::<Image>(&s.fill_resource_name, "Image")
4891 .unwrap()
4892 .clone(),
4893 ),
4894 "CustomRect" => Box::new(
4895 self.get_resource::<CustomRect>(&s.fill_resource_name, "CustomRect")
4896 .unwrap()
4897 .clone(),
4898 ),
4899 &_ => {
4900 self.problem_report_custom(
4901 RustConstructorError::SwitchFillResourceMismatch {
4902 switch_name: s.name,
4903 fill_resource_name: s.fill_resource_name,
4904 fill_resource_type: s.fill_resource_type,
4905 },
4906 SeverityLevel::SevereWarning,
4907 self.problem_list.clone(),
4908 );
4909 continue;
4910 }
4911 };
4912 mb.reg_render_resource(&mut self.render_resource_list.clone());
4913 if mb.size[1] < t1.size[1] + t2.size[1] + 10_f32 {
4914 mb.size[1] = t1.size[1] + t2.size[1] + 10_f32;
4915 cr.size[1] = mb.size[1];
4916 im1.size = [mb.size[1] - 15_f32, mb.size[1] - 15_f32];
4917 t1.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4918 t2.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4919 };
4920 if self.timer.total_time
4921 - self
4922 .split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4923 .unwrap()[1]
4924 >= self.tick_interval
4925 {
4926 self.reset_split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4927 .unwrap();
4928 if offset != mb.memory_offset {
4929 if mb.memory_offset < offset {
4930 if mb.memory_offset + mb.restore_speed >= offset {
4931 mb.memory_offset = offset;
4932 } else {
4933 mb.memory_offset += mb.restore_speed;
4934 };
4935 } else if mb.memory_offset - mb.restore_speed <= offset {
4936 mb.memory_offset = offset;
4937 } else {
4938 mb.memory_offset -= mb.restore_speed;
4939 };
4940 };
4941 if cr.origin_position[0] != -mb.size[0] - 5_f32 {
4942 if mb.exist {
4943 if cr.origin_position[0] - mb.speed <= -mb.size[0] - 5_f32 {
4944 cr.origin_position[0] = -mb.size[0] - 5_f32;
4945 if self.check_resource_exists(
4946 &format!("MessageBox{}", mb.name),
4947 "SplitTime",
4948 ) {
4949 self.reset_split_time(&format!("MessageBox{}", mb.name), safe_mode)
4950 .unwrap();
4951 };
4952 } else {
4953 cr.origin_position[0] -= mb.speed;
4954 };
4955 } else if cr.origin_position[0] + mb.speed >= 15_f32 {
4956 cr.origin_position[0] = 15_f32;
4957 delete_count += 1;
4958 deleted = true;
4959 } else {
4960 cr.origin_position[0] += mb.speed;
4961 };
4962 };
4963 };
4964 cr.origin_position[1] = mb.memory_offset + 20_f32;
4965 im1.origin_position = [
4966 cr.origin_position[0] + 5_f32,
4967 cr.origin_position[1] + mb.size[1] / 2_f32,
4968 ];
4969 t1.origin_position = [
4970 im1.origin_position[0] + im1.size[0] + 5_f32,
4971 cr.origin_position[1] + 5_f32,
4972 ];
4973 t2.origin_position = [
4974 im1.origin_position[0] + im1.size[0] + 5_f32,
4975 t1.origin_position[1] + t1.size[1],
4976 ];
4977 for sd in &mut s.appearance {
4978 sd.image_config.origin_position = cr.position;
4979 sd.custom_rect_config.origin_position = cr.position;
4980 }
4981 if !mb.keep_existing
4982 && self.timer.total_time
4983 - self
4984 .split_time(&format!("MessageBox{}", mb.name), safe_mode)
4985 .unwrap()[1]
4986 >= mb.existing_time
4987 && cr.origin_position[0] == -mb.size[0] - 5_f32
4988 {
4989 mb.exist = false;
4990 if cr.origin_position[0] + mb.speed >= 15_f32 {
4991 cr.origin_position[0] = 15_f32;
4992 } else {
4993 cr.origin_position[0] += mb.speed;
4994 };
4995 };
4996 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4997 let rect = Rect::from_min_size(
4998 Pos2 {
4999 x: fr.position()[0],
5000 y: fr.position()[1],
5001 },
5002 Vec2 {
5003 x: cr.size[0] + 15_f32,
5004 y: cr.size[1] + 15_f32,
5005 },
5006 );
5007 if rect.contains(mouse_pos) {
5008 s.appearance[0].image_config.overlay_color[3] = 255;
5009 s.appearance[0].custom_rect_config.color[3] = 255;
5010 s.appearance[0].custom_rect_config.border_color[3] = 255;
5011 } else {
5012 s.appearance[0].image_config.overlay_color[3] = 0;
5013 s.appearance[0].custom_rect_config.color[3] = 0;
5014 s.appearance[0].custom_rect_config.border_color[3] = 0;
5015 };
5016 };
5017 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
5018 self.replace_resource(&mb.image_name, "Image", im1.clone())
5019 .unwrap();
5020 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
5021 .unwrap();
5022 self.replace_resource(&mb.title_name, "Text", t1.clone())
5023 .unwrap();
5024 self.replace_resource(&mb.content_name, "Text", t2.clone())
5025 .unwrap();
5026 self.replace_resource(&format!("MessageBox{}Close", mb.name), "Switch", s.clone())
5027 .unwrap();
5028 match s.fill_resource_type.as_str() {
5029 "Image" => {
5030 self.replace_resource(
5031 &s.fill_resource_name,
5032 &s.fill_resource_type,
5033 fr.as_any().downcast_ref::<Image>().unwrap().clone(),
5034 )
5035 .unwrap();
5036 }
5037 "CustomRect" => {
5038 self.replace_resource(
5039 &s.fill_resource_name,
5040 &s.fill_resource_type,
5041 fr.as_any().downcast_ref::<CustomRect>().unwrap().clone(),
5042 )
5043 .unwrap();
5044 }
5045 &_ => {
5046 self.problem_report_custom(
5047 RustConstructorError::SwitchFillResourceMismatch {
5048 switch_name: s.name,
5049 fill_resource_name: s.fill_resource_name,
5050 fill_resource_type: s.fill_resource_type,
5051 },
5052 SeverityLevel::SevereWarning,
5053 self.problem_list.clone(),
5054 );
5055 continue;
5056 }
5057 };
5058 self.custom_rect(&format!("MessageBox{}", mb.name), ui, ctx, safe_mode)
5059 .unwrap();
5060 self.image(&mb.image_name.clone(), ui, ctx, safe_mode)
5061 .unwrap();
5062 self.text(&t1.name.clone(), ui, ctx, safe_mode).unwrap();
5063 self.text(&t2.name.clone(), ui, ctx, safe_mode).unwrap();
5064 self.switch(
5065 &format!("MessageBox{}Close", mb.name),
5066 ui,
5067 ctx,
5068 s.state == 0 && mb.exist,
5069 safe_mode,
5070 )
5071 .unwrap();
5072 let switch_data = self
5073 .check_switch_data(&format!("MessageBox{}Close", mb.name), safe_mode)
5074 .unwrap();
5075 if switch_data.last_time_clicked_index == 0
5076 && switch_data.state == 1
5077 && switch_data.switched
5078 {
5079 mb.exist = false;
5080 if cr.origin_position[0] + mb.speed >= 15_f32 {
5081 cr.origin_position[0] = 15_f32;
5082 } else {
5083 cr.origin_position[0] += mb.speed;
5084 };
5085 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
5086 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
5087 .unwrap();
5088 };
5089 if deleted {
5090 self.rust_constructor_resource.remove(
5091 self.rust_constructor_resource
5092 .iter()
5093 .position(|x| x.expose_type() == "Image" && x.name() == mb.image_name)
5094 .unwrap(),
5095 );
5096 self.rust_constructor_resource.remove(
5097 self.rust_constructor_resource
5098 .iter()
5099 .position(|x| {
5100 x.expose_type() == "CustomRect"
5101 && x.name() == format!("MessageBox{}", mb.name)
5102 })
5103 .unwrap(),
5104 );
5105 self.rust_constructor_resource.remove(
5106 self.rust_constructor_resource
5107 .iter()
5108 .position(|x| x.expose_type() == "Text" && x.name() == mb.title_name)
5109 .unwrap(),
5110 );
5111 self.rust_constructor_resource.remove(
5112 self.rust_constructor_resource
5113 .iter()
5114 .position(|x| x.expose_type() == "Text" && x.name() == mb.content_name)
5115 .unwrap(),
5116 );
5117 self.rust_constructor_resource.remove(
5118 self.rust_constructor_resource
5119 .iter()
5120 .position(|x| {
5121 x.expose_type() == "Switch"
5122 && x.name() == format!("MessageBox{}Close", mb.name)
5123 })
5124 .unwrap(),
5125 );
5126 self.rust_constructor_resource.remove(
5127 self.rust_constructor_resource
5128 .iter()
5129 .position(|x| {
5130 x.expose_type() == s.fill_resource_type
5131 && x.name() == s.fill_resource_name
5132 })
5133 .unwrap(),
5134 );
5135 self.rust_constructor_resource.remove(
5136 self.rust_constructor_resource
5137 .iter()
5138 .position(|x| {
5139 x.expose_type() == "SplitTime"
5140 && x.name() == format!("MessageBox{}Animation", mb.name)
5141 })
5142 .unwrap(),
5143 );
5144 if !mb.keep_existing {
5145 self.rust_constructor_resource.remove(
5146 self.rust_constructor_resource
5147 .iter()
5148 .position(|x| {
5149 x.expose_type() == "SplitTime"
5150 && x.name() == format!("MessageBox{}", mb.name)
5151 })
5152 .unwrap(),
5153 );
5154 };
5155 self.rust_constructor_resource.remove(
5156 self.rust_constructor_resource
5157 .iter()
5158 .position(|x| x.expose_type() == "MessageBox" && x.name() == mb.name)
5159 .unwrap(),
5160 );
5161 self.rust_constructor_resource.remove(
5162 self.rust_constructor_resource
5163 .iter()
5164 .position(|x| x.expose_type() == "MouseDetector" && x.name() == t1.name)
5165 .unwrap(),
5166 );
5167 self.rust_constructor_resource.remove(
5168 self.rust_constructor_resource
5169 .iter()
5170 .position(|x| x.expose_type() == "MouseDetector" && x.name() == t2.name)
5171 .unwrap(),
5172 );
5173 } else {
5174 offset += mb.size[1] + 15_f32;
5175 };
5176 }
5177 }
5178
5179 pub fn add_switch(
5181 &mut self,
5182 mut switch: Switch,
5183 fill_resource_name: &str,
5184 fill_resource_type: &str,
5185 text_name: &str,
5186 ) -> Result<(), RustConstructorError> {
5187 let mut count = 1;
5188 if switch.enable_hover_click_fill_resource[0] {
5189 count += 1;
5190 };
5191 if switch.enable_hover_click_fill_resource[1] {
5192 count += 1;
5193 };
5194 if switch.appearance.len() < count {
5195 self.problem_report_custom(
5196 RustConstructorError::SwitchAppearanceMismatch {
5197 switch_name: switch.name.clone(),
5198 differ: count as u32 - switch.appearance.len() as u32,
5199 },
5200 SeverityLevel::SevereWarning,
5201 self.problem_list.clone(),
5202 );
5203 return Err(RustConstructorError::SwitchAppearanceMismatch {
5204 switch_name: switch.name.clone(),
5205 differ: count as u32 - switch.appearance.len() as u32,
5206 });
5207 };
5208 for _ in 0..switch.appearance.len() % count {
5209 switch.appearance.pop();
5210 }
5211 switch.text_name = "".to_string();
5212 if self.check_resource_exists(text_name, "Text") {
5213 let t = self.get_resource_mut::<Text>(text_name, "Text").unwrap();
5214 switch.text_name = text_name.to_string();
5215 switch.text_origin_position = t.origin_position;
5216 t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
5217 t.x_grid = [0, 0];
5218 t.y_grid = [0, 0];
5219 } else if !text_name.is_empty() {
5220 self.problem_report_custom(
5221 RustConstructorError::TextNotFound {
5222 text_name: text_name.to_string(),
5223 },
5224 SeverityLevel::SevereWarning,
5225 self.problem_list.clone(),
5226 );
5227 };
5228 if self.check_resource_exists(fill_resource_name, fill_resource_type) {
5229 match fill_resource_type {
5230 "Image" | "CustomRect" => {
5231 switch.fill_resource_name = fill_resource_name.to_string();
5232 switch.fill_resource_type = fill_resource_type.to_string();
5233 }
5234 &_ => {
5235 self.problem_report_custom(
5236 RustConstructorError::SwitchFillResourceMismatch {
5237 switch_name: switch.name.clone(),
5238 fill_resource_name: fill_resource_name.to_string(),
5239 fill_resource_type: fill_resource_type.to_string(),
5240 },
5241 SeverityLevel::SevereWarning,
5242 self.problem_list.clone(),
5243 );
5244 return Err(RustConstructorError::SwitchFillResourceMismatch {
5245 switch_name: switch.name.clone(),
5246 fill_resource_name: fill_resource_name.to_string(),
5247 fill_resource_type: fill_resource_type.to_string(),
5248 });
5249 }
5250 };
5251 } else {
5252 self.problem_report_custom(
5253 RustConstructorError::ResourceNotFound {
5254 resource_name: fill_resource_name.to_string(),
5255 resource_type: fill_resource_type.to_string(),
5256 },
5257 SeverityLevel::SevereWarning,
5258 self.problem_list.clone(),
5259 );
5260 return Err(RustConstructorError::ResourceNotFound {
5261 resource_name: fill_resource_name.to_string(),
5262 resource_type: fill_resource_type.to_string(),
5263 });
5264 };
5265 switch.hint_text_name = String::new();
5266 if switch
5267 .appearance
5268 .iter()
5269 .filter(|x| !x.hint_text.is_empty())
5270 .count()
5271 > 0
5272 {
5273 switch.hint_text_name = format!("{}Hint", switch.name);
5274 self.add_text(
5275 Text::default()
5276 .name(&format!("{}Hint", switch.name))
5277 .content("")
5278 .origin_position(0_f32, 0_f32)
5279 .font_size(25_f32)
5280 .wrap_width(300_f32)
5281 .background_rounding(10_f32)
5282 .color(255, 255, 255, 0)
5283 .background_color(0, 0, 0, 255)
5284 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
5285 .selectable(false),
5286 );
5287 self.add_split_time(
5288 SplitTime::default().name(&format!("{}StartHoverTime", switch.name)),
5289 );
5290 self.add_split_time(
5291 SplitTime::default().name(&format!("{}HintFadeAnimation", switch.name)),
5292 );
5293 };
5294 switch.state = 0;
5295 switch.animation_count = count as u32;
5296 self.rust_constructor_resource.push(Box::new(switch));
5297 Ok(())
5298 }
5299
5300 pub fn switch(
5302 &mut self,
5303 name: &str,
5304 ui: &mut Ui,
5305 ctx: &Context,
5306 enable: bool,
5307 safe_mode: Option<bool>,
5308 ) -> Result<(), RustConstructorError> {
5309 let mut appearance_count = 0;
5310 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5311 && !self.check_resource_exists(name, "Switch")
5312 {
5313 self.problem_report_custom(
5314 RustConstructorError::SwitchNotFound {
5315 switch_name: name.to_string(),
5316 },
5317 SeverityLevel::SevereWarning,
5318 self.problem_list.clone(),
5319 );
5320 return Err(RustConstructorError::SwitchNotFound {
5321 switch_name: name.to_string(),
5322 });
5323 };
5324 let mut s = self.get_resource::<Switch>(name, "Switch").unwrap().clone();
5325 s.switched = false;
5326 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
5327 if !self.check_resource_exists(&s.fill_resource_name.clone(), &s.fill_resource_type) {
5328 self.problem_report_custom(
5329 RustConstructorError::ResourceNotFound {
5330 resource_name: s.fill_resource_name.clone(),
5331 resource_type: s.fill_resource_type.clone(),
5332 },
5333 SeverityLevel::SevereWarning,
5334 self.problem_list.clone(),
5335 );
5336 return Err(RustConstructorError::ResourceNotFound {
5337 resource_name: s.fill_resource_name,
5338 resource_type: s.fill_resource_type,
5339 });
5340 };
5341 if !s.hint_text_name.is_empty() {
5342 if !self.check_resource_exists(&format!("{}StartHoverTime", s.name), "SplitTime") {
5343 self.problem_report_custom(
5344 RustConstructorError::SplitTimeNotFound {
5345 split_time_name: format!("{}StartHoverTime", s.name),
5346 },
5347 SeverityLevel::MildWarning,
5348 self.problem_list.clone(),
5349 );
5350 self.add_split_time(
5351 SplitTime::default().name(&format!("{}StartHoverTime", s.name)),
5352 );
5353 };
5354 if !self.check_resource_exists(&format!("{}HintFadeAnimation", s.name), "SplitTime")
5355 {
5356 self.problem_report_custom(
5357 RustConstructorError::SplitTimeNotFound {
5358 split_time_name: format!("{}HintFadeAnimation", s.name),
5359 },
5360 SeverityLevel::MildWarning,
5361 self.problem_list.clone(),
5362 );
5363 self.add_split_time(
5364 SplitTime::default().name(&format!("{}HintFadeAnimation", s.name)),
5365 );
5366 };
5367 if !self.check_resource_exists(&s.hint_text_name, "Text") {
5368 self.problem_report_custom(
5369 RustConstructorError::TextNotFound {
5370 text_name: s.hint_text_name.clone(),
5371 },
5372 SeverityLevel::MildWarning,
5373 self.problem_list.clone(),
5374 );
5375 self.add_text(
5376 Text::default()
5377 .name(&s.hint_text_name)
5378 .content("")
5379 .origin_position(0_f32, 0_f32)
5380 .font_size(25_f32)
5381 .wrap_width(300_f32)
5382 .background_rounding(10_f32)
5383 .color(255, 255, 255, 0)
5384 .background_color(0, 0, 0, 255)
5385 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
5386 .selectable(false),
5387 );
5388 };
5389 };
5390 };
5391 let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
5392 "Image" => Box::new(
5393 self.get_resource::<Image>(&s.fill_resource_name.clone(), &s.fill_resource_type)
5394 .unwrap()
5395 .clone(),
5396 ),
5397 "CustomRect" => Box::new(
5398 self.get_resource::<CustomRect>(
5399 &s.fill_resource_name.clone(),
5400 &s.fill_resource_type,
5401 )
5402 .unwrap()
5403 .clone(),
5404 ),
5405 &_ => {
5406 self.problem_report_custom(
5407 RustConstructorError::SwitchFillResourceMismatch {
5408 switch_name: name.to_string(),
5409 fill_resource_name: s.fill_resource_name.clone(),
5410 fill_resource_type: s.fill_resource_type.clone(),
5411 },
5412 SeverityLevel::SevereWarning,
5413 self.problem_list.clone(),
5414 );
5415 return Err(RustConstructorError::SwitchFillResourceMismatch {
5416 switch_name: name.to_string(),
5417 fill_resource_name: s.fill_resource_name,
5418 fill_resource_type: s.fill_resource_type,
5419 });
5420 }
5421 };
5422 s.reg_render_resource(&mut self.render_resource_list);
5423 let rect = Rect::from_min_size(
5424 Pos2::new(fr.position()[0], fr.position()[1]),
5425 Vec2::new(fr.size()[0], fr.size()[1]),
5426 );
5427 let mut hovered = false;
5428 if enable {
5429 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
5430 if rect.contains(mouse_pos) {
5432 if !s.hint_text_name.is_empty() {
5433 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5434 && !self.check_resource_exists(&s.hint_text_name, "Text")
5435 {
5436 self.problem_report_custom(
5437 RustConstructorError::TextNotFound {
5438 text_name: s.hint_text_name.clone(),
5439 },
5440 SeverityLevel::SevereWarning,
5441 self.problem_list.clone(),
5442 );
5443 return Err(RustConstructorError::TextNotFound {
5444 text_name: s.hint_text_name.clone(),
5445 });
5446 };
5447 let mut t = self
5448 .get_resource::<Text>(&s.hint_text_name, "Text")
5449 .unwrap()
5450 .clone();
5451 if !s.last_time_hovered {
5452 self.reset_split_time(&format!("{}StartHoverTime", s.name), safe_mode)
5453 .unwrap();
5454 } else if self.timer.total_time
5455 - self
5456 .split_time(&format!("{}StartHoverTime", s.name), safe_mode)
5457 .unwrap()[1]
5458 >= 2_f32
5459 || t.color[3] != 0
5460 {
5461 t.color[3] = 255;
5462 t.origin_position = [mouse_pos.x, mouse_pos.y];
5463 };
5464 t.center_display.0 =
5465 if mouse_pos.x + t.size[0] <= ctx.available_rect().width() {
5466 HorizontalAlign::Left
5467 } else {
5468 HorizontalAlign::Right
5469 };
5470 t.center_display.1 =
5471 if mouse_pos.y + t.size[1] <= ctx.available_rect().height() {
5472 VerticalAlign::Top
5473 } else {
5474 VerticalAlign::Bottom
5475 };
5476 self.replace_resource(&s.hint_text_name, "Text", t.clone())
5477 .unwrap();
5478 };
5479 hovered = true;
5480 let mut clicked = vec![];
5481 for u in 0..s.click_method.len() as u32 {
5482 clicked.push(ui.input(|i| {
5483 i.pointer
5484 .button_down(s.click_method[u as usize].click_method)
5485 }));
5486 if clicked[u as usize] {
5487 s.last_time_clicked_index = u as usize;
5488 break;
5489 };
5490 }
5491 if clicked.iter().any(|x| *x) {
5492 s.last_time_clicked = true;
5493 if s.enable_hover_click_fill_resource[1] {
5494 if s.enable_hover_click_fill_resource[0] {
5495 appearance_count = 2;
5496 } else {
5497 appearance_count = 1;
5498 };
5499 } else if !s.enable_hover_click_fill_resource[0] {
5500 appearance_count = 0;
5501 };
5502 } else {
5503 if s.last_time_clicked {
5504 s.switched = true;
5505 if s.click_method[s.last_time_clicked_index].action {
5506 if s.state
5507 < (s.appearance.len() / s.animation_count as usize - 1) as u32
5508 {
5509 s.state += 1;
5510 } else {
5511 s.state = 0;
5512 };
5513 };
5514 s.last_time_clicked = false;
5515 };
5516 if s.enable_hover_click_fill_resource[0] {
5517 appearance_count = 1;
5518 } else {
5519 appearance_count = 0;
5520 };
5521 };
5522 } else {
5523 s.last_time_clicked = false;
5524 appearance_count = 0;
5525 };
5526 } else {
5527 s.last_time_clicked = false;
5528 appearance_count = 0;
5529 };
5530 } else {
5531 s.last_time_clicked = false;
5532 appearance_count = 0;
5533 };
5534 if !hovered && !s.hint_text_name.is_empty() {
5535 if s.last_time_hovered {
5536 self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5537 .unwrap();
5538 };
5539 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5540 && !self.check_resource_exists(&s.hint_text_name, "Text")
5541 {
5542 self.problem_report_custom(
5543 RustConstructorError::TextNotFound {
5544 text_name: s.hint_text_name.clone(),
5545 },
5546 SeverityLevel::SevereWarning,
5547 self.problem_list.clone(),
5548 );
5549 return Err(RustConstructorError::TextNotFound {
5550 text_name: s.hint_text_name.clone(),
5551 });
5552 };
5553 let mut t = self
5554 .get_resource::<Text>(&s.hint_text_name, "Text")
5555 .unwrap()
5556 .clone();
5557 if self.timer.total_time
5558 - self
5559 .split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5560 .unwrap()[1]
5561 >= self.tick_interval
5562 {
5563 self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5564 .unwrap();
5565 t.color[3] = t.color[3].saturating_sub(10);
5566 };
5567 self.replace_resource(&s.hint_text_name, "Text", t.clone())
5568 .unwrap();
5569 };
5570 let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
5571 "Image" => {
5572 let mut im = Box::new(
5573 fr.as_any()
5574 .downcast_ref::<Image>()
5575 .unwrap()
5576 .clone()
5577 .from_config(
5578 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5579 .image_config
5580 .clone(),
5581 ),
5582 );
5583 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5584 && !self.check_resource_exists(
5585 &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5586 .texture
5587 .clone(),
5588 "ImageTexture",
5589 )
5590 {
5591 self.problem_report_custom(
5592 RustConstructorError::ImageTextureNotFound {
5593 image_texture_name: s.appearance
5594 [(s.state * s.animation_count + appearance_count) as usize]
5595 .texture
5596 .clone(),
5597 },
5598 SeverityLevel::SevereWarning,
5599 self.problem_list.clone(),
5600 );
5601 return Err(RustConstructorError::ImageTextureNotFound {
5602 image_texture_name: s.appearance
5603 [(s.state * s.animation_count + appearance_count) as usize]
5604 .texture
5605 .clone(),
5606 });
5607 };
5608 im.cite_texture = s.appearance
5609 [(s.state * s.animation_count + appearance_count) as usize]
5610 .texture
5611 .clone();
5612 im
5613 }
5614 "CustomRect" => Box::new(
5615 fr.as_any()
5616 .downcast_ref::<CustomRect>()
5617 .unwrap()
5618 .clone()
5619 .name(&s.fill_resource_name)
5620 .from_config(
5621 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5622 .custom_rect_config
5623 .clone(),
5624 ),
5625 ),
5626 &_ => {
5627 self.problem_report_custom(
5628 RustConstructorError::SwitchFillResourceMismatch {
5629 switch_name: name.to_string(),
5630 fill_resource_name: s.fill_resource_name.clone(),
5631 fill_resource_type: s.fill_resource_type.clone(),
5632 },
5633 SeverityLevel::SevereWarning,
5634 self.problem_list.clone(),
5635 );
5636 return Err(RustConstructorError::SwitchFillResourceMismatch {
5637 switch_name: name.to_string(),
5638 fill_resource_name: s.fill_resource_name,
5639 fill_resource_type: s.fill_resource_type,
5640 });
5641 }
5642 };
5643 if !s.hint_text_name.is_empty() {
5644 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5645 && !self.check_resource_exists(&s.hint_text_name, "Text")
5646 {
5647 self.problem_report_custom(
5648 RustConstructorError::TextNotFound {
5649 text_name: s.hint_text_name.clone(),
5650 },
5651 SeverityLevel::SevereWarning,
5652 self.problem_list.clone(),
5653 );
5654 return Err(RustConstructorError::TextNotFound {
5655 text_name: s.hint_text_name,
5656 });
5657 };
5658 let mut t = self
5659 .get_resource::<Text>(&s.hint_text_name, "Text")
5660 .unwrap()
5661 .clone();
5662 t.background_color[3] = t.color[3];
5663 t.content = s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5664 .hint_text
5665 .clone();
5666 self.replace_resource(&s.hint_text_name, "Text", t.clone())
5667 .unwrap();
5668 };
5669 s.last_time_hovered = hovered;
5670 self.replace_resource(name, "Switch", s.clone()).unwrap();
5671 match s.fill_resource_type.as_str() {
5672 "Image" => {
5673 let im = fr.as_any().downcast_ref::<Image>().unwrap().clone();
5674 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, im)
5675 .unwrap();
5676 self.image(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5677 .unwrap();
5678 }
5679 "CustomRect" => {
5680 let cr = fr.as_any().downcast_ref::<CustomRect>().unwrap().clone();
5681 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, cr)
5682 .unwrap();
5683 self.custom_rect(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5684 .unwrap();
5685 }
5686 &_ => {}
5687 };
5688 s.text_origin_position = s.appearance
5689 [(s.state * s.animation_count + appearance_count) as usize]
5690 .text_config
5691 .origin_position;
5692 if !s.text_name.is_empty() {
5693 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5694 && !self.check_resource_exists(&s.text_name, "Text")
5695 {
5696 self.problem_report_custom(
5697 RustConstructorError::TextNotFound {
5698 text_name: s.text_name.clone(),
5699 },
5700 SeverityLevel::SevereWarning,
5701 self.problem_list.clone(),
5702 );
5703 return Err(RustConstructorError::TextNotFound {
5704 text_name: s.text_name,
5705 });
5706 };
5707 let mut t = self
5708 .get_resource::<Text>(&s.text_name, "Text")
5709 .unwrap()
5710 .clone();
5711 t.origin_position = [
5712 fr.position()[0] + s.text_origin_position[0],
5713 fr.position()[1] + s.text_origin_position[1],
5714 ];
5715 t = t.from_config(
5716 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5717 .text_config
5718 .clone(),
5719 );
5720 self.replace_resource(&s.text_name, "Text", t.clone())
5721 .unwrap();
5722 self.text(&s.text_name, ui, ctx, safe_mode).unwrap();
5723 };
5724 if !s.hint_text_name.is_empty() {
5725 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5726 && !self.check_resource_exists(&s.hint_text_name, "Text")
5727 {
5728 self.problem_report_custom(
5729 RustConstructorError::TextNotFound {
5730 text_name: s.hint_text_name.clone(),
5731 },
5732 SeverityLevel::SevereWarning,
5733 self.problem_list.clone(),
5734 );
5735 return Err(RustConstructorError::TextNotFound {
5736 text_name: s.hint_text_name,
5737 });
5738 };
5739 self.text(&s.hint_text_name, ui, ctx, safe_mode).unwrap();
5740 };
5741 Ok(())
5742 }
5743
5744 pub fn check_switch_data(
5746 &self,
5747 name: &str,
5748 safe_mode: Option<bool>,
5749 ) -> Result<SwitchData, RustConstructorError> {
5750 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5751 && !self.check_resource_exists(name, "Switch")
5752 {
5753 self.problem_report_custom(
5754 RustConstructorError::SwitchNotFound {
5755 switch_name: name.to_string(),
5756 },
5757 SeverityLevel::SevereWarning,
5758 self.problem_list.clone(),
5759 );
5760 return Err(RustConstructorError::SwitchNotFound {
5761 switch_name: name.to_string(),
5762 });
5763 };
5764 let s = self.get_resource::<Switch>(name, "Switch").unwrap();
5765 Ok(SwitchData {
5766 switched: s.switched,
5767 last_time_clicked_index: s.last_time_clicked_index,
5768 state: s.state,
5769 })
5770 }
5771
5772 pub fn add_mouse_detector(&mut self, mouse_detector: MouseDetector) {
5774 self.rust_constructor_resource
5775 .push(Box::new(mouse_detector));
5776 }
5777
5778 pub fn mouse_detector(
5779 &mut self,
5780 name: &str,
5781 ui: &Ui,
5782 ctx: &Context,
5783 mouse_detector_level: MouseDetectorLevel,
5784 safe_mode: Option<bool>,
5785 ) -> Result<(), RustConstructorError> {
5786 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5787 && !self.check_resource_exists(name, "MouseDetector")
5788 {
5789 self.problem_report_custom(
5790 RustConstructorError::MouseDetectorNotFound {
5791 mouse_detector_name: name.to_string(),
5792 },
5793 SeverityLevel::SevereWarning,
5794 self.problem_list.clone(),
5795 );
5796 return Err(RustConstructorError::MouseDetectorNotFound {
5797 mouse_detector_name: name.to_string(),
5798 });
5799 };
5800 let md = self
5801 .get_resource_mut::<MouseDetector>(name, "MouseDetector")
5802 .unwrap();
5803 md.position[0] = match md.x_grid[1] {
5804 0 => md.origin_position[0],
5805 _ => {
5806 (ctx.available_rect().width() as f64 / md.x_grid[1] as f64 * md.x_grid[0] as f64)
5807 as f32
5808 + md.origin_position[0]
5809 }
5810 };
5811 md.position[1] = match md.y_grid[1] {
5812 0 => md.origin_position[1],
5813 _ => {
5814 (ctx.available_rect().height() as f64 / md.y_grid[1] as f64 * md.y_grid[0] as f64)
5815 as f32
5816 + md.origin_position[1]
5817 }
5818 };
5819 match md.center_display.0 {
5820 HorizontalAlign::Left => {}
5821 HorizontalAlign::Center => md.position[0] -= md.size[0] / 2.0,
5822 HorizontalAlign::Right => md.position[0] -= md.size[0],
5823 };
5824 match md.center_display.1 {
5825 VerticalAlign::Top => {}
5826 VerticalAlign::Center => md.position[1] -= md.size[1] / 2.0,
5827 VerticalAlign::Bottom => md.position[1] -= md.size[1],
5828 };
5829 md.position[0] += md.offset[0];
5830 md.position[1] += md.offset[1];
5831 let rect = Rect::from_min_max(
5832 Pos2::new(md.position[0], md.position[1]),
5833 Pos2::new(md.position[0] + md.size[0], md.position[1] + md.size[1]),
5834 );
5835 let response = ui.interact(rect, Id::new(name), Sense::click_and_drag());
5836 md.detect_result = match mouse_detector_level {
5837 MouseDetectorLevel::Lite => MouseDetectResult {
5838 clicked: response.clicked(),
5839 contains_pointer: response.contains_pointer(),
5840 secondary_clicked: None,
5841 middle_clicked: None,
5842 clicked_by_extra_button: None,
5843 long_touched: None,
5844 double_clicked: None,
5845 triple_clicked: None,
5846 double_clicked_by: None,
5847 triple_clicked_by: None,
5848 clicked_elsewhere: None,
5849 hovered: None,
5850 drag_started: None,
5851 drag_started_by: None,
5852 dragged: None,
5853 dragged_by: None,
5854 drag_stopped: None,
5855 deag_stopped_by: None,
5856 drag_delta: None,
5857 total_drag_delta: None,
5858 drag_motion: None,
5859 interact_pointer_pos: None,
5860 hover_pos: None,
5861 is_pointer_button_down_on: None,
5862 },
5863 MouseDetectorLevel::Default => {
5864 let interact_hover_pos = response.interact_pointer_pos();
5865 let hover_pos = response.hover_pos();
5866 MouseDetectResult {
5867 clicked: response.clicked(),
5868 contains_pointer: response.contains_pointer(),
5869 secondary_clicked: Some(response.secondary_clicked()),
5870 middle_clicked: Some(response.middle_clicked()),
5871 clicked_by_extra_button: None,
5872 long_touched: None,
5873 double_clicked: Some(response.double_clicked()),
5874 triple_clicked: Some(response.triple_clicked()),
5875 double_clicked_by: None,
5876 triple_clicked_by: None,
5877 clicked_elsewhere: Some(response.clicked_elsewhere()),
5878 hovered: Some(response.hovered()),
5879 drag_started: Some(response.drag_started()),
5880 drag_started_by: None,
5881 dragged: Some(response.dragged()),
5882 dragged_by: None,
5883 drag_stopped: Some(response.drag_stopped()),
5884 deag_stopped_by: None,
5885 drag_delta: None,
5886 total_drag_delta: None,
5887 drag_motion: None,
5888 interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5889 Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5890 } else {
5891 Some(None)
5892 },
5893 hover_pos: if let Some(hover_pos) = hover_pos {
5894 Some(Some([hover_pos.x, hover_pos.y]))
5895 } else {
5896 Some(None)
5897 },
5898 is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5899 }
5900 }
5901 MouseDetectorLevel::Pro => {
5902 let interact_hover_pos = response.interact_pointer_pos();
5903 let hover_pos = response.hover_pos();
5904 let total_drag_delta = response.total_drag_delta();
5905 MouseDetectResult {
5906 clicked: response.clicked(),
5907 contains_pointer: response.contains_pointer(),
5908 secondary_clicked: Some(response.secondary_clicked()),
5909 middle_clicked: Some(response.middle_clicked()),
5910 clicked_by_extra_button: Some([
5911 response.clicked_by(PointerButton::Extra1),
5912 response.clicked_by(PointerButton::Extra2),
5913 ]),
5914 long_touched: Some(response.long_touched()),
5915 double_clicked: Some(response.double_clicked()),
5916 triple_clicked: Some(response.triple_clicked()),
5917 double_clicked_by: Some([
5918 response.double_clicked_by(PointerButton::Primary),
5919 response.double_clicked_by(PointerButton::Secondary),
5920 response.double_clicked_by(PointerButton::Middle),
5921 response.double_clicked_by(PointerButton::Extra1),
5922 response.double_clicked_by(PointerButton::Extra2),
5923 ]),
5924 triple_clicked_by: Some([
5925 response.triple_clicked_by(PointerButton::Primary),
5926 response.triple_clicked_by(PointerButton::Secondary),
5927 response.triple_clicked_by(PointerButton::Middle),
5928 response.triple_clicked_by(PointerButton::Extra1),
5929 response.triple_clicked_by(PointerButton::Extra2),
5930 ]),
5931 clicked_elsewhere: Some(response.clicked_elsewhere()),
5932 hovered: Some(response.hovered()),
5933 drag_started: Some(response.drag_started()),
5934 drag_started_by: Some([
5935 response.drag_started_by(PointerButton::Primary),
5936 response.drag_started_by(PointerButton::Secondary),
5937 response.drag_started_by(PointerButton::Middle),
5938 response.drag_started_by(PointerButton::Extra1),
5939 response.drag_started_by(PointerButton::Extra2),
5940 ]),
5941 dragged: Some(response.dragged()),
5942 dragged_by: Some([
5943 response.dragged_by(PointerButton::Primary),
5944 response.dragged_by(PointerButton::Secondary),
5945 response.dragged_by(PointerButton::Middle),
5946 response.dragged_by(PointerButton::Extra1),
5947 response.dragged_by(PointerButton::Extra2),
5948 ]),
5949 drag_stopped: Some(response.drag_stopped()),
5950 deag_stopped_by: Some([
5951 response.drag_stopped_by(PointerButton::Primary),
5952 response.drag_stopped_by(PointerButton::Secondary),
5953 response.drag_stopped_by(PointerButton::Middle),
5954 response.drag_stopped_by(PointerButton::Extra1),
5955 response.drag_stopped_by(PointerButton::Extra2),
5956 ]),
5957 drag_delta: Some([response.drag_delta().x, response.drag_delta().y]),
5958 total_drag_delta: if let Some(total_drag_delta) = total_drag_delta {
5959 Some(Some([total_drag_delta.x, total_drag_delta.y]))
5960 } else {
5961 Some(None)
5962 },
5963 drag_motion: Some([response.drag_motion().x, response.drag_motion().y]),
5964 interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5965 Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5966 } else {
5967 Some(None)
5968 },
5969 hover_pos: if let Some(hover_pos) = hover_pos {
5970 Some(Some([hover_pos.x, hover_pos.y]))
5971 } else {
5972 Some(None)
5973 },
5974 is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5975 }
5976 }
5977 };
5978 Ok(())
5979 }
5980
5981 pub fn check_mouse_detect_result(
5982 &self,
5983 name: &str,
5984 safe_mode: Option<bool>,
5985 ) -> Result<MouseDetectResult, RustConstructorError> {
5986 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5987 && !self.check_resource_exists(name, "MouseDetector")
5988 {
5989 self.problem_report_custom(
5990 RustConstructorError::MouseDetectorNotFound {
5991 mouse_detector_name: name.to_string(),
5992 },
5993 SeverityLevel::SevereWarning,
5994 self.problem_list.clone(),
5995 );
5996 return Err(RustConstructorError::MouseDetectorNotFound {
5997 mouse_detector_name: name.to_string(),
5998 });
5999 };
6000 let md = self
6001 .get_resource::<MouseDetector>(name, "MouseDetector")
6002 .unwrap();
6003 Ok(md.detect_result.clone())
6004 }
6005}