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 struct ReportState {
235 pub current_page: String,
237 pub current_total_runtime: f32,
239 pub current_page_runtime: f32,
241}
242
243#[derive(Debug, Clone, PartialEq, PartialOrd)]
245pub struct Problem {
246 pub severity_level: SeverityLevel,
248 pub problem: String,
250 pub annotation: String,
252 pub report_state: ReportState,
254 pub problem_type: RustConstructorError,
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
260pub enum SeverityLevel {
261 MildWarning,
263 SevereWarning,
265 Error,
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
271pub struct PageData {
272 pub discern_type: String,
273 pub name: String,
274 pub forced_update: bool,
276 pub change_page_updated: bool,
278 pub enter_page_updated: bool,
280}
281
282impl RustConstructorResource for PageData {
283 fn name(&self) -> &str {
284 &self.name
285 }
286
287 fn expose_type(&self) -> &str {
288 &self.discern_type
289 }
290
291 fn as_any(&self) -> &dyn Any {
292 self
293 }
294
295 fn as_any_mut(&mut self) -> &mut dyn Any {
296 self
297 }
298}
299
300impl Default for PageData {
301 fn default() -> Self {
302 PageData {
303 discern_type: String::from("PageData"),
304 name: String::from("PageData"),
305 forced_update: true,
306 change_page_updated: false,
307 enter_page_updated: false,
308 }
309 }
310}
311
312impl PageData {
313 #[inline]
314 pub fn name(mut self, name: &str) -> Self {
315 self.name = name.to_string();
316 self
317 }
318
319 #[inline]
320 pub fn forced_update(mut self, forced_update: bool) -> Self {
321 self.forced_update = forced_update;
322 self
323 }
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
328pub struct Timer {
329 pub start_time: f32,
331 pub total_time: f32,
333 pub timer: Instant,
335 pub now_time: f32,
337}
338
339impl Default for Timer {
340 fn default() -> Self {
341 Timer {
342 start_time: 0_f32,
343 total_time: 0_f32,
344 timer: Instant::now(),
345 now_time: 0_f32,
346 }
347 }
348}
349
350#[derive(Clone, PartialEq, Eq, Hash)]
352pub struct DebugTextureHandle(TextureHandle);
353
354impl Debug for DebugTextureHandle {
355 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
356 f.debug_struct("DebugTextureHandle").finish()
358 }
359}
360
361impl DebugTextureHandle {
362 pub fn new(texture_handle: TextureHandle) -> Self {
363 Self(texture_handle)
364 }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
369pub struct ImageTexture {
370 pub discern_type: String,
371 pub name: String,
372 pub texture: Option<DebugTextureHandle>,
374 pub cite_path: String,
376}
377
378impl RustConstructorResource for ImageTexture {
379 fn name(&self) -> &str {
380 &self.name
381 }
382
383 fn expose_type(&self) -> &str {
384 &self.discern_type
385 }
386
387 fn as_any(&self) -> &dyn Any {
388 self
389 }
390
391 fn as_any_mut(&mut self) -> &mut dyn Any {
392 self
393 }
394}
395
396impl Default for ImageTexture {
397 fn default() -> Self {
398 ImageTexture {
399 discern_type: String::from("ImageTexture"),
400 name: String::from("ImageTexture"),
401 texture: None,
402 cite_path: String::from(""),
403 }
404 }
405}
406
407impl ImageTexture {
408 #[inline]
409 pub fn name(mut self, name: &str) -> Self {
410 self.name = name.to_string();
411 self
412 }
413}
414
415#[derive(Debug, Clone, PartialEq, PartialOrd)]
417pub struct CustomRectConfig {
418 pub size: [f32; 2],
420 pub rounding: f32,
422 pub x_grid: [u32; 2],
424 pub y_grid: [u32; 2],
426 pub center_display: (HorizontalAlign, VerticalAlign),
428 pub offset: [f32; 2],
430 pub color: [u8; 4],
432 pub border_width: f32,
434 pub border_color: [u8; 4],
436 pub origin_position: [f32; 2],
438}
439
440impl Default for CustomRectConfig {
441 fn default() -> Self {
442 Self {
443 size: [100_f32, 100_f32],
444 rounding: 2_f32,
445 x_grid: [0, 0],
446 y_grid: [0, 0],
447 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
448 offset: [0_f32, 0_f32],
449 color: [255, 255, 255, 255],
450 border_width: 2_f32,
451 border_color: [0, 0, 0, 255],
452 origin_position: [0_f32, 0_f32],
453 }
454 }
455}
456
457impl CustomRectConfig {
458 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
459 self.origin_position = position_config.origin_position;
460 self.size = position_config.size;
461 self.x_grid = position_config.x_grid;
462 self.y_grid = position_config.y_grid;
463 self.center_display = position_config.center_display;
464 self.offset = position_config.offset;
465 self
466 }
467
468 pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
469 Self {
470 size: custom_rect.size,
471 rounding: custom_rect.rounding,
472 x_grid: custom_rect.x_grid,
473 y_grid: custom_rect.y_grid,
474 center_display: custom_rect.center_display,
475 offset: custom_rect.offset,
476 color: custom_rect.color,
477 border_width: custom_rect.border_width,
478 border_color: custom_rect.border_color,
479 origin_position: custom_rect.origin_position,
480 }
481 }
482
483 #[inline]
484 pub fn size(mut self, width: f32, height: f32) -> Self {
485 self.size = [width, height];
486 self
487 }
488
489 #[inline]
490 pub fn rounding(mut self, rounding: f32) -> Self {
491 self.rounding = rounding;
492 self
493 }
494
495 #[inline]
496 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
497 self.x_grid = [fetch, total];
498 self
499 }
500
501 #[inline]
502 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
503 self.y_grid = [fetch, total];
504 self
505 }
506
507 #[inline]
508 pub fn center_display(
509 mut self,
510 horizontal_align: HorizontalAlign,
511 vertical_align: VerticalAlign,
512 ) -> Self {
513 self.center_display = (horizontal_align, vertical_align);
514 self
515 }
516
517 #[inline]
518 pub fn offset(mut self, x: f32, y: f32) -> Self {
519 self.offset = [x, y];
520 self
521 }
522
523 #[inline]
524 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
525 self.color = [r, g, b, a];
526 self
527 }
528
529 #[inline]
530 pub fn border_width(mut self, border_width: f32) -> Self {
531 self.border_width = border_width;
532 self
533 }
534
535 #[inline]
536 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
537 self.border_color = [r, g, b, a];
538 self
539 }
540
541 #[inline]
542 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
543 self.origin_position = [x, y];
544 self
545 }
546}
547
548#[derive(Debug, Clone, PartialEq, PartialOrd)]
550pub struct CustomRect {
551 pub discern_type: String,
552 pub name: String,
553 pub position: [f32; 2],
555 pub size: [f32; 2],
557 pub rounding: f32,
559 pub x_grid: [u32; 2],
561 pub y_grid: [u32; 2],
563 pub center_display: (HorizontalAlign, VerticalAlign),
565 pub offset: [f32; 2],
567 pub color: [u8; 4],
569 pub border_width: f32,
571 pub border_color: [u8; 4],
573 pub origin_position: [f32; 2],
575}
576
577impl RustConstructorResource for CustomRect {
578 fn name(&self) -> &str {
579 &self.name
580 }
581
582 fn expose_type(&self) -> &str {
583 &self.discern_type
584 }
585
586 fn as_any(&self) -> &dyn Any {
587 self
588 }
589
590 fn as_any_mut(&mut self) -> &mut dyn Any {
591 self
592 }
593}
594
595impl BasicFrontResource for CustomRect {
596 fn position(&self) -> [f32; 2] {
597 self.position
598 }
599
600 fn size(&self) -> [f32; 2] {
601 self.size
602 }
603
604 fn modify_position(&mut self, x: f32, y: f32) {
605 self.origin_position = [x, y];
606 }
607
608 fn modify_size(&mut self, width: f32, height: f32) {
609 self.size = [width, height];
610 }
611
612 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
613 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
614 }
615}
616
617impl Default for CustomRect {
618 fn default() -> Self {
619 Self {
620 discern_type: String::from("CustomRect"),
621 name: String::from("CustomRect"),
622 position: [0_f32, 0_f32],
623 size: [100_f32, 100_f32],
624 rounding: 2_f32,
625 x_grid: [0, 0],
626 y_grid: [0, 0],
627 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
628 offset: [0_f32, 0_f32],
629 color: [255, 255, 255, 255],
630 border_width: 2_f32,
631 border_color: [0, 0, 0, 255],
632 origin_position: [0_f32, 0_f32],
633 }
634 }
635}
636
637impl CustomRect {
638 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
639 self.origin_position = position_config.origin_position;
640 self.size = position_config.size;
641 self.x_grid = position_config.x_grid;
642 self.y_grid = position_config.y_grid;
643 self.center_display = position_config.center_display;
644 self.offset = position_config.offset;
645 self
646 }
647
648 pub fn from_config(mut self, config: CustomRectConfig) -> Self {
649 self.size = config.size;
650 self.rounding = config.rounding;
651 self.x_grid = config.x_grid;
652 self.y_grid = config.y_grid;
653 self.center_display = config.center_display;
654 self.offset = config.offset;
655 self.color = config.color;
656 self.border_width = config.border_width;
657 self.border_color = config.border_color;
658 self.origin_position = config.origin_position;
659 self
660 }
661
662 #[inline]
663 pub fn name(mut self, name: &str) -> Self {
664 self.name = name.to_string();
665 self
666 }
667
668 #[inline]
669 pub fn size(mut self, width: f32, height: f32) -> Self {
670 self.size = [width, height];
671 self
672 }
673
674 #[inline]
675 pub fn rounding(mut self, rounding: f32) -> Self {
676 self.rounding = rounding;
677 self
678 }
679
680 #[inline]
681 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
682 self.x_grid = [fetch, total];
683 self
684 }
685
686 #[inline]
687 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
688 self.y_grid = [fetch, total];
689 self
690 }
691
692 #[inline]
693 pub fn center_display(
694 mut self,
695 horizontal_align: HorizontalAlign,
696 vertical_align: VerticalAlign,
697 ) -> Self {
698 self.center_display = (horizontal_align, vertical_align);
699 self
700 }
701
702 #[inline]
703 pub fn offset(mut self, x: f32, y: f32) -> Self {
704 self.offset = [x, y];
705 self
706 }
707
708 #[inline]
709 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
710 self.color = [r, g, b, a];
711 self
712 }
713
714 #[inline]
715 pub fn border_width(mut self, border_width: f32) -> Self {
716 self.border_width = border_width;
717 self
718 }
719
720 #[inline]
721 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
722 self.border_color = [r, g, b, a];
723 self
724 }
725
726 #[inline]
727 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
728 self.origin_position = [x, y];
729 self
730 }
731}
732
733#[derive(Debug, Clone, PartialEq, PartialOrd)]
735pub struct ImageConfig {
736 pub size: [f32; 2],
738 pub x_grid: [u32; 2],
740 pub y_grid: [u32; 2],
742 pub center_display: (HorizontalAlign, VerticalAlign),
744 pub offset: [f32; 2],
746 pub alpha: u8,
748 pub overlay_color: [u8; 4],
750 pub background_color: [u8; 4],
752 pub rotate_angle: f32,
754 pub rotate_center: [f32; 2],
756 pub origin_position: [f32; 2],
758 pub cite_texture: String,
760}
761
762impl Default for ImageConfig {
763 fn default() -> Self {
764 Self {
765 size: [100_f32, 100_f32],
766 x_grid: [0, 0],
767 y_grid: [0, 0],
768 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
769 offset: [0_f32, 0_f32],
770 alpha: 255,
771 overlay_color: [255, 255, 255, 255],
772 background_color: [0, 0, 0, 0],
773 rotate_angle: 0_f32,
774 rotate_center: [0_f32, 0_f32],
775 origin_position: [0_f32, 0_f32],
776 cite_texture: String::from("ImageTexture"),
777 }
778 }
779}
780
781impl ImageConfig {
782 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
783 self.origin_position = position_config.origin_position;
784 self.size = position_config.size;
785 self.x_grid = position_config.x_grid;
786 self.y_grid = position_config.y_grid;
787 self.center_display = position_config.center_display;
788 self.offset = position_config.offset;
789 self
790 }
791
792 pub fn from_image(image: Image) -> Self {
793 Self {
794 size: image.size,
795 x_grid: image.x_grid,
796 y_grid: image.y_grid,
797 center_display: image.center_display,
798 offset: image.offset,
799 alpha: image.alpha,
800 overlay_color: image.overlay_color,
801 background_color: image.background_color,
802 rotate_angle: image.rotate_angle,
803 rotate_center: image.rotate_center,
804 cite_texture: image.cite_texture,
805 origin_position: image.origin_position,
806 }
807 }
808
809 #[inline]
810 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
811 self.origin_position = [x, y];
812 self
813 }
814
815 #[inline]
816 pub fn size(mut self, width: f32, height: f32) -> Self {
817 self.size = [width, height];
818 self
819 }
820
821 #[inline]
822 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
823 self.x_grid = [fetch, total];
824 self
825 }
826
827 #[inline]
828 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
829 self.y_grid = [fetch, total];
830 self
831 }
832
833 #[inline]
834 pub fn center_display(
835 mut self,
836 horizontal_align: HorizontalAlign,
837 vertical_align: VerticalAlign,
838 ) -> Self {
839 self.center_display = (horizontal_align, vertical_align);
840 self
841 }
842
843 #[inline]
844 pub fn offset(mut self, x: f32, y: f32) -> Self {
845 self.offset = [x, y];
846 self
847 }
848
849 #[inline]
850 pub fn alpha(mut self, alpha: u8) -> Self {
851 self.alpha = alpha;
852 self
853 }
854
855 #[inline]
856 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
857 self.overlay_color = [r, g, b, a];
858 self
859 }
860
861 #[inline]
862 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
863 self.background_color = [r, g, b, a];
864 self
865 }
866
867 #[inline]
868 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
869 self.rotate_angle = rotate_angle;
870 self
871 }
872
873 #[inline]
874 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
875 self.rotate_center = [x, y];
876 self
877 }
878}
879
880#[derive(Debug, Clone, PartialEq)]
882pub struct Image {
883 pub discern_type: String,
884 pub name: String,
885 pub texture: Option<DebugTextureHandle>,
887 pub position: [f32; 2],
889 pub size: [f32; 2],
891 pub x_grid: [u32; 2],
893 pub y_grid: [u32; 2],
895 pub center_display: (HorizontalAlign, VerticalAlign),
897 pub offset: [f32; 2],
899 pub alpha: u8,
901 pub overlay_color: [u8; 4],
903 pub background_color: [u8; 4],
905 pub rotate_angle: f32,
907 pub rotate_center: [f32; 2],
909 pub origin_position: [f32; 2],
911 pub cite_texture: String,
913 pub last_frame_cite_texture: String,
915}
916
917impl RustConstructorResource for Image {
918 fn name(&self) -> &str {
919 &self.name
920 }
921
922 fn expose_type(&self) -> &str {
923 &self.discern_type
924 }
925
926 fn as_any(&self) -> &dyn Any {
927 self
928 }
929
930 fn as_any_mut(&mut self) -> &mut dyn Any {
931 self
932 }
933}
934
935impl BasicFrontResource for Image {
936 fn position(&self) -> [f32; 2] {
937 self.position
938 }
939
940 fn size(&self) -> [f32; 2] {
941 self.size
942 }
943
944 fn modify_position(&mut self, x: f32, y: f32) {
945 self.origin_position = [x, y];
946 }
947
948 fn modify_size(&mut self, width: f32, height: f32) {
949 self.size = [width, height];
950 }
951
952 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
953 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
954 }
955}
956
957impl Default for Image {
958 fn default() -> Self {
959 Self {
960 discern_type: String::from("Image"),
961 name: String::from("Image"),
962 texture: None,
963 position: [0_f32, 0_f32],
964 size: [100_f32, 100_f32],
965 x_grid: [0, 0],
966 y_grid: [0, 0],
967 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
968 offset: [0_f32, 0_f32],
969 alpha: 255,
970 overlay_color: [255, 255, 255, 255],
971 background_color: [0, 0, 0, 0],
972 rotate_angle: 0_f32,
973 rotate_center: [0_f32, 0_f32],
974 origin_position: [0_f32, 0_f32],
975 cite_texture: String::from("ImageTexture"),
976 last_frame_cite_texture: String::from("ImageTexture"),
977 }
978 }
979}
980
981impl Image {
982 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
983 self.origin_position = position_config.origin_position;
984 self.size = position_config.size;
985 self.x_grid = position_config.x_grid;
986 self.y_grid = position_config.y_grid;
987 self.center_display = position_config.center_display;
988 self.offset = position_config.offset;
989 self
990 }
991
992 pub fn from_config(mut self, config: ImageConfig) -> Self {
993 self.size = config.size;
994 self.x_grid = config.x_grid;
995 self.y_grid = config.y_grid;
996 self.center_display = config.center_display;
997 self.offset = config.offset;
998 self.alpha = config.alpha;
999 self.overlay_color = config.overlay_color;
1000 self.background_color = config.background_color;
1001 self.rotate_angle = config.rotate_angle;
1002 self.rotate_center = config.rotate_center;
1003 self.origin_position = config.origin_position;
1004 self.cite_texture = config.cite_texture;
1005 self
1006 }
1007
1008 #[inline]
1009 pub fn name(mut self, name: &str) -> Self {
1010 self.name = name.to_string();
1011 self
1012 }
1013
1014 #[inline]
1015 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1016 self.origin_position = [x, y];
1017 self
1018 }
1019
1020 #[inline]
1021 pub fn size(mut self, width: f32, height: f32) -> Self {
1022 self.size = [width, height];
1023 self
1024 }
1025
1026 #[inline]
1027 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1028 self.x_grid = [fetch, total];
1029 self
1030 }
1031
1032 #[inline]
1033 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1034 self.y_grid = [fetch, total];
1035 self
1036 }
1037
1038 #[inline]
1039 pub fn center_display(
1040 mut self,
1041 horizontal_align: HorizontalAlign,
1042 vertical_align: VerticalAlign,
1043 ) -> Self {
1044 self.center_display = (horizontal_align, vertical_align);
1045 self
1046 }
1047
1048 #[inline]
1049 pub fn offset(mut self, x: f32, y: f32) -> Self {
1050 self.offset = [x, y];
1051 self
1052 }
1053
1054 #[inline]
1055 pub fn alpha(mut self, alpha: u8) -> Self {
1056 self.alpha = alpha;
1057 self
1058 }
1059
1060 #[inline]
1061 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1062 self.overlay_color = [r, g, b, a];
1063 self
1064 }
1065
1066 #[inline]
1067 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1068 self.background_color = [r, g, b, a];
1069 self
1070 }
1071
1072 #[inline]
1073 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1074 self.rotate_angle = rotate_angle;
1075 self
1076 }
1077
1078 #[inline]
1079 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1080 self.rotate_center = [x, y];
1081 self
1082 }
1083}
1084
1085#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1087pub enum HyperlinkSelectMethod {
1088 All(String),
1090 Segment(Vec<(usize, String)>),
1092}
1093
1094#[derive(Debug, Clone, PartialEq, PartialOrd)]
1096pub struct TextConfig {
1097 pub content: String,
1099 pub font_size: f32,
1101 pub color: [u8; 4],
1103 pub center_display: (HorizontalAlign, VerticalAlign),
1105 pub offset: [f32; 2],
1107 pub wrap_width: f32,
1109 pub background_color: [u8; 4],
1111 pub background_rounding: f32,
1113 pub x_grid: [u32; 2],
1115 pub y_grid: [u32; 2],
1117 pub origin_position: [f32; 2],
1119 pub font: String,
1121 pub selectable: bool,
1123 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1125 pub size: [f32; 2],
1127}
1128
1129impl Default for TextConfig {
1130 fn default() -> Self {
1131 Self {
1132 content: String::from("Hello world"),
1133 font_size: 16_f32,
1134 color: [255, 255, 255, 255],
1135 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1136 offset: [0_f32, 0_f32],
1137 wrap_width: 200_f32,
1138 background_color: [0, 0, 0, 0],
1139 background_rounding: 2_f32,
1140 x_grid: [0, 0],
1141 y_grid: [0, 0],
1142 origin_position: [0_f32, 0_f32],
1143 font: String::new(),
1144 selectable: true,
1145 hyperlink_text: Vec::new(),
1146 size: [0_f32, 0_f32],
1147 }
1148 }
1149}
1150
1151impl TextConfig {
1152 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1153 self.origin_position = position_config.origin_position;
1154 self.wrap_width = position_config.size[0];
1155 self.x_grid = position_config.x_grid;
1156 self.y_grid = position_config.y_grid;
1157 self.center_display = position_config.center_display;
1158 self.offset = position_config.offset;
1159 self.size = position_config.size;
1160 self
1161 }
1162
1163 pub fn from_text(text: Text) -> Self {
1164 Self {
1165 content: text.content,
1166 font_size: text.font_size,
1167 color: text.color,
1168 center_display: text.center_display,
1169 offset: text.offset,
1170 wrap_width: text.wrap_width,
1171 background_color: text.background_color,
1172 background_rounding: text.background_rounding,
1173 x_grid: text.x_grid,
1174 y_grid: text.y_grid,
1175 origin_position: text.origin_position,
1176 font: text.font,
1177 selectable: text.selectable,
1178 hyperlink_text: text.hyperlink_text,
1179 size: text.size,
1180 }
1181 }
1182
1183 #[inline]
1184 pub fn content(mut self, content: &str) -> Self {
1185 self.content = content.to_string();
1186 self
1187 }
1188
1189 #[inline]
1190 pub fn font_size(mut self, font_size: f32) -> Self {
1191 self.font_size = font_size;
1192 self
1193 }
1194
1195 #[inline]
1196 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1197 self.color = [r, g, b, a];
1198 self
1199 }
1200
1201 #[inline]
1202 pub fn center_display(
1203 mut self,
1204 horizontal_align: HorizontalAlign,
1205 vertical_align: VerticalAlign,
1206 ) -> Self {
1207 self.center_display = (horizontal_align, vertical_align);
1208 self
1209 }
1210
1211 #[inline]
1212 pub fn offset(mut self, x: f32, y: f32) -> Self {
1213 self.offset = [x, y];
1214 self
1215 }
1216
1217 #[inline]
1218 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1219 self.wrap_width = wrap_width;
1220 self
1221 }
1222
1223 #[inline]
1224 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1225 self.background_color = [r, g, b, a];
1226 self
1227 }
1228
1229 #[inline]
1230 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1231 self.background_rounding = background_rounding;
1232 self
1233 }
1234
1235 #[inline]
1236 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1237 self.x_grid = [fetch, total];
1238 self
1239 }
1240
1241 #[inline]
1242 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1243 self.y_grid = [fetch, total];
1244 self
1245 }
1246
1247 #[inline]
1248 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1249 self.origin_position = [x, y];
1250 self
1251 }
1252
1253 #[inline]
1254 pub fn font(mut self, font: &str) -> Self {
1255 self.font = font.to_string();
1256 self
1257 }
1258
1259 #[inline]
1260 pub fn selectable(mut self, selectable: bool) -> Self {
1261 self.selectable = selectable;
1262 self
1263 }
1264
1265 #[inline]
1266 pub fn hyperlink_text(
1267 mut self,
1268 target_text: &str,
1269 select_method: HyperlinkSelectMethod,
1270 ) -> Self {
1271 self.hyperlink_text
1272 .push((target_text.to_string(), select_method));
1273 self
1274 }
1275}
1276
1277#[derive(Debug, Clone, PartialEq, PartialOrd)]
1279pub struct Text {
1280 pub discern_type: String,
1281 pub name: String,
1282 pub content: String,
1284 pub font_size: f32,
1286 pub color: [u8; 4],
1288 pub position: [f32; 2],
1290 pub center_display: (HorizontalAlign, VerticalAlign),
1292 pub offset: [f32; 2],
1294 pub wrap_width: f32,
1296 pub background_color: [u8; 4],
1298 pub background_rounding: f32,
1300 pub x_grid: [u32; 2],
1302 pub y_grid: [u32; 2],
1304 pub origin_position: [f32; 2],
1306 pub font: String,
1308 pub selection: Option<(usize, usize)>,
1310 pub selectable: bool,
1312 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1314 pub hyperlink_index: Vec<(usize, usize, String)>,
1316 pub last_frame_content: String,
1318 pub size: [f32; 2],
1320}
1321
1322impl RustConstructorResource for Text {
1323 fn name(&self) -> &str {
1324 &self.name
1325 }
1326
1327 fn expose_type(&self) -> &str {
1328 &self.discern_type
1329 }
1330
1331 fn as_any(&self) -> &dyn Any {
1332 self
1333 }
1334
1335 fn as_any_mut(&mut self) -> &mut dyn Any {
1336 self
1337 }
1338}
1339
1340impl BasicFrontResource for Text {
1341 fn position(&self) -> [f32; 2] {
1342 self.position
1343 }
1344
1345 fn size(&self) -> [f32; 2] {
1346 self.size
1347 }
1348
1349 fn modify_position(&mut self, x: f32, y: f32) {
1350 self.origin_position = [x, y];
1351 }
1352
1353 fn modify_size(&mut self, width: f32, height: f32) {
1354 self.wrap_width = width;
1355 self.size = [width, height];
1356 }
1357
1358 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
1359 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
1360 }
1361}
1362
1363impl Default for Text {
1364 fn default() -> Self {
1365 Self {
1366 discern_type: String::from("Text"),
1367 name: String::from("Text"),
1368 content: String::from("Hello world"),
1369 font_size: 16_f32,
1370 color: [255, 255, 255, 255],
1371 position: [0_f32, 0_f32],
1372 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1373 offset: [0_f32, 0_f32],
1374 wrap_width: 200_f32,
1375 background_color: [0, 0, 0, 0],
1376 background_rounding: 2_f32,
1377 x_grid: [0, 0],
1378 y_grid: [0, 0],
1379 origin_position: [0_f32, 0_f32],
1380 font: String::new(),
1381 selection: None,
1382 selectable: true,
1383 hyperlink_text: Vec::new(),
1384 hyperlink_index: Vec::new(),
1385 last_frame_content: String::from(""),
1386 size: [0_f32, 0_f32],
1387 }
1388 }
1389}
1390
1391impl Text {
1392 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1393 self.origin_position = position_config.origin_position;
1394 self.wrap_width = position_config.size[0];
1395 self.x_grid = position_config.x_grid;
1396 self.y_grid = position_config.y_grid;
1397 self.center_display = position_config.center_display;
1398 self.offset = position_config.offset;
1399 self.size = position_config.size;
1400 self
1401 }
1402
1403 pub fn from_config(mut self, config: TextConfig) -> Self {
1404 self.content = config.content;
1405 self.font_size = config.font_size;
1406 self.color = config.color;
1407 self.center_display = config.center_display;
1408 self.offset = config.offset;
1409 self.wrap_width = config.wrap_width;
1410 self.background_color = config.background_color;
1411 self.background_rounding = config.background_rounding;
1412 self.x_grid = config.x_grid;
1413 self.y_grid = config.y_grid;
1414 self.origin_position = config.origin_position;
1415 self.font = config.font;
1416 self.selectable = config.selectable;
1417 self.hyperlink_text = config.hyperlink_text;
1418 self.size = config.size;
1419 self
1420 }
1421
1422 #[inline]
1423 pub fn name(mut self, name: &str) -> Self {
1424 self.name = name.to_string();
1425 self
1426 }
1427
1428 #[inline]
1429 pub fn content(mut self, content: &str) -> Self {
1430 self.content = content.to_string();
1431 self
1432 }
1433
1434 #[inline]
1435 pub fn font_size(mut self, font_size: f32) -> Self {
1436 self.font_size = font_size;
1437 self
1438 }
1439
1440 #[inline]
1441 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1442 self.color = [r, g, b, a];
1443 self
1444 }
1445
1446 #[inline]
1447 pub fn center_display(
1448 mut self,
1449 horizontal_align: HorizontalAlign,
1450 vertical_align: VerticalAlign,
1451 ) -> Self {
1452 self.center_display = (horizontal_align, vertical_align);
1453 self
1454 }
1455
1456 #[inline]
1457 pub fn offset(mut self, x: f32, y: f32) -> Self {
1458 self.offset = [x, y];
1459 self
1460 }
1461
1462 #[inline]
1463 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1464 self.wrap_width = wrap_width;
1465 self
1466 }
1467
1468 #[inline]
1469 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1470 self.background_color = [r, g, b, a];
1471 self
1472 }
1473
1474 #[inline]
1475 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1476 self.background_rounding = background_rounding;
1477 self
1478 }
1479
1480 #[inline]
1481 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1482 self.x_grid = [fetch, total];
1483 self
1484 }
1485
1486 #[inline]
1487 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1488 self.y_grid = [fetch, total];
1489 self
1490 }
1491
1492 #[inline]
1493 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1494 self.origin_position = [x, y];
1495 self
1496 }
1497
1498 #[inline]
1499 pub fn font(mut self, font: &str) -> Self {
1500 self.font = font.to_string();
1501 self
1502 }
1503
1504 #[inline]
1505 pub fn selectable(mut self, selectable: bool) -> Self {
1506 self.selectable = selectable;
1507 self
1508 }
1509
1510 #[inline]
1511 pub fn hyperlink_text(
1512 mut self,
1513 target_text: &str,
1514 select_method: HyperlinkSelectMethod,
1515 ) -> Self {
1516 self.hyperlink_text
1517 .push((target_text.to_string(), select_method));
1518 self
1519 }
1520}
1521
1522#[derive(Debug, Clone, PartialEq, PartialOrd)]
1524pub struct Variable<T> {
1525 pub discern_type: String,
1526 pub name: String,
1527 pub value: Option<T>,
1529}
1530
1531impl<T: Debug + 'static> RustConstructorResource for Variable<T> {
1532 fn name(&self) -> &str {
1533 &self.name
1534 }
1535
1536 fn expose_type(&self) -> &str {
1537 &self.discern_type
1538 }
1539
1540 fn as_any(&self) -> &dyn Any {
1541 self
1542 }
1543
1544 fn as_any_mut(&mut self) -> &mut dyn Any {
1545 self
1546 }
1547}
1548
1549impl<T> Default for Variable<T> {
1550 fn default() -> Self {
1551 Variable {
1552 discern_type: String::from("Variable"),
1553 name: String::from("Variable"),
1554 value: None,
1555 }
1556 }
1557}
1558
1559impl<T> Variable<T> {
1560 #[inline]
1561 pub fn name(mut self, name: &str) -> Self {
1562 self.name = name.to_string();
1563 self
1564 }
1565
1566 #[inline]
1567 pub fn value(mut self, value: Option<T>) -> Self {
1568 self.value = value;
1569 self
1570 }
1571}
1572
1573#[derive(Debug, Clone, PartialEq)]
1575pub struct Font {
1576 pub name: String,
1577 pub discern_type: String,
1578 pub font_definitions: FontDefinitions,
1580 pub path: String,
1582}
1583
1584impl RustConstructorResource for Font {
1585 fn name(&self) -> &str {
1586 &self.name
1587 }
1588
1589 fn expose_type(&self) -> &str {
1590 &self.discern_type
1591 }
1592
1593 fn as_any(&self) -> &dyn Any {
1594 self
1595 }
1596
1597 fn as_any_mut(&mut self) -> &mut dyn Any {
1598 self
1599 }
1600}
1601
1602impl Default for Font {
1603 fn default() -> Self {
1604 Self {
1605 discern_type: String::from("Font"),
1606 name: String::from("Font"),
1607 font_definitions: FontDefinitions::default(),
1608 path: String::from(""),
1609 }
1610 }
1611}
1612
1613impl Font {
1614 #[inline]
1615 pub fn name(mut self, name: &str) -> Self {
1616 self.name = name.to_string();
1617 self
1618 }
1619
1620 #[inline]
1621 pub fn path(mut self, path: &str) -> Self {
1622 self.path = path.to_string();
1623 self
1624 }
1625}
1626
1627#[derive(Debug, Clone, PartialEq, PartialOrd)]
1629pub struct SplitTime {
1630 pub discern_type: String,
1631 pub name: String,
1632 pub time: [f32; 2],
1634}
1635
1636impl RustConstructorResource for SplitTime {
1637 fn name(&self) -> &str {
1638 &self.name
1639 }
1640
1641 fn expose_type(&self) -> &str {
1642 &self.discern_type
1643 }
1644
1645 fn as_any(&self) -> &dyn Any {
1646 self
1647 }
1648
1649 fn as_any_mut(&mut self) -> &mut dyn Any {
1650 self
1651 }
1652}
1653
1654impl Default for SplitTime {
1655 fn default() -> Self {
1656 Self {
1657 discern_type: String::from("SplitTime"),
1658 name: String::from("SplitTime"),
1659 time: [0_f32, 0_f32],
1660 }
1661 }
1662}
1663
1664impl SplitTime {
1665 #[inline]
1666 pub fn name(mut self, name: &str) -> Self {
1667 self.name = name.to_string();
1668 self
1669 }
1670}
1671
1672#[derive(Debug, Clone, PartialEq, PartialOrd)]
1674pub struct SwitchAppearance {
1675 pub image_config: ImageConfig,
1677 pub custom_rect_config: CustomRectConfig,
1679 pub text_config: TextConfig,
1681 pub texture: String,
1683 pub hint_text: String,
1685}
1686
1687#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1689pub struct SwitchClickAction {
1690 pub click_method: PointerButton,
1692 pub action: bool,
1694}
1695
1696#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1698pub struct SwitchData {
1699 pub switched: bool,
1701 pub last_time_clicked_index: usize,
1703 pub state: u32,
1705}
1706
1707#[derive(Debug, Clone, PartialEq)]
1709pub struct Switch {
1710 pub discern_type: String,
1711 pub name: String,
1712 pub appearance: Vec<SwitchAppearance>,
1714 pub fill_resource_name: String,
1716 pub fill_resource_type: String,
1718 pub enable_hover_click_fill_resource: [bool; 2],
1720 pub state: u32,
1722 pub click_method: Vec<SwitchClickAction>,
1724 pub last_time_hovered: bool,
1726 pub last_time_clicked: bool,
1728 pub last_time_clicked_index: usize,
1730 pub animation_count: u32,
1732 pub hint_text_name: String,
1734 pub text_name: String,
1736 pub text_origin_position: [f32; 2],
1738 pub switched: bool,
1740}
1741
1742impl RustConstructorResource for Switch {
1743 fn name(&self) -> &str {
1744 &self.name
1745 }
1746
1747 fn expose_type(&self) -> &str {
1748 &self.discern_type
1749 }
1750
1751 fn as_any(&self) -> &dyn Any {
1752 self
1753 }
1754
1755 fn as_any_mut(&mut self) -> &mut dyn Any {
1756 self
1757 }
1758}
1759
1760impl Default for Switch {
1761 fn default() -> Self {
1762 Self {
1763 discern_type: String::from("Switch"),
1764 name: String::from("Switch"),
1765 appearance: vec![],
1766 fill_resource_name: String::from("FillResource"),
1767 fill_resource_type: String::from("Image"),
1768 enable_hover_click_fill_resource: [false, false],
1769 state: 0,
1770 click_method: vec![],
1771 last_time_hovered: false,
1772 last_time_clicked: false,
1773 last_time_clicked_index: 5,
1774 animation_count: 0,
1775 hint_text_name: String::from("HintText"),
1776 text_name: String::from("Text"),
1777 text_origin_position: [0_f32, 0_f32],
1778 switched: false,
1779 }
1780 }
1781}
1782
1783impl Switch {
1784 #[inline]
1785 pub fn name(mut self, name: &str) -> Self {
1786 self.name = name.to_string();
1787 self
1788 }
1789
1790 #[inline]
1791 pub fn appearance(mut self, appearance: Vec<SwitchAppearance>) -> Self {
1792 self.appearance = appearance;
1793 self
1794 }
1795
1796 #[inline]
1797 pub fn enable_hover_click_fill_resource(
1798 mut self,
1799 enable_hover_fill_resource: bool,
1800 enable_click_fill_resource: bool,
1801 ) -> Self {
1802 self.enable_hover_click_fill_resource =
1803 [enable_hover_fill_resource, enable_click_fill_resource];
1804 self
1805 }
1806
1807 #[inline]
1808 pub fn click_method(mut self, click_method: Vec<SwitchClickAction>) -> Self {
1809 self.click_method = click_method;
1810 self
1811 }
1812}
1813
1814#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1816pub struct RenderResource {
1817 pub discern_type: String,
1818 pub name: String,
1819}
1820
1821#[derive(Debug, Clone, PartialEq, PartialOrd)]
1823pub struct MessageBox {
1824 pub discern_type: String,
1825 pub name: String,
1826 pub size: [f32; 2],
1828 pub content_name: String,
1830 pub title_name: String,
1832 pub image_name: String,
1834 pub keep_existing: bool,
1836 pub existing_time: f32,
1838 pub exist: bool,
1840 pub speed: f32,
1842 pub restore_speed: f32,
1844 pub memory_offset: f32,
1846}
1847
1848impl RustConstructorResource for MessageBox {
1849 fn name(&self) -> &str {
1850 &self.name
1851 }
1852
1853 fn expose_type(&self) -> &str {
1854 &self.discern_type
1855 }
1856
1857 fn as_any(&self) -> &dyn Any {
1858 self
1859 }
1860
1861 fn as_any_mut(&mut self) -> &mut dyn Any {
1862 self
1863 }
1864}
1865
1866impl Default for MessageBox {
1867 fn default() -> Self {
1868 Self {
1869 discern_type: String::from("MessageBox"),
1870 name: String::from("MessageBox"),
1871 size: [100_f32, 100_f32],
1872 content_name: String::from("Content"),
1873 title_name: String::from("Title"),
1874 image_name: String::from("Image"),
1875 keep_existing: false,
1876 existing_time: 3_f32,
1877 exist: true,
1878 speed: 30_f32,
1879 restore_speed: 10_f32,
1880 memory_offset: 0_f32,
1881 }
1882 }
1883}
1884
1885impl MessageBox {
1886 #[inline]
1887 pub fn name(mut self, name: &str) -> Self {
1888 self.name = name.to_string();
1889 self
1890 }
1891
1892 #[inline]
1893 pub fn size(mut self, width: f32, height: f32) -> Self {
1894 self.size = [width, height];
1895 self
1896 }
1897
1898 #[inline]
1899 pub fn keep_existing(mut self, keep_existing: bool) -> Self {
1900 self.keep_existing = keep_existing;
1901 self
1902 }
1903
1904 #[inline]
1905 pub fn existing_time(mut self, existing_time: f32) -> Self {
1906 self.existing_time = existing_time;
1907 self
1908 }
1909
1910 #[inline]
1911 pub fn speed(mut self, speed: f32) -> Self {
1912 self.speed = speed;
1913 self
1914 }
1915
1916 #[inline]
1917 pub fn restore_speed(mut self, restore_speed: f32) -> Self {
1918 self.restore_speed = restore_speed;
1919 self
1920 }
1921}
1922
1923#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1925pub enum MouseDetectorLevel {
1926 Lite,
1928 #[default]
1930 Default,
1931 Pro,
1933}
1934
1935#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1937pub struct MouseDetectResult {
1938 pub clicked: bool,
1940 pub contains_pointer: bool,
1942 pub secondary_clicked: Option<bool>,
1944 pub middle_clicked: Option<bool>,
1946 pub clicked_by_extra_button: Option<[bool; 2]>,
1948 pub long_touched: Option<bool>,
1950 pub double_clicked: Option<bool>,
1952 pub triple_clicked: Option<bool>,
1954 pub double_clicked_by: Option<[bool; 5]>,
1956 pub triple_clicked_by: Option<[bool; 5]>,
1958 pub clicked_elsewhere: Option<bool>,
1960 pub hovered: Option<bool>,
1962 pub drag_started: Option<bool>,
1964 pub drag_started_by: Option<[bool; 5]>,
1966 pub dragged: Option<bool>,
1968 pub dragged_by: Option<[bool; 5]>,
1970 pub drag_stopped: Option<bool>,
1972 pub deag_stopped_by: Option<[bool; 5]>,
1974 pub drag_delta: Option<[f32; 2]>,
1976 pub total_drag_delta: Option<Option<[f32; 2]>>,
1978 pub drag_motion: Option<[f32; 2]>,
1980 pub interact_pointer_pos: Option<Option<[f32; 2]>>,
1982 pub hover_pos: Option<Option<[f32; 2]>>,
1984 pub is_pointer_button_down_on: Option<bool>,
1986}
1987
1988#[derive(Debug, Clone, PartialEq, PartialOrd)]
1990pub struct MouseDetector {
1991 pub discern_type: String,
1992 pub name: String,
1993 pub position: [f32; 2],
1995 pub origin_position: [f32; 2],
1997 pub size: [f32; 2],
1999 pub x_grid: [u32; 2],
2001 pub y_grid: [u32; 2],
2003 pub center_display: (HorizontalAlign, VerticalAlign),
2005 pub offset: [f32; 2],
2007 pub detect_result: MouseDetectResult,
2009}
2010
2011impl RustConstructorResource for MouseDetector {
2012 fn name(&self) -> &str {
2013 &self.name
2014 }
2015
2016 fn expose_type(&self) -> &str {
2017 &self.discern_type
2018 }
2019
2020 fn as_any(&self) -> &dyn Any {
2021 self
2022 }
2023
2024 fn as_any_mut(&mut self) -> &mut dyn Any {
2025 self
2026 }
2027}
2028
2029impl Default for MouseDetector {
2030 fn default() -> Self {
2031 Self {
2032 discern_type: String::from("MouseDetector"),
2033 name: String::from("MouseDetector"),
2034 position: [0_f32, 0_f32],
2035 origin_position: [0_f32, 0_f32],
2036 size: [100_f32, 100_f32],
2037 x_grid: [0, 0],
2038 y_grid: [0, 0],
2039 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
2040 offset: [0_f32, 0_f32],
2041 detect_result: MouseDetectResult::default(),
2042 }
2043 }
2044}
2045
2046impl MouseDetector {
2047 pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
2048 self.origin_position = position_config.origin_position;
2049 self.size = position_config.size;
2050 self.x_grid = position_config.x_grid;
2051 self.y_grid = position_config.y_grid;
2052 self.center_display = position_config.center_display;
2053 self.offset = position_config.offset;
2054 self
2055 }
2056
2057 #[inline]
2058 pub fn name(mut self, name: &str) -> Self {
2059 self.name = name.to_string();
2060 self
2061 }
2062
2063 #[inline]
2064 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
2065 self.origin_position = [x, y];
2066 self
2067 }
2068
2069 #[inline]
2070 pub fn size(mut self, width: f32, height: f32) -> Self {
2071 self.size = [width, height];
2072 self
2073 }
2074
2075 #[inline]
2076 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
2077 self.x_grid = [fetch, total];
2078 self
2079 }
2080
2081 #[inline]
2082 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
2083 self.y_grid = [fetch, total];
2084 self
2085 }
2086
2087 #[inline]
2088 pub fn center_display(
2089 mut self,
2090 horizontal_align: HorizontalAlign,
2091 vertical_align: VerticalAlign,
2092 ) -> Self {
2093 self.center_display = (horizontal_align, vertical_align);
2094 self
2095 }
2096
2097 #[inline]
2098 pub fn offset(mut self, x: f32, y: f32) -> Self {
2099 self.offset = [x, y];
2100 self
2101 }
2102}
2103
2104#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2106pub enum RustConstructorError {
2107 ImageGetFailed { image_path: String },
2109 ImageNotFound { image_name: String },
2111 ImageTextureNotFound { image_texture_name: String },
2113 TextNotFound { text_name: String },
2115 VariableNotFound { variable_name: String },
2117 VariableTypeMismatch { variable_name: String },
2119 SplitTimeNotFound { split_time_name: String },
2121 SwitchAppearanceMismatch { switch_name: String, differ: u32 },
2123 SwitchFillResourceMismatch {
2125 switch_name: String,
2126 fill_resource_name: String,
2127 fill_resource_type: String,
2128 },
2129 SwitchNotFound { switch_name: String },
2131 MessageBoxAlreadyExists { message_box_name: String },
2133 MouseDetectorNotFound { mouse_detector_name: String },
2135 FontGetFailed { font_path: String },
2137 FontNotFound { font_name: String },
2139 RectNotFound { rect_name: String },
2141 ResourceNotFound {
2143 resource_name: String,
2144 resource_type: String,
2145 },
2146 PageNotFound { page_name: String },
2148 CustomError {
2150 error_name: String,
2151 error_message: String,
2152 error_annotation: String,
2153 },
2154}
2155
2156impl Display for RustConstructorError {
2157 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2158 Debug::fmt(self, f)
2159 }
2160}
2161
2162impl Error for RustConstructorError {}
2163
2164impl Default for RustConstructorError {
2165 fn default() -> Self {
2166 RustConstructorError::ImageGetFailed {
2167 image_path: "".to_string(),
2168 }
2169 }
2170}
2171
2172#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2174pub enum HorizontalAlign {
2175 #[default]
2177 Left,
2178 Center,
2180 Right,
2182}
2183
2184#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2186pub enum VerticalAlign {
2187 #[default]
2189 Top,
2190 Center,
2192 Bottom,
2194}
2195
2196#[derive(Debug)]
2198pub struct App {
2199 pub strict_mode: bool,
2201 pub safe_mode: bool,
2203 pub rust_constructor_resource: Vec<Box<dyn RustConstructorResource>>,
2205 pub render_resource_list: Vec<RenderResource>,
2207 pub problem_list: Vec<Problem>,
2209 pub tick_interval: f32,
2211 pub current_page: String,
2213 pub timer: Timer,
2215 pub frame_times: Vec<f32>,
2217 pub last_frame_time: Option<f64>,
2219}
2220
2221impl Default for App {
2222 fn default() -> Self {
2223 App {
2224 strict_mode: false,
2225 safe_mode: true,
2226 rust_constructor_resource: Vec::new(),
2227 render_resource_list: Vec::new(),
2228 problem_list: Vec::new(),
2229 tick_interval: 0.05,
2230 current_page: String::new(),
2231 timer: Timer::default(),
2232 frame_times: Vec::new(),
2233 last_frame_time: None,
2234 }
2235 }
2236}
2237
2238impl App {
2239 #[inline]
2240 pub fn strict_mode(mut self, strict_mode: bool) -> Self {
2241 self.strict_mode = strict_mode;
2242 self
2243 }
2244
2245 #[inline]
2246 pub fn safe_mode(mut self, safe_mode: bool) -> Self {
2247 self.safe_mode = safe_mode;
2248 self
2249 }
2250
2251 #[inline]
2252 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
2253 self.tick_interval = tick_interval;
2254 self
2255 }
2256
2257 #[inline]
2258 pub fn current_page(mut self, current_page: &str) -> Self {
2259 self.current_page = current_page.to_string();
2260 self
2261 }
2262
2263 pub fn page_handler(&mut self, ctx: &Context) {
2265 self.update_frame_stats(ctx);
2267 self.render_resource_list = Vec::new();
2269 self.update_timer();
2271 if let Ok(Some(pd)) = self.get_resource::<PageData>(&self.current_page.clone(), "PageData")
2272 && pd.forced_update
2273 {
2274 ctx.request_repaint();
2276 };
2277 }
2278
2279 pub fn add_page(&mut self, mut page_data: PageData) {
2281 page_data.change_page_updated = false;
2282 page_data.enter_page_updated = false;
2283 self.rust_constructor_resource.push(Box::new(page_data));
2284 }
2285
2286 pub fn switch_page(
2288 &mut self,
2289 name: &str,
2290 safe_mode: Option<bool>,
2291 ) -> Result<(), RustConstructorError> {
2292 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2293 && !self.check_resource_exists(name, "PageData")
2294 {
2295 self.problem_report_custom(
2296 RustConstructorError::PageNotFound {
2297 page_name: name.to_string(),
2298 },
2299 SeverityLevel::SevereWarning,
2300 self.problem_list.clone(),
2301 );
2302 return Err(RustConstructorError::PageNotFound {
2303 page_name: name.to_string(),
2304 });
2305 };
2306 self.current_page = name.to_string();
2307 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2308 pd.enter_page_updated = false;
2309 self.timer.start_time = self.timer.total_time;
2310 self.update_timer();
2311 Ok(())
2312 }
2313
2314 pub fn replace_resource_custom<T>(
2316 &self,
2317 name: &str,
2318 discern_type: &str,
2319 resource: T,
2320 mut target: Vec<Box<dyn RustConstructorResource>>,
2321 ) -> Result<(), RustConstructorError>
2322 where
2323 T: RustConstructorResource + 'static,
2324 {
2325 if let Some(index) = self
2326 .rust_constructor_resource
2327 .iter()
2328 .position(|x| x.name() == name && x.expose_type() == discern_type)
2329 {
2330 target[index] = Box::new(resource);
2331 Ok(())
2332 } else {
2333 self.problem_report_custom(
2334 RustConstructorError::ResourceNotFound {
2335 resource_name: name.to_string(),
2336 resource_type: discern_type.to_string(),
2337 },
2338 SeverityLevel::SevereWarning,
2339 self.problem_list.clone(),
2340 );
2341 Err(RustConstructorError::ResourceNotFound {
2342 resource_name: name.to_string(),
2343 resource_type: discern_type.to_string(),
2344 })
2345 }
2346 }
2347
2348 pub fn replace_resource<T>(
2350 &mut self,
2351 name: &str,
2352 discern_type: &str,
2353 resource: T,
2354 ) -> Result<(), RustConstructorError>
2355 where
2356 T: RustConstructorResource + 'static,
2357 {
2358 if let Some(index) = self
2359 .rust_constructor_resource
2360 .iter()
2361 .position(|x| x.name() == name && x.expose_type() == discern_type)
2362 {
2363 self.rust_constructor_resource[index] = Box::new(resource);
2364 Ok(())
2365 } else {
2366 self.problem_report_custom(
2367 RustConstructorError::ResourceNotFound {
2368 resource_name: name.to_string(),
2369 resource_type: discern_type.to_string(),
2370 },
2371 SeverityLevel::SevereWarning,
2372 self.problem_list.clone(),
2373 );
2374 Err(RustConstructorError::ResourceNotFound {
2375 resource_name: name.to_string(),
2376 resource_type: discern_type.to_string(),
2377 })
2378 }
2379 }
2380
2381 pub fn get_resource<T>(
2383 &self,
2384 name: &str,
2385 discern_type: &str,
2386 ) -> Result<Option<&T>, RustConstructorError>
2387 where
2388 T: RustConstructorResource + 'static,
2389 {
2390 if self.check_resource_exists(name, discern_type) {
2391 Ok(self
2392 .rust_constructor_resource
2393 .iter()
2394 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2395 .and_then(|resource| resource.as_any().downcast_ref::<T>()))
2396 } else {
2397 self.problem_report_custom(
2398 RustConstructorError::ResourceNotFound {
2399 resource_name: name.to_string(),
2400 resource_type: discern_type.to_string(),
2401 },
2402 SeverityLevel::SevereWarning,
2403 self.problem_list.clone(),
2404 );
2405 Err(RustConstructorError::ResourceNotFound {
2406 resource_name: name.to_string(),
2407 resource_type: discern_type.to_string(),
2408 })
2409 }
2410 }
2411
2412 pub fn get_resource_mut<T>(
2414 &mut self,
2415 name: &str,
2416 discern_type: &str,
2417 ) -> Result<&mut T, RustConstructorError>
2418 where
2419 T: RustConstructorResource + 'static,
2420 {
2421 if self.check_resource_exists(name, discern_type) {
2422 Ok(self
2423 .rust_constructor_resource
2424 .iter_mut()
2425 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2426 .and_then(|resource| resource.as_any_mut().downcast_mut::<T>())
2427 .unwrap())
2428 } else {
2429 self.problem_report_custom(
2430 RustConstructorError::ResourceNotFound {
2431 resource_name: name.to_string(),
2432 resource_type: discern_type.to_string(),
2433 },
2434 SeverityLevel::SevereWarning,
2435 self.problem_list.clone(),
2436 );
2437 Err(RustConstructorError::ResourceNotFound {
2438 resource_name: name.to_string(),
2439 resource_type: discern_type.to_string(),
2440 })
2441 }
2442 }
2443
2444 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> bool {
2446 self.rust_constructor_resource
2447 .iter()
2448 .any(|x| x.name() == name && x.expose_type() == discern_type)
2449 }
2450
2451 pub fn add_fonts(&mut self, mut font: Font) -> Result<(), RustConstructorError> {
2453 let mut fonts = FontDefinitions::default();
2454 if let Ok(font_read_data) = read(font.path.clone()) {
2455 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
2456 fonts.font_data.insert(
2457 font.name.to_owned(),
2458 Arc::new(FontData::from_owned(
2459 Arc::try_unwrap(font_data).ok().unwrap(),
2460 )),
2461 );
2462
2463 fonts
2465 .families
2466 .entry(FontFamily::Proportional)
2467 .or_default()
2468 .insert(0, font.name.to_owned());
2469
2470 fonts
2471 .families
2472 .entry(FontFamily::Monospace)
2473 .or_default()
2474 .insert(0, font.name.to_owned());
2475
2476 font.font_definitions = fonts;
2477 self.rust_constructor_resource.push(Box::new(font));
2478 Ok(())
2479 } else {
2480 self.problem_report_custom(
2481 RustConstructorError::FontGetFailed {
2482 font_path: font.path.to_string(),
2483 },
2484 SeverityLevel::SevereWarning,
2485 self.problem_list.clone(),
2486 );
2487 Err(RustConstructorError::FontGetFailed {
2488 font_path: font.path.to_string(),
2489 })
2490 }
2491 }
2492
2493 pub fn font(
2495 &mut self,
2496 name: &str,
2497 safe_mode: Option<bool>,
2498 ) -> Result<FontDefinitions, RustConstructorError> {
2499 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2500 && !self.check_resource_exists(name, "Font")
2501 {
2502 self.problem_report_custom(
2503 RustConstructorError::FontNotFound {
2504 font_name: name.to_string(),
2505 },
2506 SeverityLevel::SevereWarning,
2507 self.problem_list.clone(),
2508 );
2509 return Err(RustConstructorError::FontNotFound {
2510 font_name: name.to_string(),
2511 });
2512 };
2513 let f = self.get_resource::<Font>(name, "Font").unwrap().unwrap();
2514 Ok(f.font_definitions.clone())
2515 }
2516
2517 pub fn register_all_fonts(&mut self, ctx: &Context, safe_mode: Option<bool>) {
2519 let mut font_definitions = FontDefinitions::default();
2520 let mut font_resources = Vec::new();
2521 for i in 0..self.rust_constructor_resource.len() {
2522 if let Some(f) = self.rust_constructor_resource[i]
2523 .as_any()
2524 .downcast_ref::<Font>()
2525 {
2526 font_resources.push(f.clone());
2527 };
2528 }
2529 for i in &font_resources {
2530 let font_name = i.name.clone();
2531 if let Ok(font_def) = self.font(&font_name, safe_mode) {
2533 if let Some(font_data) = font_def.font_data.get(&font_name) {
2535 font_definitions
2536 .font_data
2537 .insert(font_name.clone(), Arc::clone(font_data));
2538 font_definitions
2539 .families
2540 .entry(FontFamily::Name(font_name.clone().into()))
2541 .or_default()
2542 .push(font_name.clone());
2543 };
2544
2545 font_definitions
2547 .families
2548 .entry(FontFamily::Proportional)
2549 .or_default()
2550 .insert(0, font_name.to_owned());
2551
2552 font_definitions
2553 .families
2554 .entry(FontFamily::Monospace)
2555 .or_default()
2556 .insert(0, font_name.to_owned());
2557 };
2558 }
2559 ctx.set_fonts(font_definitions);
2560 }
2561
2562 fn problem_processor(
2564 &self,
2565 problem_type: RustConstructorError,
2566 severity_level: SeverityLevel,
2567 ) -> (String, String) {
2568 let (problem, annotation) = match problem_type.clone() {
2569 RustConstructorError::FontGetFailed { font_path } => (
2570 format!("Font get failed({:?}): {}", severity_level, font_path,),
2571 "Please check if the font file exists and the path is correct.".to_string(),
2572 ),
2573 RustConstructorError::FontNotFound { font_name } => (
2574 format!("Font not found({:?}): {}", severity_level, font_name,),
2575 "Please check whether the font has been added.".to_string(),
2576 ),
2577 RustConstructorError::ImageGetFailed { image_path } => (
2578 format!("Image get failed({:?}): {}", severity_level, image_path,),
2579 "Please check whether the image path is correct and whether the image has been added.".to_string(),
2580 ),
2581 RustConstructorError::ImageNotFound { image_name } => (
2582 format!("Image not found({:?}): {}", severity_level, image_name,),
2583 "Please check whether the image has been added.".to_string(),
2584 ),
2585 RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2586 format!("Image texture not found({:?}): {}", severity_level, image_texture_name,),
2587 "Please check whether the image texture has been added.".to_string(),
2588 ),
2589 RustConstructorError::TextNotFound { text_name } => (
2590 format!("Text not found({:?}): {}", severity_level, text_name,),
2591 "Please check whether the text has been added.".to_string(),
2592 ),
2593 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2594 format!("Message box already exists({:?}): {}", severity_level, message_box_name,),
2595 "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2596 ),
2597 RustConstructorError::MouseDetectorNotFound { mouse_detector_name } => (
2598 format!("Mouse detector not found({:?}): {}", severity_level, mouse_detector_name,),
2599 "Please check whether the mouse detector has been added.".to_string(),
2600 ),
2601 RustConstructorError::SplitTimeNotFound { split_time_name } => (
2602 format!("Split time not found({:?}): {}", severity_level, split_time_name,),
2603 "Please check whether the split time has been added.".to_string(),
2604 ),
2605 RustConstructorError::SwitchAppearanceMismatch {
2606 switch_name,
2607 differ,
2608 } => (
2609 format!(
2610 "Switch appearance list's number of items is large / small {} more({:?}): {}",
2611 differ, severity_level, switch_name
2612 ),
2613 "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2614 ),
2615 RustConstructorError::SwitchNotFound { switch_name } => (
2616 format!("Switch not found({:?}): {}", severity_level, switch_name,),
2617 "Please check whether the switch has been added.".to_string(),
2618 ),
2619 RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2620 format!("Switch fill resource mismatch({:?}): Resource {} of switch {} is not of type {}", severity_level, fill_resource_name, switch_name, fill_resource_type,),
2621 "Please check whether the imported fill resource is correctly typed.".to_string(),
2622 ),
2623 RustConstructorError::PageNotFound { page_name } => (
2624 format!("Page not found({:?}): {}", severity_level, page_name,),
2625 "Please check whether the page has been added.".to_string(),
2626 ),
2627 RustConstructorError::VariableNotFound { variable_name } => (
2628 format!("Variable not found({:?}): {}", severity_level, variable_name,),
2629 "Please check whether the variable has been added.".to_string(),
2630 ),
2631 RustConstructorError::VariableTypeMismatch { variable_name } => (
2632 format!("Variable type mismatch({:?}): {}", severity_level, variable_name,),
2633 "Please check whether the generics used for matching are filled correctly.".to_string(),
2634 ),
2635 RustConstructorError::RectNotFound { rect_name } => (
2636 format!("Rect not found({:?}): {}", severity_level, rect_name,),
2637 "Please check whether the rect has been added.".to_string(),
2638 ),
2639 RustConstructorError::ResourceNotFound {
2640 resource_name,
2641 resource_type,
2642 } => (
2643 format!(
2644 "Resource not found({:?}): {}(\"{}\")",
2645 severity_level, resource_type, resource_name,
2646 ),
2647 "Please check whether the resource has been added.".to_string(),
2648 ),
2649 RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2650 format!("Custom error({}, {:?}): {}", error_name, severity_level, error_message),
2651 error_annotation
2652 )
2653 };
2654 if self.strict_mode {
2656 panic!(
2657 "Rust Constructor Error({:?}): {}\nnote: {}",
2658 problem_type, problem, annotation
2659 );
2660 };
2661 (problem, annotation)
2662 }
2663
2664 pub fn problem_report(
2666 &mut self,
2667 problem_type: RustConstructorError,
2668 severity_level: SeverityLevel,
2669 ) {
2670 let (problem, annotation) =
2671 self.problem_processor(problem_type.clone(), severity_level);
2672 self.problem_list.push(Problem {
2673 severity_level,
2674 problem,
2675 annotation,
2676 report_state: ReportState {
2677 current_page: self.current_page.clone(),
2678 current_total_runtime: self.timer.total_time,
2679 current_page_runtime: self.timer.now_time,
2680 },
2681 problem_type: problem_type.clone(),
2682 });
2683 }
2684
2685 pub fn problem_report_custom(
2687 &self,
2688 problem_type: RustConstructorError,
2689 severity_level: SeverityLevel,
2690 mut problem_storage: Vec<Problem>,
2691 ) {
2692 let (problem, annotation) =
2693 self.problem_processor(problem_type.clone(), severity_level);
2694 problem_storage.push(Problem {
2695 severity_level,
2696 problem,
2697 annotation,
2698 report_state: ReportState {
2699 current_page: self.current_page.clone(),
2700 current_total_runtime: self.timer.total_time,
2701 current_page_runtime: self.timer.now_time,
2702 },
2703 problem_type: problem_type.clone(),
2704 });
2705 }
2706
2707 pub fn check_updated(
2709 &mut self,
2710 name: &str,
2711 safe_mode: Option<bool>,
2712 ) -> Result<bool, RustConstructorError> {
2713 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2714 && !self.check_resource_exists(name, "PageData")
2715 {
2716 self.problem_report_custom(
2717 RustConstructorError::PageNotFound {
2718 page_name: name.to_string(),
2719 },
2720 SeverityLevel::SevereWarning,
2721 self.problem_list.clone(),
2722 );
2723 return Err(RustConstructorError::PageNotFound {
2724 page_name: name.to_string(),
2725 });
2726 };
2727 let pd = self
2728 .get_resource::<PageData>(name, "PageData")
2729 .unwrap()
2730 .unwrap()
2731 .clone();
2732 if !pd.change_page_updated {
2733 self.new_page_update(name, safe_mode).unwrap();
2734 };
2735 Ok(pd.change_page_updated)
2736 }
2737
2738 pub fn check_enter_updated(
2740 &mut self,
2741 name: &str,
2742 safe_mode: Option<bool>,
2743 ) -> Result<bool, RustConstructorError> {
2744 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2745 && !self.check_resource_exists(name, "PageData")
2746 {
2747 self.problem_report_custom(
2748 RustConstructorError::PageNotFound {
2749 page_name: name.to_string(),
2750 },
2751 SeverityLevel::SevereWarning,
2752 self.problem_list.clone(),
2753 );
2754 return Err(RustConstructorError::PageNotFound {
2755 page_name: name.to_string(),
2756 });
2757 };
2758 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2759 let return_value = pd.enter_page_updated;
2760 pd.enter_page_updated = true;
2761 Ok(return_value)
2762 }
2763
2764 pub fn new_page_update(
2766 &mut self,
2767 name: &str,
2768 safe_mode: Option<bool>,
2769 ) -> Result<(), RustConstructorError> {
2770 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2771 && !self.check_resource_exists(name, "PageData")
2772 {
2773 self.problem_report_custom(
2774 RustConstructorError::PageNotFound {
2775 page_name: name.to_string(),
2776 },
2777 SeverityLevel::SevereWarning,
2778 self.problem_list.clone(),
2779 );
2780 return Err(RustConstructorError::PageNotFound {
2781 page_name: name.to_string(),
2782 });
2783 }
2784 self.timer.start_time = self.timer.total_time;
2785 self.update_timer();
2786 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2787 pd.change_page_updated = true;
2788 Ok(())
2789 }
2790
2791 pub fn update_frame_stats(&mut self, ctx: &Context) {
2793 let current_time = ctx.input(|i| i.time);
2794 if let Some(last) = self.last_frame_time {
2795 let delta = (current_time - last) as f32;
2796 self.frame_times.push(delta);
2797 const MAX_SAMPLES: usize = 120;
2798 if self.frame_times.len() > MAX_SAMPLES {
2799 let remove_count = self.frame_times.len() - MAX_SAMPLES;
2800 self.frame_times.drain(0..remove_count);
2801 }
2802 }
2803 self.last_frame_time = Some(current_time);
2804 }
2805
2806 pub fn current_fps(&self) -> f32 {
2808 if self.frame_times.is_empty() {
2809 0.0
2810 } else {
2811 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
2812 }
2813 }
2814
2815 pub fn add_split_time(&mut self, mut split_time: SplitTime) {
2817 split_time.time = [self.timer.now_time, self.timer.total_time];
2818 self.rust_constructor_resource.push(Box::new(split_time));
2819 }
2820
2821 pub fn reset_split_time(
2823 &mut self,
2824 name: &str,
2825 safe_mode: Option<bool>,
2826 ) -> Result<(), RustConstructorError> {
2827 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2828 && !self.check_resource_exists(name, "SplitTime")
2829 {
2830 self.problem_report_custom(
2831 RustConstructorError::SplitTimeNotFound {
2832 split_time_name: name.to_string(),
2833 },
2834 SeverityLevel::SevereWarning,
2835 self.problem_list.clone(),
2836 );
2837 return Err(RustConstructorError::SplitTimeNotFound {
2838 split_time_name: name.to_string(),
2839 });
2840 };
2841 let new_time = [self.timer.now_time, self.timer.total_time];
2842 let st = self
2843 .get_resource_mut::<SplitTime>(name, "SplitTime")
2844 .unwrap();
2845 st.time = new_time;
2846 Ok(())
2847 }
2848
2849 pub fn split_time(
2851 &self,
2852 name: &str,
2853 safe_mode: Option<bool>,
2854 ) -> Result<[f32; 2], RustConstructorError> {
2855 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2856 && !self.check_resource_exists(name, "SplitTime")
2857 {
2858 self.problem_report_custom(
2859 RustConstructorError::SplitTimeNotFound {
2860 split_time_name: name.to_string(),
2861 },
2862 SeverityLevel::SevereWarning,
2863 self.problem_list.clone(),
2864 );
2865 return Err(RustConstructorError::SplitTimeNotFound {
2866 split_time_name: name.to_string(),
2867 });
2868 };
2869 let st = self
2870 .get_resource::<SplitTime>(name, "SplitTime")
2871 .unwrap()
2872 .unwrap();
2873 Ok(st.time)
2874 }
2875
2876 pub fn update_timer(&mut self) {
2878 let elapsed = self.timer.timer.elapsed();
2879 let seconds = elapsed.as_secs();
2880 let milliseconds = elapsed.subsec_millis();
2881 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
2882 self.timer.now_time = self.timer.total_time - self.timer.start_time
2883 }
2884
2885 pub fn add_custom_rect(&mut self, custom_rect: CustomRect) {
2887 self.rust_constructor_resource.push(Box::new(custom_rect));
2888 }
2889
2890 pub fn custom_rect(
2892 &mut self,
2893 name: &str,
2894 ui: &mut Ui,
2895 ctx: &Context,
2896 safe_mode: Option<bool>,
2897 ) -> Result<(), RustConstructorError> {
2898 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2899 && !self.check_resource_exists(name, "CustomRect")
2900 {
2901 self.problem_report_custom(
2902 RustConstructorError::RectNotFound {
2903 rect_name: name.to_string(),
2904 },
2905 SeverityLevel::SevereWarning,
2906 self.problem_list.clone(),
2907 );
2908 return Err(RustConstructorError::RectNotFound {
2909 rect_name: name.to_string(),
2910 });
2911 };
2912 let render_resource_list = &mut self.render_resource_list.clone();
2913 let cr = self
2914 .get_resource_mut::<CustomRect>(name, "CustomRect")
2915 .unwrap();
2916 cr.reg_render_resource(render_resource_list);
2917 cr.position[0] = match cr.x_grid[1] {
2918 0 => cr.origin_position[0],
2919 _ => {
2920 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64 * cr.x_grid[0] as f64)
2921 as f32
2922 + cr.origin_position[0]
2923 }
2924 };
2925 cr.position[1] = match cr.y_grid[1] {
2926 0 => cr.origin_position[1],
2927 _ => {
2928 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64 * cr.y_grid[0] as f64)
2929 as f32
2930 + cr.origin_position[1]
2931 }
2932 };
2933 match cr.center_display.0 {
2934 HorizontalAlign::Left => {}
2935 HorizontalAlign::Center => cr.position[0] -= cr.size[0] / 2.0,
2936 HorizontalAlign::Right => cr.position[0] -= cr.size[0],
2937 };
2938 match cr.center_display.1 {
2939 VerticalAlign::Top => {}
2940 VerticalAlign::Center => cr.position[1] -= cr.size[1] / 2.0,
2941 VerticalAlign::Bottom => cr.position[1] -= cr.size[1],
2942 };
2943 cr.position[0] += cr.offset[0];
2944 cr.position[1] += cr.offset[1];
2945 ui.painter().rect(
2946 Rect::from_min_max(
2947 Pos2::new(cr.position[0], cr.position[1]),
2948 Pos2::new(cr.position[0] + cr.size[0], cr.position[1] + cr.size[1]),
2949 ),
2950 cr.rounding,
2951 Color32::from_rgba_unmultiplied(cr.color[0], cr.color[1], cr.color[2], cr.color[3]),
2952 Stroke {
2953 width: cr.border_width,
2954 color: Color32::from_rgba_unmultiplied(
2955 cr.border_color[0],
2956 cr.border_color[1],
2957 cr.border_color[2],
2958 cr.border_color[3],
2959 ),
2960 },
2961 StrokeKind::Inside,
2962 );
2963 Ok(())
2964 }
2965
2966 pub fn add_text(&mut self, text: Text) {
2968 self.rust_constructor_resource.push(Box::new(text));
2969 }
2970
2971 pub fn text(
2973 &mut self,
2974 name: &str,
2975 ui: &mut Ui,
2976 ctx: &Context,
2977 safe_mode: Option<bool>,
2978 ) -> Result<(), RustConstructorError> {
2979 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2980 && !self.check_resource_exists(name, "Text")
2981 {
2982 self.problem_report_custom(
2983 RustConstructorError::TextNotFound {
2984 text_name: name.to_string(),
2985 },
2986 SeverityLevel::SevereWarning,
2987 self.problem_list.clone(),
2988 );
2989 return Err(RustConstructorError::TextNotFound {
2990 text_name: name.to_string(),
2991 });
2992 };
2993 let mut t = self
2994 .get_resource::<Text>(name, "Text")
2995 .unwrap()
2996 .unwrap()
2997 .clone();
2998 t.reg_render_resource(&mut self.render_resource_list);
2999 let galley: Arc<Galley> = ui.fonts_mut(|f| {
3001 f.layout(
3002 t.content.to_string(),
3003 if !t.font.is_empty() {
3004 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3005 && !self.check_resource_exists(&t.font.clone(), "Font")
3006 {
3007 self.problem_report_custom(
3008 RustConstructorError::FontNotFound {
3009 font_name: t.font.clone(),
3010 },
3011 SeverityLevel::MildWarning,
3012 self.problem_list.clone(),
3013 );
3014 FontId::new(t.font_size, FontFamily::Name(t.font.clone().into()))
3015 } else {
3016 FontId::proportional(t.font_size)
3017 }
3018 } else {
3019 FontId::proportional(t.font_size)
3020 },
3021 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]),
3022 t.wrap_width,
3023 )
3024 });
3025 t.size = [galley.size().x, galley.size().y];
3026 t.position[0] = match t.x_grid[1] {
3027 0 => t.origin_position[0],
3028 _ => {
3029 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64 * t.x_grid[0] as f64)
3030 as f32
3031 + t.origin_position[0]
3032 }
3033 };
3034 t.position[1] = match t.y_grid[1] {
3035 0 => t.origin_position[1],
3036 _ => {
3037 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64 * t.y_grid[0] as f64)
3038 as f32
3039 + t.origin_position[1]
3040 }
3041 };
3042 let pos_x = match t.center_display.0 {
3043 HorizontalAlign::Left => t.position[0],
3044 HorizontalAlign::Center => t.position[0] - t.size[0] / 2.0,
3045 HorizontalAlign::Right => t.position[0] - t.size[0],
3046 };
3047 let pos_y = match t.center_display.1 {
3048 VerticalAlign::Top => t.position[1],
3049 VerticalAlign::Center => t.position[1] - t.size[1] / 2.0,
3050 VerticalAlign::Bottom => t.position[1] - t.size[1],
3051 };
3052 t.position[0] += t.offset[0];
3053 t.position[1] += t.offset[1];
3054 let position = Pos2::new(pos_x, pos_y);
3056
3057 let rect = Rect::from_min_size(position, t.size.into());
3058 ui.painter().rect_filled(
3060 rect,
3061 t.background_rounding,
3062 Color32::from_rgba_unmultiplied(
3063 t.background_color[0],
3064 t.background_color[1],
3065 t.background_color[2],
3066 t.background_color[3],
3067 ),
3068 ); ui.painter().galley(
3071 position,
3072 galley.clone(),
3073 Color32::from_rgba_unmultiplied(
3074 t.color[0], t.color[1], t.color[2], t.color[3], ),
3076 );
3077
3078 if t.last_frame_content != t.content {
3080 t.hyperlink_index.clear();
3081
3082 let byte_to_char_map: std::collections::HashMap<usize, usize> = t
3084 .content
3085 .char_indices()
3086 .enumerate()
3087 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
3088 .collect();
3089
3090 for (text, method) in &t.hyperlink_text {
3091 let matches: Vec<(usize, &str)> = t.content.match_indices(text).collect();
3092 let text_char_count = text.chars().count();
3093
3094 if let HyperlinkSelectMethod::All(url) = method {
3095 for (byte_index, _) in matches {
3096 if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3097 t.hyperlink_index.push((
3098 start_char_index,
3099 start_char_index + text_char_count,
3100 url.clone(),
3101 ));
3102 };
3103 }
3104 } else if let HyperlinkSelectMethod::Segment(list) = method {
3105 for (index, url) in list {
3106 if *index >= matches.len() {
3107 continue;
3108 };
3109 let (byte_index, _) = matches[*index];
3110 if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3111 t.hyperlink_index.push((
3112 start_char_index,
3113 start_char_index + text_char_count,
3114 url.clone(),
3115 ));
3116 };
3117 }
3118 };
3119 }
3120 };
3121
3122 for (start, end, _) in &t.hyperlink_index {
3124 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3126 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3127
3128 let start_pos = start_cursor.left_top();
3129 let end_pos = end_cursor.right_top();
3130 if start_cursor.min.y == end_cursor.min.y {
3133 let underline_y =
3135 position.y + start_pos.y + galley.rows.first().map_or(14.0, |row| row.height())
3136 - 2.0;
3137
3138 let color =
3140 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]);
3141
3142 ui.painter().line_segment(
3143 [
3144 Pos2::new(position.x + start_pos.x, underline_y),
3145 Pos2::new(position.x + end_pos.x, underline_y),
3146 ],
3147 Stroke::new(t.font_size / 10_f32, color),
3148 );
3149 } else {
3150 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
3155 let end_row = (end_pos.y / row_height).round() as usize;
3156
3157 for row in start_row..=end_row {
3158 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
3162 let row_rect = current_row.rect();
3163
3164 let color = Color32::from_rgba_unmultiplied(
3165 t.color[0], t.color[1], t.color[2], t.color[3],
3166 );
3167
3168 if row == start_row {
3169 ui.painter().line_segment(
3171 [
3172 Pos2::new(position.x + start_pos.x, row_y),
3173 Pos2::new(position.x + row_rect.max.x, row_y),
3174 ],
3175 Stroke::new(t.font_size / 10_f32, color),
3176 );
3177 } else if row == end_row {
3178 ui.painter().line_segment(
3180 [
3181 Pos2::new(position.x + row_rect.min.x, row_y),
3182 Pos2::new(position.x + end_pos.x, row_y),
3183 ],
3184 Stroke::new(t.font_size / 10_f32, color),
3185 );
3186 } else {
3187 ui.painter().line_segment(
3189 [
3190 Pos2::new(position.x + row_rect.min.x, row_y),
3191 Pos2::new(position.x + row_rect.max.x, row_y),
3192 ],
3193 Stroke::new(t.font_size / 10_f32, color),
3194 );
3195 };
3196 };
3197 }
3198 };
3199 }
3200
3201 if t.selectable {
3202 if !self.check_resource_exists(&t.name, "MouseDetector") {
3203 self.add_mouse_detector(
3204 MouseDetector::default()
3205 .name(&t.name)
3206 .from_position_config(PositionConfig::from_text(t.clone()))
3207 .offset(-20_f32, -5_f32)
3208 .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3209 );
3210 } else {
3211 self.replace_resource(
3212 &t.name,
3213 "MouseDetector",
3214 MouseDetector::default()
3215 .name(&t.name)
3216 .from_position_config(PositionConfig::from_text(t.clone()))
3217 .offset(-20_f32, -5_f32)
3218 .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3219 )
3220 .unwrap();
3221 };
3222
3223 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
3225 let relative_pos = pointer_pos - position.to_vec2();
3226 let cursor = galley.cursor_from_pos(relative_pos);
3227 cursor.index
3228 };
3229
3230 self.mouse_detector(&t.name, ui, ctx, MouseDetectorLevel::Default, safe_mode)
3231 .unwrap();
3232 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
3233 let detect_result = self.check_mouse_detect_result(&t.name, safe_mode).unwrap();
3234 if !detect_result.clicked
3235 && (fullscreen_detect_result.any_click() || fullscreen_detect_result.any_pressed())
3236 {
3237 t.selection = None;
3238 };
3239
3240 if (detect_result.clicked || detect_result.drag_started.unwrap())
3241 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3242 {
3243 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3244 t.selection = Some((cursor, cursor));
3245 };
3246
3247 if detect_result.dragged.unwrap()
3248 && t.selection.is_some()
3249 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3250 {
3251 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3252 if let Some((start, _)) = t.selection {
3253 t.selection = Some((start, cursor));
3254 };
3255 };
3256
3257 if t.selection.is_some()
3258 && ui.input(|input| input.key_released(Key::A) && input.modifiers.command)
3259 {
3260 t.selection = Some((0, t.content.chars().count()));
3261 };
3262
3263 let copy_triggered = ui.input(|input| {
3265 let c_released = input.key_released(Key::C);
3266 let cmd_pressed = input.modifiers.command;
3267 c_released && cmd_pressed
3268 });
3269 if copy_triggered && let Some((start, end)) = t.selection {
3270 let (start, end) = (start.min(end), start.max(end));
3271 let chars: Vec<char> = t.content.chars().collect();
3272 if start <= chars.len() && end <= chars.len() && start < end {
3273 let selected_text: String = chars[start..end].iter().collect();
3274 ui.ctx().copy_text(selected_text);
3275 };
3276 };
3277
3278 if let Some((start, end)) = t.selection {
3280 let (start, end) = (start.min(end), start.max(end));
3281 if start != end {
3282 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
3284 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3285
3286 let start_pos = start_cursor.left_top();
3287 let end_pos = end_cursor.right_top();
3288 if start_pos.y == end_pos.y {
3290 let rows = &galley.rows;
3292 let row_height = if !rows.is_empty() {
3293 if let Some(row) = rows.first() {
3295 row.height()
3296 } else {
3297 t.size[1] / t.content.lines().count() as f32
3298 }
3299 } else {
3300 t.size[1] / t.content.lines().count() as f32
3301 };
3302
3303 let selection_rect = Rect::from_min_max(
3304 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3305 Pos2::new(
3306 position.x + end_pos.x,
3307 position.y + start_pos.y + row_height,
3308 ),
3309 );
3310 ui.painter().rect_filled(
3311 selection_rect,
3312 0.0,
3313 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3314 );
3315 } else {
3316 let rows = &galley.rows;
3318 let row_height = if !rows.is_empty() {
3319 rows[0].height()
3320 } else {
3321 t.size[1] / t.content.lines().count() as f32
3322 };
3323
3324 let selection_top = position.y + start_pos.y.min(end_pos.y);
3326 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
3327
3328 let start_row_index = (start_pos.y / row_height).floor() as usize;
3330 let end_row_index = (end_pos.y / row_height).floor() as usize;
3331 let (first_row_index, last_row_index) = if start_row_index <= end_row_index
3332 {
3333 (start_row_index, end_row_index)
3334 } else {
3335 (end_row_index, start_row_index)
3336 };
3337
3338 for (i, row) in rows.iter().enumerate() {
3339 let row_y = position.y + row_height * i as f32;
3340 let row_bottom = row_y + row_height;
3341 if row_bottom > selection_top && row_y <= selection_bottom {
3343 let left = if i == first_row_index {
3344 position.x + start_pos.x
3346 } else {
3347 position.x + row.rect().min.x
3349 };
3350
3351 let right = if i == last_row_index {
3352 position.x + end_pos.x
3354 } else {
3355 position.x + row.rect().max.x
3357 };
3358
3359 let selection_rect = Rect::from_min_max(
3360 Pos2::new(left, row_y),
3361 Pos2::new(right, row_bottom),
3362 );
3363
3364 if selection_rect.width() > 0.0 && selection_rect.height() > 0.0 {
3366 ui.painter().rect_filled(
3367 selection_rect,
3368 0.0,
3369 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3370 );
3371 };
3372 };
3373 }
3374 };
3375 };
3376 };
3377 };
3378
3379 for (start, end, url) in &t.hyperlink_index {
3381 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3383 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3384
3385 let start_pos = start_cursor.left_top();
3386 let end_pos = end_cursor.right_top();
3387
3388 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3389
3390 let link_responses = if start_cursor.min.y == end_cursor.min.y {
3392 let link_rect = Rect::from_min_max(
3394 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3395 Pos2::new(
3396 position.x + end_pos.x,
3397 position.y + start_pos.y + row_height,
3398 ),
3399 );
3400 vec![ui.interact(
3401 link_rect,
3402 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
3403 egui::Sense::click(),
3404 )]
3405 } else {
3406 let start_row = (start_pos.y / row_height).round() as usize;
3408 let end_row = (end_pos.y / row_height).round() as usize;
3409 let mut responses = Vec::new();
3410
3411 for row in start_row..=end_row {
3412 if let Some(current_row) = galley.rows.get(row) {
3413 let row_rect = current_row.rect();
3414 let row_y = position.y + row as f32 * row_height;
3415
3416 let link_rect = if row == start_row {
3417 Rect::from_min_max(
3419 Pos2::new(position.x + start_pos.x, row_y),
3420 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3421 )
3422 } else if row == end_row {
3423 Rect::from_min_max(
3425 Pos2::new(position.x + row_rect.min.x, row_y),
3426 Pos2::new(position.x + end_pos.x, row_y + row_height),
3427 )
3428 } else {
3429 Rect::from_min_max(
3431 Pos2::new(position.x + row_rect.min.x, row_y),
3432 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3433 )
3434 };
3435
3436 responses.push(ui.interact(
3437 link_rect,
3438 Id::new(format!("link_{}_{}_{}_row_{}", t.name, start, end, row)),
3439 Sense::click(),
3440 ));
3441 };
3442 }
3443 responses
3444 };
3445
3446 let mut is_pressing_link = false;
3448 for link_response in &link_responses {
3449 if link_response.is_pointer_button_down_on() && !link_response.drag_started() {
3450 t.selection = None;
3451 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
3452 let relative_pos = pointer_pos - position.to_vec2();
3453 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3454 if cursor.index >= *start && cursor.index <= *end {
3455 is_pressing_link = true;
3456 break;
3457 };
3458 };
3459 };
3460 }
3461
3462 let mut clicked_on_link = false;
3464 for link_response in &link_responses {
3465 if link_response.clicked()
3466 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3467 {
3468 let relative_pos = pointer_pos - position.to_vec2();
3469 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3470 if cursor.index >= *start && cursor.index <= *end {
3471 clicked_on_link = true;
3472 break;
3473 };
3474 };
3475 }
3476
3477 if clicked_on_link {
3478 if !url.is_empty() {
3480 ui.ctx().open_url(OpenUrl::new_tab(url));
3481 };
3482 };
3483
3484 if is_pressing_link {
3486 if start_cursor.min.y == end_cursor.min.y {
3487 let selection_rect = Rect::from_min_max(
3489 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3490 Pos2::new(
3491 position.x + end_pos.x,
3492 position.y
3493 + start_pos.y
3494 + galley.rows.first().map_or(14.0, |row| row.height()),
3495 ),
3496 );
3497 ui.painter().rect_filled(
3498 selection_rect,
3499 0.0,
3500 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3501 );
3502 } else {
3503 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3505 let start_row = (start_pos.y / row_height).round() as usize;
3506 let end_row = (end_pos.y / row_height).round() as usize;
3507
3508 for row in start_row..=end_row {
3509 if let Some(current_row) = galley.rows.get(row) {
3510 let row_rect = current_row.rect();
3511
3512 if row == start_row {
3513 let selection_rect = Rect::from_min_max(
3515 Pos2::new(
3516 position.x + start_pos.x,
3517 position.y + row as f32 * row_height,
3518 ),
3519 Pos2::new(
3520 position.x + row_rect.max.x,
3521 position.y + row as f32 * row_height + row_height,
3522 ),
3523 );
3524 ui.painter().rect_filled(
3525 selection_rect,
3526 0.0,
3527 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3528 );
3529 } else if row == end_row {
3530 let selection_rect = Rect::from_min_max(
3532 Pos2::new(
3533 position.x + row_rect.min.x,
3534 position.y + row as f32 * row_height,
3535 ),
3536 Pos2::new(
3537 position.x + end_pos.x,
3538 position.y + row as f32 * row_height + row_height,
3539 ),
3540 );
3541 ui.painter().rect_filled(
3542 selection_rect,
3543 0.0,
3544 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3545 );
3546 } else {
3547 let selection_rect = Rect::from_min_max(
3549 Pos2::new(
3550 position.x + row_rect.min.x,
3551 position.y + row as f32 * row_height,
3552 ),
3553 Pos2::new(
3554 position.x + row_rect.max.x,
3555 position.y + row as f32 * row_height + row_height,
3556 ),
3557 );
3558 ui.painter().rect_filled(
3559 selection_rect,
3560 0.0,
3561 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3562 );
3563 };
3564 };
3565 }
3566 };
3567 };
3568 }
3569 t.last_frame_content = t.content.clone();
3570 self.replace_resource(name, "Text", t).unwrap();
3571 Ok(())
3572 }
3573
3574 pub fn add_var<T: Debug + 'static>(&mut self, variable: Variable<T>) {
3576 self.rust_constructor_resource.push(Box::new(variable));
3577 }
3578
3579 pub fn modify_var<T: Debug + 'static>(
3581 &mut self,
3582 name: &str,
3583 value: Option<T>,
3584 safe_mode: Option<bool>,
3585 ) -> Result<(), RustConstructorError> {
3586 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3587 && !self.check_resource_exists(name, "Variable")
3588 {
3589 self.problem_report_custom(
3590 RustConstructorError::VariableNotFound {
3591 variable_name: name.to_string(),
3592 },
3593 SeverityLevel::SevereWarning,
3594 self.problem_list.clone(),
3595 );
3596 return Err(RustConstructorError::VariableNotFound {
3597 variable_name: name.to_string(),
3598 });
3599 };
3600 let v = self
3601 .get_resource_mut::<Variable<T>>(name, "Variable")
3602 .unwrap();
3603 v.value = value;
3604 Ok(())
3605 }
3606
3607 pub fn var<T: Debug + 'static>(
3609 &self,
3610 name: &str,
3611 safe_mode: Option<bool>,
3612 ) -> Result<Option<&T>, RustConstructorError> {
3613 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
3614 if !self.check_resource_exists(name, "Variable") {
3615 self.problem_report_custom(
3616 RustConstructorError::VariableNotFound {
3617 variable_name: name.to_string(),
3618 },
3619 SeverityLevel::SevereWarning,
3620 self.problem_list.clone(),
3621 );
3622 return Err(RustConstructorError::VariableNotFound {
3623 variable_name: name.to_string(),
3624 });
3625 };
3626 if self
3627 .get_resource::<Variable<T>>(name, "Variable")
3628 .unwrap()
3629 .is_none()
3630 {
3631 self.problem_report_custom(
3632 RustConstructorError::VariableTypeMismatch {
3633 variable_name: name.to_string(),
3634 },
3635 SeverityLevel::SevereWarning,
3636 self.problem_list.clone(),
3637 );
3638 return Err(RustConstructorError::VariableTypeMismatch {
3639 variable_name: name.to_string(),
3640 });
3641 };
3642 };
3643 let v = self
3644 .get_resource::<Variable<T>>(name, "Variable")
3645 .unwrap()
3646 .unwrap();
3647 Ok(v.value.as_ref())
3648 }
3649
3650 pub fn add_image_texture(
3652 &mut self,
3653 mut image_texture: ImageTexture,
3654 path: &str,
3655 flip: [bool; 2],
3656 ctx: &Context,
3657 ) {
3658 if let Ok(mut file) = File::open(path) {
3659 let mut buffer = Vec::new();
3660 file.read_to_end(&mut buffer).unwrap();
3661 let img_bytes = buffer;
3662 let img = image::load_from_memory(&img_bytes).unwrap();
3663 let color_data = match flip {
3664 [true, true] => img.fliph().flipv().into_rgba8(),
3665 [true, false] => img.fliph().into_rgba8(),
3666 [false, true] => img.flipv().into_rgba8(),
3667 _ => img.into_rgba8(),
3668 };
3669 let (w, h) = (color_data.width(), color_data.height());
3670 let raw_data: Vec<u8> = color_data.into_raw();
3671
3672 let color_image =
3673 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3674 let loaded_image_texture = ctx.load_texture(
3675 image_texture.name.clone(),
3676 color_image,
3677 TextureOptions::LINEAR,
3678 );
3679 image_texture.texture = Some(DebugTextureHandle::new(loaded_image_texture));
3680 image_texture.cite_path = path.to_string();
3681 self.rust_constructor_resource.push(Box::new(image_texture));
3682 } else {
3683 self.problem_report_custom(
3684 RustConstructorError::ImageGetFailed {
3685 image_path: path.to_string(),
3686 },
3687 SeverityLevel::SevereWarning,
3688 self.problem_list.clone(),
3689 );
3690 };
3691 }
3692
3693 pub fn image_texture(
3695 &self,
3696 name: &str,
3697 safe_mode: Option<bool>,
3698 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3699 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3700 && !self.check_resource_exists(name, "ImageTexture")
3701 {
3702 self.problem_report_custom(
3703 RustConstructorError::ImageNotFound {
3704 image_name: name.to_string(),
3705 },
3706 SeverityLevel::SevereWarning,
3707 self.problem_list.clone(),
3708 );
3709 return Err(RustConstructorError::ImageNotFound {
3710 image_name: name.to_string(),
3711 });
3712 };
3713 let it = self
3714 .get_resource::<ImageTexture>(name, "ImageTexture")
3715 .unwrap()
3716 .unwrap();
3717 Ok(it.texture.clone())
3718 }
3719
3720 pub fn reset_image_texture(
3722 &mut self,
3723 name: &str,
3724 path: &str,
3725 flip: [bool; 2],
3726 ctx: &Context,
3727 safe_mode: Option<bool>,
3728 ) -> Result<(), RustConstructorError> {
3729 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3730 && !self.check_resource_exists(name, "ImageTexture")
3731 {
3732 self.problem_report_custom(
3733 RustConstructorError::ImageTextureNotFound {
3734 image_texture_name: name.to_string(),
3735 },
3736 SeverityLevel::SevereWarning,
3737 self.problem_list.clone(),
3738 );
3739 return Err(RustConstructorError::ImageTextureNotFound {
3740 image_texture_name: name.to_string(),
3741 });
3742 };
3743 let it = self
3744 .get_resource_mut::<ImageTexture>(name, "ImageTexture")
3745 .unwrap();
3746 if let Ok(mut file) = File::open(path) {
3747 let mut buffer = Vec::new();
3748 file.read_to_end(&mut buffer).unwrap();
3749 let img_bytes = buffer;
3750 let img = image::load_from_memory(&img_bytes).unwrap();
3751 let color_data = match flip {
3752 [true, true] => img.fliph().flipv().into_rgba8(),
3753 [true, false] => img.fliph().into_rgba8(),
3754 [false, true] => img.flipv().into_rgba8(),
3755 _ => img.into_rgba8(),
3756 };
3757 let (w, h) = (color_data.width(), color_data.height());
3758 let raw_data: Vec<u8> = color_data.into_raw();
3759
3760 let color_image =
3761 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3762 let image_texture =
3763 ctx.load_texture(it.name.clone(), color_image, TextureOptions::LINEAR);
3764 it.texture = Some(DebugTextureHandle::new(image_texture));
3765 it.cite_path = path.to_string();
3766 } else {
3767 self.problem_report_custom(
3768 RustConstructorError::ImageGetFailed {
3769 image_path: path.to_string(),
3770 },
3771 SeverityLevel::SevereWarning,
3772 self.problem_list.clone(),
3773 );
3774 };
3775 Ok(())
3776 }
3777
3778 pub fn add_image(
3780 &mut self,
3781 mut image: Image,
3782 image_texture_name: &str,
3783 safe_mode: Option<bool>,
3784 ) -> Result<(), RustConstructorError> {
3785 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3786 && !self.check_resource_exists(image_texture_name, "ImageTexture")
3787 {
3788 self.problem_report_custom(
3789 RustConstructorError::ImageTextureNotFound {
3790 image_texture_name: image_texture_name.to_string(),
3791 },
3792 SeverityLevel::SevereWarning,
3793 self.problem_list.clone(),
3794 );
3795 return Err(RustConstructorError::ImageTextureNotFound {
3796 image_texture_name: image_texture_name.to_string(),
3797 });
3798 };
3799 let it = self
3800 .get_resource::<ImageTexture>(image_texture_name, "ImageTexture")
3801 .unwrap()
3802 .unwrap();
3803 image.texture = it.texture.clone();
3804 image.cite_texture = it.name.clone();
3805 image.last_frame_cite_texture = it.name.clone();
3806 self.rust_constructor_resource.push(Box::new(image));
3807 Ok(())
3808 }
3809
3810 pub fn image(
3812 &mut self,
3813 name: &str,
3814 ui: &mut Ui,
3815 ctx: &Context,
3816 safe_mode: Option<bool>,
3817 ) -> Result<(), RustConstructorError> {
3818 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3819 && !self.check_resource_exists(name, "Image")
3820 {
3821 self.problem_report_custom(
3822 RustConstructorError::ImageNotFound {
3823 image_name: name.to_string(),
3824 },
3825 SeverityLevel::SevereWarning,
3826 self.problem_list.clone(),
3827 );
3828 return Err(RustConstructorError::ImageNotFound {
3829 image_name: name.to_string(),
3830 });
3831 };
3832 let mut im = self
3833 .get_resource_mut::<Image>(name, "Image")
3834 .unwrap()
3835 .clone();
3836 if im.cite_texture != im.last_frame_cite_texture {
3837 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3838 && !self.check_resource_exists(&im.cite_texture, "ImageTexture")
3839 {
3840 self.problem_report_custom(
3841 RustConstructorError::ImageTextureNotFound {
3842 image_texture_name: im.cite_texture.clone(),
3843 },
3844 SeverityLevel::MildWarning,
3845 self.problem_list.clone(),
3846 );
3847 } else {
3848 let it = self
3849 .get_resource::<ImageTexture>(&im.cite_texture, "ImageTexture")
3850 .unwrap()
3851 .unwrap();
3852 im.texture = it.texture.clone();
3853 };
3854 };
3855 im.reg_render_resource(&mut self.render_resource_list);
3856 im.position[0] = match im.x_grid[1] {
3857 0 => im.origin_position[0],
3858 _ => {
3859 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64 * im.x_grid[0] as f64)
3860 as f32
3861 + im.origin_position[0]
3862 }
3863 };
3864 im.position[1] = match im.y_grid[1] {
3865 0 => im.origin_position[1],
3866 _ => {
3867 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64 * im.y_grid[0] as f64)
3868 as f32
3869 + im.origin_position[1]
3870 }
3871 };
3872 match im.center_display.0 {
3873 HorizontalAlign::Left => {}
3874 HorizontalAlign::Center => im.position[0] -= im.size[0] / 2.0,
3875 HorizontalAlign::Right => im.position[0] -= im.size[0],
3876 };
3877 match im.center_display.1 {
3878 VerticalAlign::Top => {}
3879 VerticalAlign::Center => im.position[1] -= im.size[1] / 2.0,
3880 VerticalAlign::Bottom => im.position[1] -= im.size[1],
3881 };
3882 im.position[0] += im.offset[0];
3883 im.position[1] += im.offset[1];
3884 if let Some(texture) = &im.texture {
3885 let rect = Rect::from_min_size(
3886 Pos2::new(im.position[0], im.position[1]),
3887 Vec2::new(im.size[0], im.size[1]),
3888 );
3889
3890 egui::Image::new(ImageSource::Texture((&texture.0).into()))
3892 .tint(Color32::from_rgba_unmultiplied(
3893 im.overlay_color[0],
3894 im.overlay_color[1],
3895 im.overlay_color[2],
3896 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
3898 ))
3899 .bg_fill(Color32::from_rgba_unmultiplied(
3900 im.background_color[0],
3901 im.background_color[1],
3902 im.background_color[2],
3903 im.background_color[3],
3904 ))
3905 .rotate(
3906 im.rotate_angle,
3907 [
3908 im.rotate_center[0] / im.size[0],
3909 im.rotate_center[1] / im.size[1],
3910 ]
3911 .into(),
3912 )
3913 .paint_at(ui, rect)
3914 };
3915 im.last_frame_cite_texture = im.cite_texture.clone();
3916 self.replace_resource(name, "Image", im).unwrap();
3917 Ok(())
3918 }
3919
3920 #[allow(clippy::too_many_arguments)]
3922 pub fn add_message_box(
3923 &mut self,
3924 mut message_box: MessageBox,
3925 title_name: &str,
3926 content_name: &str,
3927 image_name: &str,
3928 close_switch_fill_resource_name: &str,
3929 close_switch_fill_resource_type: &str,
3930 safe_mode: Option<bool>,
3931 ) -> Result<(), RustConstructorError> {
3932 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3933 && self.check_resource_exists(&message_box.name, "MessageBox")
3934 {
3935 self.problem_report_custom(
3936 RustConstructorError::MessageBoxAlreadyExists {
3937 message_box_name: message_box.name.to_string(),
3938 },
3939 SeverityLevel::SevereWarning,
3940 self.problem_list.clone(),
3941 );
3942 return Err(RustConstructorError::MessageBoxAlreadyExists {
3943 message_box_name: message_box.name.to_string(),
3944 });
3945 };
3946 message_box.exist = true;
3947 message_box.memory_offset = 0_f32;
3948
3949 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3950 && !self.check_resource_exists(image_name, "Image")
3951 {
3952 self.problem_report_custom(
3953 RustConstructorError::ImageNotFound {
3954 image_name: image_name.to_string(),
3955 },
3956 SeverityLevel::SevereWarning,
3957 self.problem_list.clone(),
3958 );
3959 return Err(RustConstructorError::ImageNotFound {
3960 image_name: image_name.to_string(),
3961 });
3962 };
3963 let im = self.get_resource_mut::<Image>(image_name, "Image").unwrap();
3964 im.size = [message_box.size[1] - 15_f32, message_box.size[1] - 15_f32];
3965 im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
3966 im.x_grid = [1, 1];
3967 im.y_grid = [0, 1];
3968 im.name = format!("MessageBox{}", im.name);
3969 message_box.image_name = im.name.to_string();
3970
3971 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3972 && !self.check_resource_exists(title_name, "Text")
3973 {
3974 self.problem_report_custom(
3975 RustConstructorError::TextNotFound {
3976 text_name: title_name.to_string(),
3977 },
3978 SeverityLevel::SevereWarning,
3979 self.problem_list.clone(),
3980 );
3981 return Err(RustConstructorError::TextNotFound {
3982 text_name: title_name.to_string(),
3983 });
3984 };
3985 let t = self.get_resource_mut::<Text>(title_name, "Text").unwrap();
3986 t.x_grid = [1, 1];
3987 t.y_grid = [0, 1];
3988 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3989 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
3990 t.name = format!("MessageBox{}", t.name);
3991 message_box.title_name = t.name.to_string();
3992
3993 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3994 && !self.check_resource_exists(content_name, "Text")
3995 {
3996 self.problem_report_custom(
3997 RustConstructorError::TextNotFound {
3998 text_name: content_name.to_string(),
3999 },
4000 SeverityLevel::SevereWarning,
4001 self.problem_list.clone(),
4002 );
4003 return Err(RustConstructorError::TextNotFound {
4004 text_name: content_name.to_string(),
4005 });
4006 };
4007 let t = self.get_resource_mut::<Text>(content_name, "Text").unwrap();
4008 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
4009 t.x_grid = [1, 1];
4010 t.y_grid = [0, 1];
4011 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
4012 t.name = format!("MessageBox{}", t.name);
4013 message_box.content_name = t.name.to_string();
4014
4015 if !message_box.keep_existing {
4016 self.add_split_time(
4017 SplitTime::default().name(&format!("MessageBox{}", message_box.name)),
4018 );
4019 };
4020
4021 self.add_split_time(
4022 SplitTime::default().name(&format!("MessageBox{}Animation", message_box.name)),
4023 );
4024
4025 self.add_custom_rect(
4026 CustomRect::default()
4027 .name(&format!("MessageBox{}", message_box.name))
4028 .origin_position(0_f32, 0_f32)
4029 .size(message_box.size[0], message_box.size[1])
4030 .rounding(20_f32)
4031 .x_grid(1, 1)
4032 .y_grid(0, 1)
4033 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4034 .color(100, 100, 100, 125)
4035 .border_width(0_f32),
4036 );
4037
4038 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4039 match close_switch_fill_resource_type {
4040 "Image" | "CustomRect" => {}
4041 &_ => {
4042 self.problem_report_custom(
4043 RustConstructorError::SwitchFillResourceMismatch {
4044 switch_name: format!("MessageBox{}Close", message_box.name),
4045 fill_resource_name: close_switch_fill_resource_name.to_string(),
4046 fill_resource_type: close_switch_fill_resource_type.to_string(),
4047 },
4048 SeverityLevel::SevereWarning,
4049 self.problem_list.clone(),
4050 );
4051 return Err(RustConstructorError::SwitchFillResourceMismatch {
4052 switch_name: format!("MessageBox{}Close", message_box.name),
4053 fill_resource_name: close_switch_fill_resource_name.to_string(),
4054 fill_resource_type: close_switch_fill_resource_type.to_string(),
4055 });
4056 }
4057 };
4058 };
4059
4060 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4061 && !self.check_resource_exists(
4062 close_switch_fill_resource_name,
4063 close_switch_fill_resource_type,
4064 )
4065 {
4066 self.problem_report_custom(
4067 RustConstructorError::ResourceNotFound {
4068 resource_name: close_switch_fill_resource_name.to_string(),
4069 resource_type: close_switch_fill_resource_type.to_string(),
4070 },
4071 SeverityLevel::SevereWarning,
4072 self.problem_list.clone(),
4073 );
4074 return Err(RustConstructorError::ResourceNotFound {
4075 resource_name: close_switch_fill_resource_name.to_string(),
4076 resource_type: close_switch_fill_resource_type.to_string(),
4077 });
4078 };
4079
4080 let (texture, image_config, custom_rect_config, color, border_color) =
4081 match close_switch_fill_resource_type {
4082 "Image" => {
4083 let im = self
4084 .get_resource_mut::<Image>(close_switch_fill_resource_name, "Image")
4085 .unwrap();
4086 im.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4087 (
4088 im.cite_texture.clone(),
4089 ImageConfig::from_image(im.clone())
4090 .size(30_f32, 30_f32)
4091 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4092 CustomRectConfig::default(),
4093 im.overlay_color,
4094 [0, 0, 0, 0],
4095 )
4096 }
4097 "CustomRect" => {
4098 let cr = self
4099 .get_resource_mut::<CustomRect>(
4100 close_switch_fill_resource_name,
4101 "CustomRect",
4102 )
4103 .unwrap();
4104 cr.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4105 (
4106 String::new(),
4107 ImageConfig::default(),
4108 CustomRectConfig::from_custom_rect(cr.clone())
4109 .size(30_f32, 30_f32)
4110 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4111 cr.color,
4112 cr.border_color,
4113 )
4114 }
4115 &_ => {
4116 self.problem_report_custom(
4117 RustConstructorError::SwitchFillResourceMismatch {
4118 switch_name: format!("MessageBox{}Close", message_box.name),
4119 fill_resource_name: close_switch_fill_resource_name.to_string(),
4120 fill_resource_type: close_switch_fill_resource_type.to_string(),
4121 },
4122 SeverityLevel::SevereWarning,
4123 self.problem_list.clone(),
4124 );
4125 return Err(RustConstructorError::SwitchFillResourceMismatch {
4126 switch_name: format!("MessageBox{}Close", message_box.name),
4127 fill_resource_name: close_switch_fill_resource_name.to_string(),
4128 fill_resource_type: close_switch_fill_resource_type.to_string(),
4129 });
4130 }
4131 };
4132
4133 self.add_switch(
4134 Switch::default()
4135 .name(&format!("MessageBox{}Close", message_box.name))
4136 .appearance(vec![
4137 SwitchAppearance {
4138 image_config: image_config
4139 .clone()
4140 .overlay_color(color[0], color[1], color[2], 0),
4141 custom_rect_config: custom_rect_config
4142 .clone()
4143 .color(color[0], color[1], color[2], 0)
4144 .border_color(border_color[0], border_color[1], border_color[2], 0),
4145 text_config: TextConfig::default(),
4146 texture: texture.clone(),
4147 hint_text: String::new(),
4148 },
4149 SwitchAppearance {
4150 image_config: image_config.clone().overlay_color(
4151 (color[0] as u32 * 180 / 255) as u8,
4152 (color[1] as u32 * 180 / 255) as u8,
4153 (color[2] as u32 * 180 / 255) as u8,
4154 255,
4155 ),
4156 custom_rect_config: custom_rect_config
4157 .clone()
4158 .color(
4159 (color[0] as u32 * 180 / 255) as u8,
4160 (color[1] as u32 * 180 / 255) as u8,
4161 (color[2] as u32 * 180 / 255) as u8,
4162 255,
4163 )
4164 .border_color(
4165 (border_color[0] as u32 * 180 / 255) as u8,
4166 (border_color[1] as u32 * 180 / 255) as u8,
4167 (border_color[2] as u32 * 180 / 255) as u8,
4168 255,
4169 ),
4170 text_config: TextConfig::default(),
4171 texture: texture.clone(),
4172 hint_text: String::new(),
4173 },
4174 SwitchAppearance {
4175 image_config: image_config.clone().overlay_color(0, 0, 0, 0),
4176 custom_rect_config: custom_rect_config
4177 .clone()
4178 .color(0, 0, 0, 0)
4179 .border_color(0, 0, 0, 0),
4180 text_config: TextConfig::default(),
4181 texture: texture.clone(),
4182 hint_text: String::new(),
4183 },
4184 SwitchAppearance {
4185 image_config: image_config.overlay_color(0, 0, 0, 0),
4186 custom_rect_config: custom_rect_config
4187 .color(0, 0, 0, 0)
4188 .border_color(0, 0, 0, 0),
4189 text_config: TextConfig::default(),
4190 texture,
4191 hint_text: String::new(),
4192 },
4193 ])
4194 .enable_hover_click_fill_resource(false, true)
4195 .click_method(vec![SwitchClickAction {
4196 click_method: PointerButton::Primary,
4197 action: true,
4198 }]),
4199 &format!("MessageBox{}Close", close_switch_fill_resource_name),
4200 close_switch_fill_resource_type,
4201 "",
4202 )
4203 .unwrap();
4204 self.rust_constructor_resource
4205 .push(Box::new(message_box.clone()));
4206 Ok(())
4207 }
4208
4209 pub fn message_box_display(&mut self, ctx: &Context, ui: &mut Ui, safe_mode: Option<bool>) {
4211 let mut offset = 0_f32;
4212 let mut delete_count = 0;
4213 let mut index_list = Vec::new();
4214 for i in 0..self.rust_constructor_resource.len() {
4215 if self.rust_constructor_resource[i]
4216 .as_any()
4217 .downcast_ref::<MessageBox>()
4218 .is_some()
4219 {
4220 index_list.push(i);
4221 };
4222 }
4223 for u in 0..index_list.len() {
4224 let mut deleted = false;
4225 let i = u - delete_count;
4226 let mut mb = self.rust_constructor_resource[index_list[i]]
4227 .as_any()
4228 .downcast_ref::<MessageBox>()
4229 .unwrap()
4230 .clone();
4231 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4232 if !self.check_resource_exists(&mb.image_name, "Image") {
4233 self.problem_report_custom(
4234 RustConstructorError::ImageNotFound {
4235 image_name: mb.image_name,
4236 },
4237 SeverityLevel::SevereWarning,
4238 self.problem_list.clone(),
4239 );
4240 continue;
4241 };
4242 if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "CustomRect") {
4243 self.problem_report_custom(
4244 RustConstructorError::RectNotFound {
4245 rect_name: format!("MessageBox{}", mb.name),
4246 },
4247 SeverityLevel::SevereWarning,
4248 self.problem_list.clone(),
4249 );
4250 continue;
4251 };
4252 if !self.check_resource_exists(&mb.title_name, "Text") {
4253 self.problem_report_custom(
4254 RustConstructorError::TextNotFound {
4255 text_name: mb.title_name,
4256 },
4257 SeverityLevel::SevereWarning,
4258 self.problem_list.clone(),
4259 );
4260 continue;
4261 };
4262 if !self.check_resource_exists(&mb.content_name, "Text") {
4263 self.problem_report_custom(
4264 RustConstructorError::TextNotFound {
4265 text_name: mb.content_name,
4266 },
4267 SeverityLevel::SevereWarning,
4268 self.problem_list.clone(),
4269 );
4270 continue;
4271 };
4272 if !self.check_resource_exists(&format!("MessageBox{}Close", mb.name), "Switch") {
4273 self.problem_report_custom(
4274 RustConstructorError::SwitchNotFound {
4275 switch_name: format!("MessageBox{}Close", mb.name),
4276 },
4277 SeverityLevel::SevereWarning,
4278 self.problem_list.clone(),
4279 );
4280 continue;
4281 };
4282 if !self
4283 .check_resource_exists(&format!("MessageBox{}Animation", mb.name), "SplitTime")
4284 {
4285 self.problem_report_custom(
4286 RustConstructorError::SplitTimeNotFound {
4287 split_time_name: format!("MessageBox{}Animation", mb.name),
4288 },
4289 SeverityLevel::SevereWarning,
4290 self.problem_list.clone(),
4291 );
4292 continue;
4293 };
4294 if !mb.keep_existing
4295 && !self.check_resource_exists(&format!("MessageBox{}", mb.name), "SplitTime")
4296 {
4297 self.problem_report_custom(
4298 RustConstructorError::SplitTimeNotFound {
4299 split_time_name: format!("MessageBox{}", mb.name),
4300 },
4301 SeverityLevel::SevereWarning,
4302 self.problem_list.clone(),
4303 );
4304 continue;
4305 };
4306 };
4307 let mut im1 = self
4308 .get_resource::<Image>(&mb.image_name, "Image")
4309 .unwrap()
4310 .unwrap()
4311 .clone();
4312 let mut cr = self
4313 .get_resource::<CustomRect>(&format!("MessageBox{}", mb.name), "CustomRect")
4314 .unwrap()
4315 .unwrap()
4316 .clone();
4317 let mut t1 = self
4318 .get_resource::<Text>(&mb.title_name, "Text")
4319 .unwrap()
4320 .unwrap()
4321 .clone();
4322 let mut t2 = self
4323 .get_resource::<Text>(&mb.content_name, "Text")
4324 .unwrap()
4325 .unwrap()
4326 .clone();
4327 let mut s = self
4328 .get_resource::<Switch>(&format!("MessageBox{}Close", mb.name), "Switch")
4329 .unwrap()
4330 .unwrap()
4331 .clone();
4332 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4333 && !self.check_resource_exists(&s.fill_resource_name, &s.fill_resource_type)
4334 {
4335 self.problem_report_custom(
4336 RustConstructorError::ResourceNotFound {
4337 resource_name: s.fill_resource_name,
4338 resource_type: s.fill_resource_type,
4339 },
4340 SeverityLevel::SevereWarning,
4341 self.problem_list.clone(),
4342 );
4343 continue;
4344 };
4345 let fr: Box<dyn BasicFrontResource> = match s.fill_resource_type.as_str() {
4346 "Image" => Box::new(
4347 self.get_resource::<Image>(&s.fill_resource_name, "Image")
4348 .unwrap()
4349 .unwrap()
4350 .clone(),
4351 ),
4352 "CustomRect" => Box::new(
4353 self.get_resource::<CustomRect>(&s.fill_resource_name, "CustomRect")
4354 .unwrap()
4355 .unwrap()
4356 .clone(),
4357 ),
4358 &_ => {
4359 self.problem_report_custom(
4360 RustConstructorError::SwitchFillResourceMismatch {
4361 switch_name: s.name,
4362 fill_resource_name: s.fill_resource_name,
4363 fill_resource_type: s.fill_resource_type,
4364 },
4365 SeverityLevel::SevereWarning,
4366 self.problem_list.clone(),
4367 );
4368 continue;
4369 }
4370 };
4371 mb.reg_render_resource(&mut self.render_resource_list.clone());
4372 if mb.size[1] < t1.size[1] + t2.size[1] + 10_f32 {
4373 mb.size[1] = t1.size[1] + t2.size[1] + 10_f32;
4374 cr.size[1] = mb.size[1];
4375 im1.size = [mb.size[1] - 15_f32, mb.size[1] - 15_f32];
4376 t1.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4377 t2.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4378 };
4379 if self.timer.total_time
4380 - self
4381 .split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4382 .unwrap()[1]
4383 >= self.tick_interval
4384 {
4385 self.reset_split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4386 .unwrap();
4387 if offset != mb.memory_offset {
4388 if mb.memory_offset < offset {
4389 if mb.memory_offset + mb.restore_speed >= offset {
4390 mb.memory_offset = offset;
4391 } else {
4392 mb.memory_offset += mb.restore_speed;
4393 };
4394 } else if mb.memory_offset - mb.restore_speed <= offset {
4395 mb.memory_offset = offset;
4396 } else {
4397 mb.memory_offset -= mb.restore_speed;
4398 };
4399 };
4400 if cr.origin_position[0] != -mb.size[0] - 5_f32 {
4401 if mb.exist {
4402 if cr.origin_position[0] - mb.speed <= -mb.size[0] - 5_f32 {
4403 cr.origin_position[0] = -mb.size[0] - 5_f32;
4404 if self.check_resource_exists(
4405 &format!("MessageBox{}", mb.name),
4406 "SplitTime",
4407 ) {
4408 self.reset_split_time(&format!("MessageBox{}", mb.name), safe_mode)
4409 .unwrap();
4410 };
4411 } else {
4412 cr.origin_position[0] -= mb.speed;
4413 };
4414 } else if cr.origin_position[0] + mb.speed >= 15_f32 {
4415 cr.origin_position[0] = 15_f32;
4416 delete_count += 1;
4417 deleted = true;
4418 } else {
4419 cr.origin_position[0] += mb.speed;
4420 };
4421 };
4422 };
4423 cr.origin_position[1] = mb.memory_offset + 20_f32;
4424 im1.origin_position = [
4425 cr.origin_position[0] + 5_f32,
4426 cr.origin_position[1] + mb.size[1] / 2_f32,
4427 ];
4428 t1.origin_position = [
4429 im1.origin_position[0] + im1.size[0] + 5_f32,
4430 cr.origin_position[1] + 5_f32,
4431 ];
4432 t2.origin_position = [
4433 im1.origin_position[0] + im1.size[0] + 5_f32,
4434 t1.origin_position[1] + t1.size[1],
4435 ];
4436 for sd in &mut s.appearance {
4437 sd.image_config.origin_position = cr.position;
4438 sd.custom_rect_config.origin_position = cr.position;
4439 }
4440 if !mb.keep_existing
4441 && self.timer.total_time
4442 - self
4443 .split_time(&format!("MessageBox{}", mb.name), safe_mode)
4444 .unwrap()[1]
4445 >= mb.existing_time
4446 && cr.origin_position[0] == -mb.size[0] - 5_f32
4447 {
4448 mb.exist = false;
4449 if cr.origin_position[0] + mb.speed >= 15_f32 {
4450 cr.origin_position[0] = 15_f32;
4451 } else {
4452 cr.origin_position[0] += mb.speed;
4453 };
4454 };
4455 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4456 let rect = Rect::from_min_size(
4457 Pos2 {
4458 x: fr.position()[0],
4459 y: fr.position()[1],
4460 },
4461 Vec2 {
4462 x: cr.size[0] + 15_f32,
4463 y: cr.size[1] + 15_f32,
4464 },
4465 );
4466 if rect.contains(mouse_pos) {
4467 s.appearance[0].image_config.overlay_color[3] = 255;
4468 s.appearance[0].custom_rect_config.color[3] = 255;
4469 s.appearance[0].custom_rect_config.border_color[3] = 255;
4470 } else {
4471 s.appearance[0].image_config.overlay_color[3] = 0;
4472 s.appearance[0].custom_rect_config.color[3] = 0;
4473 s.appearance[0].custom_rect_config.border_color[3] = 0;
4474 };
4475 };
4476 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4477 self.replace_resource(&mb.image_name, "Image", im1.clone())
4478 .unwrap();
4479 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4480 .unwrap();
4481 self.replace_resource(&mb.title_name, "Text", t1.clone())
4482 .unwrap();
4483 self.replace_resource(&mb.content_name, "Text", t2.clone())
4484 .unwrap();
4485 self.replace_resource(&format!("MessageBox{}Close", mb.name), "Switch", s.clone())
4486 .unwrap();
4487 match s.fill_resource_type.as_str() {
4488 "Image" => {
4489 self.replace_resource(
4490 &s.fill_resource_name,
4491 &s.fill_resource_type,
4492 fr.as_any().downcast_ref::<Image>().unwrap().clone(),
4493 )
4494 .unwrap();
4495 }
4496 "CustomRect" => {
4497 self.replace_resource(
4498 &s.fill_resource_name,
4499 &s.fill_resource_type,
4500 fr.as_any().downcast_ref::<CustomRect>().unwrap().clone(),
4501 )
4502 .unwrap();
4503 }
4504 &_ => {
4505 self.problem_report_custom(
4506 RustConstructorError::SwitchFillResourceMismatch {
4507 switch_name: s.name,
4508 fill_resource_name: s.fill_resource_name,
4509 fill_resource_type: s.fill_resource_type,
4510 },
4511 SeverityLevel::SevereWarning,
4512 self.problem_list.clone(),
4513 );
4514 continue;
4515 }
4516 };
4517 self.custom_rect(&format!("MessageBox{}", mb.name), ui, ctx, safe_mode)
4518 .unwrap();
4519 self.image(&mb.image_name.clone(), ui, ctx, safe_mode)
4520 .unwrap();
4521 self.text(&t1.name.clone(), ui, ctx, safe_mode).unwrap();
4522 self.text(&t2.name.clone(), ui, ctx, safe_mode).unwrap();
4523 self.switch(
4524 &format!("MessageBox{}Close", mb.name),
4525 ui,
4526 ctx,
4527 s.state == 0 && mb.exist,
4528 safe_mode,
4529 )
4530 .unwrap();
4531 let switch_data = self
4532 .check_switch_data(&format!("MessageBox{}Close", mb.name), safe_mode)
4533 .unwrap();
4534 if switch_data.last_time_clicked_index == 0
4535 && switch_data.state == 1
4536 && switch_data.switched
4537 {
4538 mb.exist = false;
4539 if cr.origin_position[0] + mb.speed >= 15_f32 {
4540 cr.origin_position[0] = 15_f32;
4541 } else {
4542 cr.origin_position[0] += mb.speed;
4543 };
4544 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4545 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4546 .unwrap();
4547 };
4548 if deleted {
4549 self.rust_constructor_resource.remove(
4550 self.rust_constructor_resource
4551 .iter()
4552 .position(|x| x.expose_type() == "Image" && x.name() == mb.image_name)
4553 .unwrap(),
4554 );
4555 self.rust_constructor_resource.remove(
4556 self.rust_constructor_resource
4557 .iter()
4558 .position(|x| {
4559 x.expose_type() == "CustomRect"
4560 && x.name() == format!("MessageBox{}", mb.name)
4561 })
4562 .unwrap(),
4563 );
4564 self.rust_constructor_resource.remove(
4565 self.rust_constructor_resource
4566 .iter()
4567 .position(|x| x.expose_type() == "Text" && x.name() == mb.title_name)
4568 .unwrap(),
4569 );
4570 self.rust_constructor_resource.remove(
4571 self.rust_constructor_resource
4572 .iter()
4573 .position(|x| x.expose_type() == "Text" && x.name() == mb.content_name)
4574 .unwrap(),
4575 );
4576 self.rust_constructor_resource.remove(
4577 self.rust_constructor_resource
4578 .iter()
4579 .position(|x| {
4580 x.expose_type() == "Switch"
4581 && x.name() == format!("MessageBox{}Close", mb.name)
4582 })
4583 .unwrap(),
4584 );
4585 self.rust_constructor_resource.remove(
4586 self.rust_constructor_resource
4587 .iter()
4588 .position(|x| {
4589 x.expose_type() == s.fill_resource_type
4590 && x.name() == s.fill_resource_name
4591 })
4592 .unwrap(),
4593 );
4594 self.rust_constructor_resource.remove(
4595 self.rust_constructor_resource
4596 .iter()
4597 .position(|x| {
4598 x.expose_type() == "SplitTime"
4599 && x.name() == format!("MessageBox{}Animation", mb.name)
4600 })
4601 .unwrap(),
4602 );
4603 if !mb.keep_existing {
4604 self.rust_constructor_resource.remove(
4605 self.rust_constructor_resource
4606 .iter()
4607 .position(|x| {
4608 x.expose_type() == "SplitTime"
4609 && x.name() == format!("MessageBox{}", mb.name)
4610 })
4611 .unwrap(),
4612 );
4613 };
4614 self.rust_constructor_resource.remove(
4615 self.rust_constructor_resource
4616 .iter()
4617 .position(|x| x.expose_type() == "MessageBox" && x.name() == mb.name)
4618 .unwrap(),
4619 );
4620 self.rust_constructor_resource.remove(
4621 self.rust_constructor_resource
4622 .iter()
4623 .position(|x| x.expose_type() == "MouseDetector" && x.name() == t1.name)
4624 .unwrap(),
4625 );
4626 self.rust_constructor_resource.remove(
4627 self.rust_constructor_resource
4628 .iter()
4629 .position(|x| x.expose_type() == "MouseDetector" && x.name() == t2.name)
4630 .unwrap(),
4631 );
4632 } else {
4633 offset += mb.size[1] + 15_f32;
4634 };
4635 }
4636 }
4637
4638 pub fn add_switch(
4640 &mut self,
4641 mut switch: Switch,
4642 fill_resource_name: &str,
4643 fill_resource_type: &str,
4644 text_name: &str,
4645 ) -> Result<(), RustConstructorError> {
4646 let mut count = 1;
4647 if switch.enable_hover_click_fill_resource[0] {
4648 count += 1;
4649 };
4650 if switch.enable_hover_click_fill_resource[1] {
4651 count += 1;
4652 };
4653 if switch.appearance.len() < count {
4654 self.problem_report_custom(
4655 RustConstructorError::SwitchAppearanceMismatch {
4656 switch_name: switch.name.clone(),
4657 differ: count as u32 - switch.appearance.len() as u32,
4658 },
4659 SeverityLevel::SevereWarning,
4660 self.problem_list.clone(),
4661 );
4662 return Err(RustConstructorError::SwitchAppearanceMismatch {
4663 switch_name: switch.name.clone(),
4664 differ: count as u32 - switch.appearance.len() as u32,
4665 });
4666 };
4667 for _ in 0..switch.appearance.len() % count {
4668 switch.appearance.pop();
4669 }
4670 switch.text_name = "".to_string();
4671 if self.check_resource_exists(text_name, "Text") {
4672 let t = self.get_resource_mut::<Text>(text_name, "Text").unwrap();
4673 switch.text_name = text_name.to_string();
4674 switch.text_origin_position = t.origin_position;
4675 t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
4676 t.x_grid = [0, 0];
4677 t.y_grid = [0, 0];
4678 } else if !text_name.is_empty() {
4679 self.problem_report_custom(
4680 RustConstructorError::TextNotFound {
4681 text_name: text_name.to_string(),
4682 },
4683 SeverityLevel::SevereWarning,
4684 self.problem_list.clone(),
4685 );
4686 };
4687 if self.check_resource_exists(fill_resource_name, fill_resource_type) {
4688 match fill_resource_type {
4689 "Image" | "CustomRect" => {
4690 switch.fill_resource_name = fill_resource_name.to_string();
4691 switch.fill_resource_type = fill_resource_type.to_string();
4692 }
4693 &_ => {
4694 self.problem_report_custom(
4695 RustConstructorError::SwitchFillResourceMismatch {
4696 switch_name: switch.name.clone(),
4697 fill_resource_name: fill_resource_name.to_string(),
4698 fill_resource_type: fill_resource_type.to_string(),
4699 },
4700 SeverityLevel::SevereWarning,
4701 self.problem_list.clone(),
4702 );
4703 return Err(RustConstructorError::SwitchFillResourceMismatch {
4704 switch_name: switch.name.clone(),
4705 fill_resource_name: fill_resource_name.to_string(),
4706 fill_resource_type: fill_resource_type.to_string(),
4707 });
4708 }
4709 };
4710 } else {
4711 self.problem_report_custom(
4712 RustConstructorError::ResourceNotFound {
4713 resource_name: fill_resource_name.to_string(),
4714 resource_type: fill_resource_type.to_string(),
4715 },
4716 SeverityLevel::SevereWarning,
4717 self.problem_list.clone(),
4718 );
4719 return Err(RustConstructorError::ResourceNotFound {
4720 resource_name: fill_resource_name.to_string(),
4721 resource_type: fill_resource_type.to_string(),
4722 });
4723 };
4724 switch.hint_text_name = String::new();
4725 if switch
4726 .appearance
4727 .iter()
4728 .filter(|x| !x.hint_text.is_empty())
4729 .count()
4730 > 0
4731 {
4732 switch.hint_text_name = format!("{}Hint", switch.name);
4733 self.add_text(
4734 Text::default()
4735 .name(&format!("{}Hint", switch.name))
4736 .content("")
4737 .origin_position(0_f32, 0_f32)
4738 .font_size(25_f32)
4739 .wrap_width(300_f32)
4740 .background_rounding(10_f32)
4741 .color(255, 255, 255, 0)
4742 .background_color(0, 0, 0, 255)
4743 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4744 .selectable(false),
4745 );
4746 self.add_split_time(
4747 SplitTime::default().name(&format!("{}StartHoverTime", switch.name)),
4748 );
4749 self.add_split_time(
4750 SplitTime::default().name(&format!("{}HintFadeAnimation", switch.name)),
4751 );
4752 };
4753 switch.state = 0;
4754 switch.animation_count = count as u32;
4755 self.rust_constructor_resource.push(Box::new(switch));
4756 Ok(())
4757 }
4758
4759 pub fn switch(
4761 &mut self,
4762 name: &str,
4763 ui: &mut Ui,
4764 ctx: &Context,
4765 enable: bool,
4766 safe_mode: Option<bool>,
4767 ) -> Result<(), RustConstructorError> {
4768 let mut appearance_count = 0;
4769 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4770 && !self.check_resource_exists(name, "Switch")
4771 {
4772 self.problem_report_custom(
4773 RustConstructorError::SwitchNotFound {
4774 switch_name: name.to_string(),
4775 },
4776 SeverityLevel::SevereWarning,
4777 self.problem_list.clone(),
4778 );
4779 return Err(RustConstructorError::SwitchNotFound {
4780 switch_name: name.to_string(),
4781 });
4782 };
4783 let mut s = self
4784 .get_resource::<Switch>(name, "Switch")
4785 .unwrap()
4786 .unwrap()
4787 .clone();
4788 s.switched = false;
4789 if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4790 if !self.check_resource_exists(&s.fill_resource_name.clone(), &s.fill_resource_type) {
4791 self.problem_report_custom(
4792 RustConstructorError::ResourceNotFound {
4793 resource_name: s.fill_resource_name.clone(),
4794 resource_type: s.fill_resource_type.clone(),
4795 },
4796 SeverityLevel::SevereWarning,
4797 self.problem_list.clone(),
4798 );
4799 return Err(RustConstructorError::ResourceNotFound {
4800 resource_name: s.fill_resource_name,
4801 resource_type: s.fill_resource_type,
4802 });
4803 };
4804 if !s.hint_text_name.is_empty() {
4805 if !self.check_resource_exists(&format!("{}StartHoverTime", s.name), "SplitTime") {
4806 self.problem_report_custom(
4807 RustConstructorError::SplitTimeNotFound {
4808 split_time_name: format!("{}StartHoverTime", s.name),
4809 },
4810 SeverityLevel::MildWarning,
4811 self.problem_list.clone(),
4812 );
4813 self.add_split_time(
4814 SplitTime::default().name(&format!("{}StartHoverTime", s.name)),
4815 );
4816 };
4817 if !self.check_resource_exists(&format!("{}HintFadeAnimation", s.name), "SplitTime")
4818 {
4819 self.problem_report_custom(
4820 RustConstructorError::SplitTimeNotFound {
4821 split_time_name: format!("{}HintFadeAnimation", s.name),
4822 },
4823 SeverityLevel::MildWarning,
4824 self.problem_list.clone(),
4825 );
4826 self.add_split_time(
4827 SplitTime::default().name(&format!("{}HintFadeAnimation", s.name)),
4828 );
4829 };
4830 if !self.check_resource_exists(&s.hint_text_name, "Text") {
4831 self.problem_report_custom(
4832 RustConstructorError::TextNotFound {
4833 text_name: s.hint_text_name.clone(),
4834 },
4835 SeverityLevel::MildWarning,
4836 self.problem_list.clone(),
4837 );
4838 self.add_text(
4839 Text::default()
4840 .name(&s.hint_text_name)
4841 .content("")
4842 .origin_position(0_f32, 0_f32)
4843 .font_size(25_f32)
4844 .wrap_width(300_f32)
4845 .background_rounding(10_f32)
4846 .color(255, 255, 255, 0)
4847 .background_color(0, 0, 0, 255)
4848 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4849 .selectable(false),
4850 );
4851 };
4852 };
4853 };
4854 let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
4855 "Image" => Box::new(
4856 self.get_resource::<Image>(&s.fill_resource_name.clone(), &s.fill_resource_type)
4857 .unwrap()
4858 .unwrap()
4859 .clone(),
4860 ),
4861 "CustomRect" => Box::new(
4862 self.get_resource::<CustomRect>(
4863 &s.fill_resource_name.clone(),
4864 &s.fill_resource_type,
4865 )
4866 .unwrap()
4867 .unwrap()
4868 .clone(),
4869 ),
4870 &_ => {
4871 self.problem_report_custom(
4872 RustConstructorError::SwitchFillResourceMismatch {
4873 switch_name: name.to_string(),
4874 fill_resource_name: s.fill_resource_name.clone(),
4875 fill_resource_type: s.fill_resource_type.clone(),
4876 },
4877 SeverityLevel::SevereWarning,
4878 self.problem_list.clone(),
4879 );
4880 return Err(RustConstructorError::SwitchFillResourceMismatch {
4881 switch_name: name.to_string(),
4882 fill_resource_name: s.fill_resource_name,
4883 fill_resource_type: s.fill_resource_type,
4884 });
4885 }
4886 };
4887 s.reg_render_resource(&mut self.render_resource_list);
4888 let rect = Rect::from_min_size(
4889 Pos2::new(fr.position()[0], fr.position()[1]),
4890 Vec2::new(fr.size()[0], fr.size()[1]),
4891 );
4892 let mut hovered = false;
4893 if enable {
4894 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4895 if rect.contains(mouse_pos) {
4897 if !s.hint_text_name.is_empty() {
4898 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4899 && !self.check_resource_exists(&s.hint_text_name, "Text")
4900 {
4901 self.problem_report_custom(
4902 RustConstructorError::TextNotFound {
4903 text_name: s.hint_text_name.clone(),
4904 },
4905 SeverityLevel::SevereWarning,
4906 self.problem_list.clone(),
4907 );
4908 return Err(RustConstructorError::TextNotFound {
4909 text_name: s.hint_text_name.clone(),
4910 });
4911 };
4912 let mut t = self
4913 .get_resource::<Text>(&s.hint_text_name, "Text")
4914 .unwrap()
4915 .unwrap()
4916 .clone();
4917 if !s.last_time_hovered {
4918 self.reset_split_time(&format!("{}StartHoverTime", s.name), safe_mode)
4919 .unwrap();
4920 } else if self.timer.total_time
4921 - self
4922 .split_time(&format!("{}StartHoverTime", s.name), safe_mode)
4923 .unwrap()[1]
4924 >= 2_f32
4925 || t.color[3] != 0
4926 {
4927 t.color[3] = 255;
4928 t.origin_position = [mouse_pos.x, mouse_pos.y];
4929 };
4930 t.center_display.0 =
4931 if mouse_pos.x + t.size[0] <= ctx.available_rect().width() {
4932 HorizontalAlign::Left
4933 } else {
4934 HorizontalAlign::Right
4935 };
4936 t.center_display.1 =
4937 if mouse_pos.y + t.size[1] <= ctx.available_rect().height() {
4938 VerticalAlign::Top
4939 } else {
4940 VerticalAlign::Bottom
4941 };
4942 self.replace_resource(&s.hint_text_name, "Text", t.clone())
4943 .unwrap();
4944 };
4945 hovered = true;
4946 let mut clicked = vec![];
4947 for u in 0..s.click_method.len() as u32 {
4948 clicked.push(ui.input(|i| {
4949 i.pointer
4950 .button_down(s.click_method[u as usize].click_method)
4951 }));
4952 if clicked[u as usize] {
4953 s.last_time_clicked_index = u as usize;
4954 break;
4955 };
4956 }
4957 if clicked.iter().any(|x| *x) {
4958 s.last_time_clicked = true;
4959 if s.enable_hover_click_fill_resource[1] {
4960 if s.enable_hover_click_fill_resource[0] {
4961 appearance_count = 2;
4962 } else {
4963 appearance_count = 1;
4964 };
4965 } else if !s.enable_hover_click_fill_resource[0] {
4966 appearance_count = 0;
4967 };
4968 } else {
4969 if s.last_time_clicked {
4970 s.switched = true;
4971 if s.click_method[s.last_time_clicked_index].action {
4972 if s.state
4973 < (s.appearance.len() / s.animation_count as usize - 1) as u32
4974 {
4975 s.state += 1;
4976 } else {
4977 s.state = 0;
4978 };
4979 };
4980 s.last_time_clicked = false;
4981 };
4982 if s.enable_hover_click_fill_resource[0] {
4983 appearance_count = 1;
4984 } else {
4985 appearance_count = 0;
4986 };
4987 };
4988 } else {
4989 s.last_time_clicked = false;
4990 appearance_count = 0;
4991 };
4992 } else {
4993 s.last_time_clicked = false;
4994 appearance_count = 0;
4995 };
4996 } else {
4997 s.last_time_clicked = false;
4998 appearance_count = 0;
4999 };
5000 if !hovered && !s.hint_text_name.is_empty() {
5001 if s.last_time_hovered {
5002 self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5003 .unwrap();
5004 };
5005 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5006 && !self.check_resource_exists(&s.hint_text_name, "Text")
5007 {
5008 self.problem_report_custom(
5009 RustConstructorError::TextNotFound {
5010 text_name: s.hint_text_name.clone(),
5011 },
5012 SeverityLevel::SevereWarning,
5013 self.problem_list.clone(),
5014 );
5015 return Err(RustConstructorError::TextNotFound {
5016 text_name: s.hint_text_name.clone(),
5017 });
5018 };
5019 let mut t = self
5020 .get_resource::<Text>(&s.hint_text_name, "Text")
5021 .unwrap()
5022 .unwrap()
5023 .clone();
5024 if self.timer.total_time
5025 - self
5026 .split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5027 .unwrap()[1]
5028 >= self.tick_interval
5029 {
5030 self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5031 .unwrap();
5032 t.color[3] = t.color[3].saturating_sub(10);
5033 };
5034 self.replace_resource(&s.hint_text_name, "Text", t.clone())
5035 .unwrap();
5036 };
5037 let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
5038 "Image" => {
5039 let mut im = Box::new(
5040 fr.as_any()
5041 .downcast_ref::<Image>()
5042 .unwrap()
5043 .clone()
5044 .from_config(
5045 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5046 .image_config
5047 .clone(),
5048 ),
5049 );
5050 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5051 && !self.check_resource_exists(
5052 &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5053 .texture
5054 .clone(),
5055 "ImageTexture",
5056 )
5057 {
5058 self.problem_report_custom(
5059 RustConstructorError::ImageTextureNotFound {
5060 image_texture_name: s.appearance
5061 [(s.state * s.animation_count + appearance_count) as usize]
5062 .texture
5063 .clone(),
5064 },
5065 SeverityLevel::SevereWarning,
5066 self.problem_list.clone(),
5067 );
5068 return Err(RustConstructorError::ImageTextureNotFound {
5069 image_texture_name: s.appearance
5070 [(s.state * s.animation_count + appearance_count) as usize]
5071 .texture
5072 .clone(),
5073 });
5074 };
5075 im.cite_texture = s.appearance
5076 [(s.state * s.animation_count + appearance_count) as usize]
5077 .texture
5078 .clone();
5079 im
5080 }
5081 "CustomRect" => Box::new(
5082 fr.as_any()
5083 .downcast_ref::<CustomRect>()
5084 .unwrap()
5085 .clone()
5086 .name(&s.fill_resource_name)
5087 .from_config(
5088 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5089 .custom_rect_config
5090 .clone(),
5091 ),
5092 ),
5093 &_ => {
5094 self.problem_report_custom(
5095 RustConstructorError::SwitchFillResourceMismatch {
5096 switch_name: name.to_string(),
5097 fill_resource_name: s.fill_resource_name.clone(),
5098 fill_resource_type: s.fill_resource_type.clone(),
5099 },
5100 SeverityLevel::SevereWarning,
5101 self.problem_list.clone(),
5102 );
5103 return Err(RustConstructorError::SwitchFillResourceMismatch {
5104 switch_name: name.to_string(),
5105 fill_resource_name: s.fill_resource_name,
5106 fill_resource_type: s.fill_resource_type,
5107 });
5108 }
5109 };
5110 if !s.hint_text_name.is_empty() {
5111 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5112 && !self.check_resource_exists(&s.hint_text_name, "Text")
5113 {
5114 self.problem_report_custom(
5115 RustConstructorError::TextNotFound {
5116 text_name: s.hint_text_name.clone(),
5117 },
5118 SeverityLevel::SevereWarning,
5119 self.problem_list.clone(),
5120 );
5121 return Err(RustConstructorError::TextNotFound {
5122 text_name: s.hint_text_name,
5123 });
5124 };
5125 let mut t = self
5126 .get_resource::<Text>(&s.hint_text_name, "Text")
5127 .unwrap()
5128 .unwrap()
5129 .clone();
5130 t.background_color[3] = t.color[3];
5131 t.content = s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5132 .hint_text
5133 .clone();
5134 self.replace_resource(&s.hint_text_name, "Text", t.clone())
5135 .unwrap();
5136 };
5137 s.last_time_hovered = hovered;
5138 self.replace_resource(name, "Switch", s.clone()).unwrap();
5139 match s.fill_resource_type.as_str() {
5140 "Image" => {
5141 let im = fr.as_any().downcast_ref::<Image>().unwrap().clone();
5142 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, im)
5143 .unwrap();
5144 self.image(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5145 .unwrap();
5146 }
5147 "CustomRect" => {
5148 let cr = fr.as_any().downcast_ref::<CustomRect>().unwrap().clone();
5149 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, cr)
5150 .unwrap();
5151 self.custom_rect(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5152 .unwrap();
5153 }
5154 &_ => {}
5155 };
5156 s.text_origin_position = s.appearance
5157 [(s.state * s.animation_count + appearance_count) as usize]
5158 .text_config
5159 .origin_position;
5160 if !s.text_name.is_empty() {
5161 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5162 && !self.check_resource_exists(&s.text_name, "Text")
5163 {
5164 self.problem_report_custom(
5165 RustConstructorError::TextNotFound {
5166 text_name: s.text_name.clone(),
5167 },
5168 SeverityLevel::SevereWarning,
5169 self.problem_list.clone(),
5170 );
5171 return Err(RustConstructorError::TextNotFound {
5172 text_name: s.text_name,
5173 });
5174 };
5175 let mut t = self
5176 .get_resource::<Text>(&s.text_name, "Text")
5177 .unwrap()
5178 .unwrap()
5179 .clone();
5180 t.origin_position = [
5181 fr.position()[0] + s.text_origin_position[0],
5182 fr.position()[1] + s.text_origin_position[1],
5183 ];
5184 t = t.from_config(
5185 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5186 .text_config
5187 .clone(),
5188 );
5189 self.replace_resource(&s.text_name, "Text", t.clone())
5190 .unwrap();
5191 self.text(&s.text_name, ui, ctx, safe_mode).unwrap();
5192 };
5193 if !s.hint_text_name.is_empty() {
5194 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5195 && !self.check_resource_exists(&s.hint_text_name, "Text")
5196 {
5197 self.problem_report_custom(
5198 RustConstructorError::TextNotFound {
5199 text_name: s.hint_text_name.clone(),
5200 },
5201 SeverityLevel::SevereWarning,
5202 self.problem_list.clone(),
5203 );
5204 return Err(RustConstructorError::TextNotFound {
5205 text_name: s.hint_text_name,
5206 });
5207 };
5208 self.text(&s.hint_text_name, ui, ctx, safe_mode).unwrap();
5209 };
5210 Ok(())
5211 }
5212
5213 pub fn check_switch_data(
5215 &self,
5216 name: &str,
5217 safe_mode: Option<bool>,
5218 ) -> Result<SwitchData, RustConstructorError> {
5219 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5220 && !self.check_resource_exists(name, "Switch")
5221 {
5222 self.problem_report_custom(
5223 RustConstructorError::SwitchNotFound {
5224 switch_name: name.to_string(),
5225 },
5226 SeverityLevel::SevereWarning,
5227 self.problem_list.clone(),
5228 );
5229 return Err(RustConstructorError::SwitchNotFound {
5230 switch_name: name.to_string(),
5231 });
5232 };
5233 let s = self
5234 .get_resource::<Switch>(name, "Switch")
5235 .unwrap()
5236 .unwrap();
5237 Ok(SwitchData {
5238 switched: s.switched,
5239 last_time_clicked_index: s.last_time_clicked_index,
5240 state: s.state,
5241 })
5242 }
5243
5244 pub fn add_mouse_detector(&mut self, mouse_detector: MouseDetector) {
5246 self.rust_constructor_resource
5247 .push(Box::new(mouse_detector));
5248 }
5249
5250 pub fn mouse_detector(
5251 &mut self,
5252 name: &str,
5253 ui: &Ui,
5254 ctx: &Context,
5255 mouse_detector_level: MouseDetectorLevel,
5256 safe_mode: Option<bool>,
5257 ) -> Result<(), RustConstructorError> {
5258 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5259 && !self.check_resource_exists(name, "MouseDetector")
5260 {
5261 self.problem_report_custom(
5262 RustConstructorError::MouseDetectorNotFound {
5263 mouse_detector_name: name.to_string(),
5264 },
5265 SeverityLevel::SevereWarning,
5266 self.problem_list.clone(),
5267 );
5268 return Err(RustConstructorError::MouseDetectorNotFound {
5269 mouse_detector_name: name.to_string(),
5270 });
5271 };
5272 let md = self
5273 .get_resource_mut::<MouseDetector>(name, "MouseDetector")
5274 .unwrap();
5275 md.position[0] = match md.x_grid[1] {
5276 0 => md.origin_position[0],
5277 _ => {
5278 (ctx.available_rect().width() as f64 / md.x_grid[1] as f64 * md.x_grid[0] as f64)
5279 as f32
5280 + md.origin_position[0]
5281 }
5282 };
5283 md.position[1] = match md.y_grid[1] {
5284 0 => md.origin_position[1],
5285 _ => {
5286 (ctx.available_rect().height() as f64 / md.y_grid[1] as f64 * md.y_grid[0] as f64)
5287 as f32
5288 + md.origin_position[1]
5289 }
5290 };
5291 match md.center_display.0 {
5292 HorizontalAlign::Left => {}
5293 HorizontalAlign::Center => md.position[0] -= md.size[0] / 2.0,
5294 HorizontalAlign::Right => md.position[0] -= md.size[0],
5295 };
5296 match md.center_display.1 {
5297 VerticalAlign::Top => {}
5298 VerticalAlign::Center => md.position[1] -= md.size[1] / 2.0,
5299 VerticalAlign::Bottom => md.position[1] -= md.size[1],
5300 };
5301 md.position[0] += md.offset[0];
5302 md.position[1] += md.offset[1];
5303 let rect = Rect::from_min_max(
5304 Pos2::new(md.position[0], md.position[1]),
5305 Pos2::new(md.position[0] + md.size[0], md.position[1] + md.size[1]),
5306 );
5307 let response = ui.interact(rect, Id::new(name), Sense::click_and_drag());
5308 md.detect_result = match mouse_detector_level {
5309 MouseDetectorLevel::Lite => MouseDetectResult {
5310 clicked: response.clicked(),
5311 contains_pointer: response.contains_pointer(),
5312 secondary_clicked: None,
5313 middle_clicked: None,
5314 clicked_by_extra_button: None,
5315 long_touched: None,
5316 double_clicked: None,
5317 triple_clicked: None,
5318 double_clicked_by: None,
5319 triple_clicked_by: None,
5320 clicked_elsewhere: None,
5321 hovered: None,
5322 drag_started: None,
5323 drag_started_by: None,
5324 dragged: None,
5325 dragged_by: None,
5326 drag_stopped: None,
5327 deag_stopped_by: None,
5328 drag_delta: None,
5329 total_drag_delta: None,
5330 drag_motion: None,
5331 interact_pointer_pos: None,
5332 hover_pos: None,
5333 is_pointer_button_down_on: None,
5334 },
5335 MouseDetectorLevel::Default => {
5336 let interact_hover_pos = response.interact_pointer_pos();
5337 let hover_pos = response.hover_pos();
5338 MouseDetectResult {
5339 clicked: response.clicked(),
5340 contains_pointer: response.contains_pointer(),
5341 secondary_clicked: Some(response.secondary_clicked()),
5342 middle_clicked: Some(response.middle_clicked()),
5343 clicked_by_extra_button: None,
5344 long_touched: None,
5345 double_clicked: Some(response.double_clicked()),
5346 triple_clicked: Some(response.triple_clicked()),
5347 double_clicked_by: None,
5348 triple_clicked_by: None,
5349 clicked_elsewhere: Some(response.clicked_elsewhere()),
5350 hovered: Some(response.hovered()),
5351 drag_started: Some(response.drag_started()),
5352 drag_started_by: None,
5353 dragged: Some(response.dragged()),
5354 dragged_by: None,
5355 drag_stopped: Some(response.drag_stopped()),
5356 deag_stopped_by: None,
5357 drag_delta: None,
5358 total_drag_delta: None,
5359 drag_motion: None,
5360 interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5361 Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5362 } else {
5363 Some(None)
5364 },
5365 hover_pos: if let Some(hover_pos) = hover_pos {
5366 Some(Some([hover_pos.x, hover_pos.y]))
5367 } else {
5368 Some(None)
5369 },
5370 is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5371 }
5372 }
5373 MouseDetectorLevel::Pro => {
5374 let interact_hover_pos = response.interact_pointer_pos();
5375 let hover_pos = response.hover_pos();
5376 let total_drag_delta = response.total_drag_delta();
5377 MouseDetectResult {
5378 clicked: response.clicked(),
5379 contains_pointer: response.contains_pointer(),
5380 secondary_clicked: Some(response.secondary_clicked()),
5381 middle_clicked: Some(response.middle_clicked()),
5382 clicked_by_extra_button: Some([
5383 response.clicked_by(PointerButton::Extra1),
5384 response.clicked_by(PointerButton::Extra2),
5385 ]),
5386 long_touched: Some(response.long_touched()),
5387 double_clicked: Some(response.double_clicked()),
5388 triple_clicked: Some(response.triple_clicked()),
5389 double_clicked_by: Some([
5390 response.double_clicked_by(PointerButton::Primary),
5391 response.double_clicked_by(PointerButton::Secondary),
5392 response.double_clicked_by(PointerButton::Middle),
5393 response.double_clicked_by(PointerButton::Extra1),
5394 response.double_clicked_by(PointerButton::Extra2),
5395 ]),
5396 triple_clicked_by: Some([
5397 response.triple_clicked_by(PointerButton::Primary),
5398 response.triple_clicked_by(PointerButton::Secondary),
5399 response.triple_clicked_by(PointerButton::Middle),
5400 response.triple_clicked_by(PointerButton::Extra1),
5401 response.triple_clicked_by(PointerButton::Extra2),
5402 ]),
5403 clicked_elsewhere: Some(response.clicked_elsewhere()),
5404 hovered: Some(response.hovered()),
5405 drag_started: Some(response.drag_started()),
5406 drag_started_by: Some([
5407 response.drag_started_by(PointerButton::Primary),
5408 response.drag_started_by(PointerButton::Secondary),
5409 response.drag_started_by(PointerButton::Middle),
5410 response.drag_started_by(PointerButton::Extra1),
5411 response.drag_started_by(PointerButton::Extra2),
5412 ]),
5413 dragged: Some(response.dragged()),
5414 dragged_by: Some([
5415 response.dragged_by(PointerButton::Primary),
5416 response.dragged_by(PointerButton::Secondary),
5417 response.dragged_by(PointerButton::Middle),
5418 response.dragged_by(PointerButton::Extra1),
5419 response.dragged_by(PointerButton::Extra2),
5420 ]),
5421 drag_stopped: Some(response.drag_stopped()),
5422 deag_stopped_by: Some([
5423 response.drag_stopped_by(PointerButton::Primary),
5424 response.drag_stopped_by(PointerButton::Secondary),
5425 response.drag_stopped_by(PointerButton::Middle),
5426 response.drag_stopped_by(PointerButton::Extra1),
5427 response.drag_stopped_by(PointerButton::Extra2),
5428 ]),
5429 drag_delta: Some([response.drag_delta().x, response.drag_delta().y]),
5430 total_drag_delta: if let Some(total_drag_delta) = total_drag_delta {
5431 Some(Some([total_drag_delta.x, total_drag_delta.y]))
5432 } else {
5433 Some(None)
5434 },
5435 drag_motion: Some([response.drag_motion().x, response.drag_motion().y]),
5436 interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5437 Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5438 } else {
5439 Some(None)
5440 },
5441 hover_pos: if let Some(hover_pos) = hover_pos {
5442 Some(Some([hover_pos.x, hover_pos.y]))
5443 } else {
5444 Some(None)
5445 },
5446 is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5447 }
5448 }
5449 };
5450 Ok(())
5451 }
5452
5453 pub fn check_mouse_detect_result(
5454 &self,
5455 name: &str,
5456 safe_mode: Option<bool>,
5457 ) -> Result<MouseDetectResult, RustConstructorError> {
5458 if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5459 && !self.check_resource_exists(name, "MouseDetector")
5460 {
5461 self.problem_report_custom(
5462 RustConstructorError::MouseDetectorNotFound {
5463 mouse_detector_name: name.to_string(),
5464 },
5465 SeverityLevel::SevereWarning,
5466 self.problem_list.clone(),
5467 );
5468 return Err(RustConstructorError::MouseDetectorNotFound {
5469 mouse_detector_name: name.to_string(),
5470 });
5471 };
5472 let md = self
5473 .get_resource::<MouseDetector>(name, "MouseDetector")
5474 .unwrap()
5475 .unwrap();
5476 Ok(md.detect_result.clone())
5477 }
5478}