1use eframe::{emath::Rect, epaint::Stroke, epaint::textures::TextureOptions};
4use egui::{
5 Color32, ColorImage, Context, FontData, FontDefinitions, FontFamily, FontId, Galley, Id,
6 ImageSource, Key, OpenUrl, PointerButton, Pos2, Sense, StrokeKind, TextureHandle, Ui, Vec2,
7 text::CCursor,
8};
9use std::{
10 any::Any,
11 error::Error,
12 fmt::{Debug, Display, Formatter},
13 fs::{File, read},
14 io::Read,
15 sync::Arc,
16 time::Instant,
17 vec::Vec,
18};
19
20pub trait RustConstructorResource: Debug {
22 fn name(&self) -> &str;
24
25 fn expose_type(&self) -> &str;
27
28 fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
30 render_list.push(RenderResource {
31 discern_type: self.expose_type().to_string(),
32 name: self.name().to_string(),
33 });
34 }
35
36 fn as_any(&self) -> &dyn Any;
38
39 fn as_any_mut(&mut self) -> &mut dyn Any;
41}
42
43pub trait FrontResource: RustConstructorResource {
45 fn size(&self) -> [f32; 2];
46
47 fn position(&self) -> [f32; 2];
48
49 fn modify_size(&mut self, width: f32, height: f32);
50
51 fn modify_position(&mut self, x: f32, y: f32);
52
53 fn modify_add_position(&mut self, add_x: f32, add_y: f32);
54}
55
56#[derive(Debug, Clone, PartialEq, PartialOrd)]
58pub enum Value {
59 Bool(bool),
60 Int(i32),
61 UInt(u32),
62 Float(f32),
63 Vec(Vec<Value>),
64 String(String),
65}
66
67impl From<bool> for Value {
68 fn from(b: bool) -> Self {
69 Value::Bool(b)
70 }
71}
72
73impl From<i32> for Value {
74 fn from(i: i32) -> Self {
75 Value::Int(i)
76 }
77}
78
79impl From<u32> for Value {
80 fn from(u: u32) -> Self {
81 Value::UInt(u)
82 }
83}
84
85impl From<f32> for Value {
86 fn from(f: f32) -> Self {
87 Value::Float(f)
88 }
89}
90
91impl<T: Into<Value>> From<Vec<T>> for Value {
92 fn from(v: Vec<T>) -> Self {
93 Value::Vec(v.into_iter().map(|x| x.into()).collect())
94 }
95}
96
97impl From<String> for Value {
98 fn from(s: String) -> Self {
99 Value::String(s)
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, PartialOrd)]
105pub struct ReportState {
106 pub current_page: String,
108 pub current_total_runtime: f32,
110 pub current_page_runtime: f32,
112}
113
114#[derive(Debug, Clone, PartialEq, PartialOrd)]
116pub struct Problem {
117 pub severity_level: SeverityLevel,
119 pub problem: String,
121 pub annotation: String,
123 pub report_state: ReportState,
125 pub problem_type: RustConstructorError,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
131pub enum SeverityLevel {
132 MildWarning,
134 SevereWarning,
136 Error,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
142pub struct PageData {
143 pub discern_type: String,
144 pub name: String,
145 pub forced_update: bool,
147 pub change_page_updated: bool,
149 pub enter_page_updated: bool,
151}
152
153impl RustConstructorResource for PageData {
154 fn name(&self) -> &str {
155 &self.name
156 }
157
158 fn expose_type(&self) -> &str {
159 &self.discern_type
160 }
161
162 fn as_any(&self) -> &dyn Any {
163 self
164 }
165
166 fn as_any_mut(&mut self) -> &mut dyn Any {
167 self
168 }
169}
170
171impl Default for PageData {
172 fn default() -> Self {
173 PageData {
174 discern_type: String::from("PageData"),
175 name: String::from("PageData"),
176 forced_update: true,
177 change_page_updated: false,
178 enter_page_updated: false,
179 }
180 }
181}
182
183impl PageData {
184 #[inline]
185 pub fn name(mut self, name: &str) -> Self {
186 self.name = name.to_string();
187 self
188 }
189
190 #[inline]
191 pub fn forced_update(mut self, forced_update: bool) -> Self {
192 self.forced_update = forced_update;
193 self
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
199pub struct Timer {
200 pub start_time: f32,
202 pub total_time: f32,
204 pub timer: Instant,
206 pub now_time: f32,
208}
209
210impl Default for Timer {
211 fn default() -> Self {
212 Timer {
213 start_time: 0_f32,
214 total_time: 0_f32,
215 timer: Instant::now(),
216 now_time: 0_f32,
217 }
218 }
219}
220
221#[derive(Clone, PartialEq, Eq, Hash)]
223pub struct DebugTextureHandle(TextureHandle);
224
225impl Debug for DebugTextureHandle {
226 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
227 f.debug_struct("DebugTextureHandle").finish()
229 }
230}
231
232impl DebugTextureHandle {
233 pub fn new(texture_handle: TextureHandle) -> Self {
234 Self(texture_handle)
235 }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub struct ImageTexture {
241 pub discern_type: String,
242 pub name: String,
243 pub texture: Option<DebugTextureHandle>,
245 pub cite_path: String,
247}
248
249impl RustConstructorResource for ImageTexture {
250 fn name(&self) -> &str {
251 &self.name
252 }
253
254 fn expose_type(&self) -> &str {
255 &self.discern_type
256 }
257
258 fn as_any(&self) -> &dyn Any {
259 self
260 }
261
262 fn as_any_mut(&mut self) -> &mut dyn Any {
263 self
264 }
265}
266
267impl Default for ImageTexture {
268 fn default() -> Self {
269 ImageTexture {
270 discern_type: String::from("ImageTexture"),
271 name: String::from("ImageTexture"),
272 texture: None,
273 cite_path: String::from(""),
274 }
275 }
276}
277
278impl ImageTexture {
279 #[inline]
280 pub fn name(mut self, name: &str) -> Self {
281 self.name = name.to_string();
282 self
283 }
284}
285
286#[derive(Debug, Clone, PartialEq, PartialOrd)]
288pub struct CustomRectConfig {
289 pub size: [f32; 2],
291 pub rounding: f32,
293 pub x_grid: [u32; 2],
295 pub y_grid: [u32; 2],
297 pub center_display: (HorizontalAlign, VerticalAlign),
299 pub color: [u8; 4],
301 pub border_width: f32,
303 pub border_color: [u8; 4],
305 pub origin_position: [f32; 2],
307}
308
309impl Default for CustomRectConfig {
310 fn default() -> Self {
311 Self {
312 size: [100_f32, 100_f32],
313 rounding: 2_f32,
314 x_grid: [0, 0],
315 y_grid: [0, 0],
316 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
317 color: [255, 255, 255, 255],
318 border_width: 2_f32,
319 border_color: [0, 0, 0, 255],
320 origin_position: [0_f32, 0_f32],
321 }
322 }
323}
324
325impl CustomRectConfig {
326 pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
327 Self {
328 size: custom_rect.size,
329 rounding: custom_rect.rounding,
330 x_grid: custom_rect.x_grid,
331 y_grid: custom_rect.y_grid,
332 center_display: custom_rect.center_display,
333 color: custom_rect.color,
334 border_width: custom_rect.border_width,
335 border_color: custom_rect.border_color,
336 origin_position: custom_rect.origin_position,
337 }
338 }
339
340 #[inline]
341 pub fn size(mut self, width: f32, height: f32) -> Self {
342 self.size = [width, height];
343 self
344 }
345
346 #[inline]
347 pub fn rounding(mut self, rounding: f32) -> Self {
348 self.rounding = rounding;
349 self
350 }
351
352 #[inline]
353 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
354 self.x_grid = [fetch, total];
355 self
356 }
357
358 #[inline]
359 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
360 self.y_grid = [fetch, total];
361 self
362 }
363
364 #[inline]
365 pub fn center_display(
366 mut self,
367 horizontal_align: HorizontalAlign,
368 vertical_align: VerticalAlign,
369 ) -> Self {
370 self.center_display = (horizontal_align, vertical_align);
371 self
372 }
373
374 #[inline]
375 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
376 self.color = [r, g, b, a];
377 self
378 }
379
380 #[inline]
381 pub fn border_width(mut self, border_width: f32) -> Self {
382 self.border_width = border_width;
383 self
384 }
385
386 #[inline]
387 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
388 self.border_color = [r, g, b, a];
389 self
390 }
391
392 #[inline]
393 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
394 self.origin_position = [x, y];
395 self
396 }
397}
398
399#[derive(Debug, Clone, PartialEq, PartialOrd)]
401pub struct CustomRect {
402 pub discern_type: String,
403 pub name: String,
404 pub position: [f32; 2],
406 pub size: [f32; 2],
408 pub rounding: f32,
410 pub x_grid: [u32; 2],
412 pub y_grid: [u32; 2],
414 pub center_display: (HorizontalAlign, VerticalAlign),
416 pub color: [u8; 4],
418 pub border_width: f32,
420 pub border_color: [u8; 4],
422 pub origin_position: [f32; 2],
424}
425
426impl RustConstructorResource for CustomRect {
427 fn name(&self) -> &str {
428 &self.name
429 }
430
431 fn expose_type(&self) -> &str {
432 &self.discern_type
433 }
434
435 fn as_any(&self) -> &dyn Any {
436 self
437 }
438
439 fn as_any_mut(&mut self) -> &mut dyn Any {
440 self
441 }
442}
443
444impl FrontResource for CustomRect {
445 fn position(&self) -> [f32; 2] {
446 self.position
447 }
448
449 fn size(&self) -> [f32; 2] {
450 self.size
451 }
452
453 fn modify_position(&mut self, x: f32, y: f32) {
454 self.origin_position = [x, y];
455 }
456
457 fn modify_size(&mut self, width: f32, height: f32) {
458 self.size = [width, height];
459 }
460
461 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
462 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
463 }
464}
465
466impl Default for CustomRect {
467 fn default() -> Self {
468 Self {
469 discern_type: String::from("CustomRect"),
470 name: String::from("CustomRect"),
471 position: [0_f32, 0_f32],
472 size: [100_f32, 100_f32],
473 rounding: 2_f32,
474 x_grid: [0, 0],
475 y_grid: [0, 0],
476 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
477 color: [255, 255, 255, 255],
478 border_width: 2_f32,
479 border_color: [0, 0, 0, 255],
480 origin_position: [0_f32, 0_f32],
481 }
482 }
483}
484
485impl CustomRect {
486 pub fn from_config(mut self, config: CustomRectConfig) -> Self {
487 self.size = config.size;
488 self.rounding = config.rounding;
489 self.x_grid = config.x_grid;
490 self.y_grid = config.y_grid;
491 self.center_display = config.center_display;
492 self.color = config.color;
493 self.border_width = config.border_width;
494 self.border_color = config.border_color;
495 self.origin_position = config.origin_position;
496 self
497 }
498
499 #[inline]
500 pub fn name(mut self, name: &str) -> Self {
501 self.name = name.to_string();
502 self
503 }
504
505 #[inline]
506 pub fn size(mut self, width: f32, height: f32) -> Self {
507 self.size = [width, height];
508 self
509 }
510
511 #[inline]
512 pub fn rounding(mut self, rounding: f32) -> Self {
513 self.rounding = rounding;
514 self
515 }
516
517 #[inline]
518 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
519 self.x_grid = [fetch, total];
520 self
521 }
522
523 #[inline]
524 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
525 self.y_grid = [fetch, total];
526 self
527 }
528
529 #[inline]
530 pub fn center_display(
531 mut self,
532 horizontal_align: HorizontalAlign,
533 vertical_align: VerticalAlign,
534 ) -> Self {
535 self.center_display = (horizontal_align, vertical_align);
536 self
537 }
538
539 #[inline]
540 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
541 self.color = [r, g, b, a];
542 self
543 }
544
545 #[inline]
546 pub fn border_width(mut self, border_width: f32) -> Self {
547 self.border_width = border_width;
548 self
549 }
550
551 #[inline]
552 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
553 self.border_color = [r, g, b, a];
554 self
555 }
556
557 #[inline]
558 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
559 self.origin_position = [x, y];
560 self
561 }
562}
563
564#[derive(Debug, Clone, PartialEq, PartialOrd)]
566pub struct ImageConfig {
567 pub size: [f32; 2],
569 pub x_grid: [u32; 2],
571 pub y_grid: [u32; 2],
573 pub center_display: (HorizontalAlign, VerticalAlign),
575 pub alpha: u8,
577 pub overlay_color: [u8; 4],
579 pub background_color: [u8; 4],
581 pub rotate_angle: f32,
583 pub rotate_center: [f32; 2],
585 pub origin_position: [f32; 2],
587 pub cite_texture: String,
589}
590
591impl Default for ImageConfig {
592 fn default() -> Self {
593 Self {
594 size: [100_f32, 100_f32],
595 x_grid: [0, 0],
596 y_grid: [0, 0],
597 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
598 alpha: 255,
599 overlay_color: [255, 255, 255, 255],
600 background_color: [0, 0, 0, 0],
601 rotate_angle: 0_f32,
602 rotate_center: [0_f32, 0_f32],
603 origin_position: [0_f32, 0_f32],
604 cite_texture: String::from("ImageTexture"),
605 }
606 }
607}
608
609impl ImageConfig {
610 pub fn from_image(image: Image) -> Self {
611 Self {
612 size: image.size,
613 x_grid: image.x_grid,
614 y_grid: image.y_grid,
615 center_display: image.center_display,
616 alpha: image.alpha,
617 overlay_color: image.overlay_color,
618 background_color: image.background_color,
619 rotate_angle: image.rotate_angle,
620 rotate_center: image.rotate_center,
621 cite_texture: image.cite_texture,
622 origin_position: image.origin_position,
623 }
624 }
625
626 #[inline]
627 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
628 self.origin_position = [x, y];
629 self
630 }
631
632 #[inline]
633 pub fn size(mut self, width: f32, height: f32) -> Self {
634 self.size = [width, height];
635 self
636 }
637
638 #[inline]
639 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
640 self.x_grid = [fetch, total];
641 self
642 }
643
644 #[inline]
645 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
646 self.y_grid = [fetch, total];
647 self
648 }
649
650 #[inline]
651 pub fn center_display(
652 mut self,
653 horizontal_align: HorizontalAlign,
654 vertical_align: VerticalAlign,
655 ) -> Self {
656 self.center_display = (horizontal_align, vertical_align);
657 self
658 }
659
660 #[inline]
661 pub fn alpha(mut self, alpha: u8) -> Self {
662 self.alpha = alpha;
663 self
664 }
665
666 #[inline]
667 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
668 self.overlay_color = [r, g, b, a];
669 self
670 }
671
672 #[inline]
673 pub fn background_color(mut self, background_color: [u8; 4]) -> Self {
674 self.background_color = background_color;
675 self
676 }
677
678 #[inline]
679 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
680 self.rotate_angle = rotate_angle;
681 self
682 }
683
684 #[inline]
685 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
686 self.rotate_center = [x, y];
687 self
688 }
689}
690
691#[derive(Debug, Clone, PartialEq)]
693pub struct Image {
694 pub discern_type: String,
695 pub name: String,
696 pub texture: Option<DebugTextureHandle>,
698 pub position: [f32; 2],
700 pub size: [f32; 2],
702 pub x_grid: [u32; 2],
704 pub y_grid: [u32; 2],
706 pub center_display: (HorizontalAlign, VerticalAlign),
708 pub alpha: u8,
710 pub overlay_color: [u8; 4],
712 pub background_color: [u8; 4],
714 pub rotate_angle: f32,
716 pub rotate_center: [f32; 2],
718 pub origin_position: [f32; 2],
720 pub cite_texture: String,
722 pub last_frame_cite_texture: String,
724}
725
726impl RustConstructorResource for Image {
727 fn name(&self) -> &str {
728 &self.name
729 }
730
731 fn expose_type(&self) -> &str {
732 &self.discern_type
733 }
734
735 fn as_any(&self) -> &dyn Any {
736 self
737 }
738
739 fn as_any_mut(&mut self) -> &mut dyn Any {
740 self
741 }
742}
743
744impl FrontResource for Image {
745 fn position(&self) -> [f32; 2] {
746 self.position
747 }
748
749 fn size(&self) -> [f32; 2] {
750 self.size
751 }
752
753 fn modify_position(&mut self, x: f32, y: f32) {
754 self.origin_position = [x, y];
755 }
756
757 fn modify_size(&mut self, width: f32, height: f32) {
758 self.size = [width, height];
759 }
760
761 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
762 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
763 }
764}
765
766impl Default for Image {
767 fn default() -> Self {
768 Self {
769 discern_type: String::from("Image"),
770 name: String::from("Image"),
771 texture: None,
772 position: [0_f32, 0_f32],
773 size: [100_f32, 100_f32],
774 x_grid: [0, 0],
775 y_grid: [0, 0],
776 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
777 alpha: 255,
778 overlay_color: [255, 255, 255, 255],
779 background_color: [0, 0, 0, 0],
780 rotate_angle: 0_f32,
781 rotate_center: [0_f32, 0_f32],
782 origin_position: [0_f32, 0_f32],
783 cite_texture: String::from("ImageTexture"),
784 last_frame_cite_texture: String::from("ImageTexture"),
785 }
786 }
787}
788
789impl Image {
790 pub fn from_config(mut self, config: ImageConfig) -> Self {
791 self.size = config.size;
792 self.x_grid = config.x_grid;
793 self.y_grid = config.y_grid;
794 self.center_display = config.center_display;
795 self.alpha = config.alpha;
796 self.overlay_color = config.overlay_color;
797 self.background_color = config.background_color;
798 self.rotate_angle = config.rotate_angle;
799 self.rotate_center = config.rotate_center;
800 self.origin_position = config.origin_position;
801 self.cite_texture = config.cite_texture;
802 self
803 }
804
805 #[inline]
806 pub fn name(mut self, name: &str) -> Self {
807 self.name = name.to_string();
808 self
809 }
810
811 #[inline]
812 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
813 self.origin_position = [x, y];
814 self
815 }
816
817 #[inline]
818 pub fn size(mut self, width: f32, height: f32) -> Self {
819 self.size = [width, height];
820 self
821 }
822
823 #[inline]
824 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
825 self.x_grid = [fetch, total];
826 self
827 }
828
829 #[inline]
830 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
831 self.y_grid = [fetch, total];
832 self
833 }
834
835 #[inline]
836 pub fn center_display(
837 mut self,
838 horizontal_align: HorizontalAlign,
839 vertical_align: VerticalAlign,
840 ) -> Self {
841 self.center_display = (horizontal_align, vertical_align);
842 self
843 }
844
845 #[inline]
846 pub fn alpha(mut self, alpha: u8) -> Self {
847 self.alpha = alpha;
848 self
849 }
850
851 #[inline]
852 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
853 self.overlay_color = [r, g, b, a];
854 self
855 }
856
857 #[inline]
858 pub fn background_color(mut self, background_color: [u8; 4]) -> Self {
859 self.background_color = background_color;
860 self
861 }
862
863 #[inline]
864 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
865 self.rotate_angle = rotate_angle;
866 self
867 }
868
869 #[inline]
870 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
871 self.rotate_center = [x, y];
872 self
873 }
874}
875
876#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
878pub enum HyperlinkSelectMethod {
879 All(String),
881 Segment(Vec<(usize, String)>),
883}
884
885#[derive(Debug, Clone, PartialEq, PartialOrd)]
887pub struct TextConfig {
888 pub content: String,
890 pub font_size: f32,
892 pub color: [u8; 4],
894 pub center_display: (HorizontalAlign, VerticalAlign),
896 pub wrap_width: f32,
898 pub background_color: [u8; 4],
900 pub background_rounding: f32,
902 pub x_grid: [u32; 2],
904 pub y_grid: [u32; 2],
906 pub origin_position: [f32; 2],
908 pub font: String,
910 pub selectable: bool,
912 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
914}
915
916impl Default for TextConfig {
917 fn default() -> Self {
918 Self {
919 content: String::from("Hello world"),
920 font_size: 16_f32,
921 color: [255, 255, 255, 255],
922 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
923 wrap_width: 200_f32,
924 background_color: [0, 0, 0, 0],
925 background_rounding: 2_f32,
926 x_grid: [0, 0],
927 y_grid: [0, 0],
928 origin_position: [0_f32, 0_f32],
929 font: String::new(),
930 selectable: true,
931 hyperlink_text: Vec::new(),
932 }
933 }
934}
935
936impl TextConfig {
937 pub fn from_text(text: Text) -> Self {
938 Self {
939 content: text.content,
940 font_size: text.font_size,
941 color: text.color,
942 center_display: text.center_display,
943 wrap_width: text.wrap_width,
944 background_color: text.background_color,
945 background_rounding: text.background_rounding,
946 x_grid: text.x_grid,
947 y_grid: text.y_grid,
948 origin_position: text.origin_position,
949 font: text.font,
950 selectable: text.selectable,
951 hyperlink_text: text.hyperlink_text,
952 }
953 }
954
955 #[inline]
956 pub fn content(mut self, content: &str) -> Self {
957 self.content = content.to_string();
958 self
959 }
960
961 #[inline]
962 pub fn font_size(mut self, font_size: f32) -> Self {
963 self.font_size = font_size;
964 self
965 }
966
967 #[inline]
968 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
969 self.color = [r, g, b, a];
970 self
971 }
972
973 #[inline]
974 pub fn center_display(
975 mut self,
976 horizontal_align: HorizontalAlign,
977 vertical_align: VerticalAlign,
978 ) -> Self {
979 self.center_display = (horizontal_align, vertical_align);
980 self
981 }
982
983 #[inline]
984 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
985 self.wrap_width = wrap_width;
986 self
987 }
988
989 #[inline]
990 pub fn background_color(mut self, background_color: [u8; 4]) -> Self {
991 self.background_color = background_color;
992 self
993 }
994
995 #[inline]
996 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
997 self.background_rounding = background_rounding;
998 self
999 }
1000
1001 #[inline]
1002 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1003 self.x_grid = [fetch, total];
1004 self
1005 }
1006
1007 #[inline]
1008 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1009 self.y_grid = [fetch, total];
1010 self
1011 }
1012
1013 #[inline]
1014 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1015 self.origin_position = [x, y];
1016 self
1017 }
1018
1019 #[inline]
1020 pub fn font(mut self, font: &str) -> Self {
1021 self.font = font.to_string();
1022 self
1023 }
1024
1025 #[inline]
1026 pub fn selectable(mut self, selectable: bool) -> Self {
1027 self.selectable = selectable;
1028 self
1029 }
1030
1031 #[inline]
1032 pub fn hyperlink_text(
1033 mut self,
1034 target_text: &str,
1035 select_method: HyperlinkSelectMethod,
1036 ) -> Self {
1037 self.hyperlink_text
1038 .push((target_text.to_string(), select_method));
1039 self
1040 }
1041}
1042
1043#[derive(Debug, Clone, PartialEq, PartialOrd)]
1045pub struct Text {
1046 pub discern_type: String,
1047 pub name: String,
1048 pub content: String,
1050 pub font_size: f32,
1052 pub color: [u8; 4],
1054 pub position: [f32; 2],
1056 pub center_display: (HorizontalAlign, VerticalAlign),
1058 pub wrap_width: f32,
1060 pub background_color: [u8; 4],
1062 pub background_rounding: f32,
1064 pub x_grid: [u32; 2],
1066 pub y_grid: [u32; 2],
1068 pub origin_position: [f32; 2],
1070 pub font: String,
1072 pub selection: Option<(usize, usize)>,
1074 pub selectable: bool,
1076 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1078 pub hyperlink_index: Vec<(usize, usize, String)>,
1080 pub last_frame_content: String,
1082}
1083
1084impl RustConstructorResource for Text {
1085 fn name(&self) -> &str {
1086 &self.name
1087 }
1088
1089 fn expose_type(&self) -> &str {
1090 &self.discern_type
1091 }
1092
1093 fn as_any(&self) -> &dyn Any {
1094 self
1095 }
1096
1097 fn as_any_mut(&mut self) -> &mut dyn Any {
1098 self
1099 }
1100}
1101
1102impl FrontResource for Text {
1103 fn position(&self) -> [f32; 2] {
1104 self.position
1105 }
1106
1107 fn size(&self) -> [f32; 2] {
1108 [self.wrap_width, -1_f32]
1109 }
1110
1111 fn modify_position(&mut self, x: f32, y: f32) {
1112 self.origin_position = [x, y];
1113 }
1114
1115 fn modify_size(&mut self, width: f32, _height: f32) {
1116 self.wrap_width = width;
1117 }
1118
1119 fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
1120 self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
1121 }
1122}
1123
1124impl Default for Text {
1125 fn default() -> Self {
1126 Self {
1127 discern_type: String::from("Text"),
1128 name: String::from("Text"),
1129 content: String::from("Hello world"),
1130 font_size: 16_f32,
1131 color: [255, 255, 255, 255],
1132 position: [0_f32, 0_f32],
1133 center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1134 wrap_width: 200_f32,
1135 background_color: [0, 0, 0, 0],
1136 background_rounding: 2_f32,
1137 x_grid: [0, 0],
1138 y_grid: [0, 0],
1139 origin_position: [0_f32, 0_f32],
1140 font: String::new(),
1141 selection: None,
1142 selectable: true,
1143 hyperlink_text: Vec::new(),
1144 hyperlink_index: Vec::new(),
1145 last_frame_content: String::from("Hello world"),
1146 }
1147 }
1148}
1149
1150impl Text {
1151 pub fn from_config(mut self, config: TextConfig) -> Self {
1152 self.content = config.content;
1153 self.font_size = config.font_size;
1154 self.color = config.color;
1155 self.center_display = config.center_display;
1156 self.wrap_width = config.wrap_width;
1157 self.background_color = config.background_color;
1158 self.background_rounding = config.background_rounding;
1159 self.x_grid = config.x_grid;
1160 self.y_grid = config.y_grid;
1161 self.origin_position = config.origin_position;
1162 self.font = config.font;
1163 self.selectable = config.selectable;
1164 self.hyperlink_text = config.hyperlink_text;
1165 self
1166 }
1167
1168 #[inline]
1169 pub fn name(mut self, name: &str) -> Self {
1170 self.name = name.to_string();
1171 self
1172 }
1173
1174 #[inline]
1175 pub fn content(mut self, content: &str) -> Self {
1176 self.content = content.to_string();
1177 self
1178 }
1179
1180 #[inline]
1181 pub fn font_size(mut self, font_size: f32) -> Self {
1182 self.font_size = font_size;
1183 self
1184 }
1185
1186 #[inline]
1187 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1188 self.color = [r, g, b, a];
1189 self
1190 }
1191
1192 #[inline]
1193 pub fn center_display(
1194 mut self,
1195 horizontal_align: HorizontalAlign,
1196 vertical_align: VerticalAlign,
1197 ) -> Self {
1198 self.center_display = (horizontal_align, vertical_align);
1199 self
1200 }
1201
1202 #[inline]
1203 pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1204 self.wrap_width = wrap_width;
1205 self
1206 }
1207
1208 #[inline]
1209 pub fn background_color(mut self, background_color: [u8; 4]) -> Self {
1210 self.background_color = background_color;
1211 self
1212 }
1213
1214 #[inline]
1215 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1216 self.background_rounding = background_rounding;
1217 self
1218 }
1219
1220 #[inline]
1221 pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1222 self.x_grid = [fetch, total];
1223 self
1224 }
1225
1226 #[inline]
1227 pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1228 self.y_grid = [fetch, total];
1229 self
1230 }
1231
1232 #[inline]
1233 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1234 self.origin_position = [x, y];
1235 self
1236 }
1237
1238 #[inline]
1239 pub fn font(mut self, font: &str) -> Self {
1240 self.font = font.to_string();
1241 self
1242 }
1243
1244 #[inline]
1245 pub fn selectable(mut self, selectable: bool) -> Self {
1246 self.selectable = selectable;
1247 self
1248 }
1249
1250 #[inline]
1251 pub fn hyperlink_text(
1252 mut self,
1253 target_text: &str,
1254 select_method: HyperlinkSelectMethod,
1255 ) -> Self {
1256 self.hyperlink_text
1257 .push((target_text.to_string(), select_method));
1258 self
1259 }
1260}
1261
1262#[derive(Debug, Clone, PartialEq, PartialOrd)]
1264pub struct Variable {
1265 pub discern_type: String,
1266 pub name: String,
1267 pub value: Value,
1269}
1270
1271impl RustConstructorResource for Variable {
1272 fn name(&self) -> &str {
1273 &self.name
1274 }
1275
1276 fn expose_type(&self) -> &str {
1277 &self.discern_type
1278 }
1279
1280 fn as_any(&self) -> &dyn Any {
1281 self
1282 }
1283
1284 fn as_any_mut(&mut self) -> &mut dyn Any {
1285 self
1286 }
1287}
1288
1289impl Default for Variable {
1290 fn default() -> Self {
1291 Variable {
1292 discern_type: String::from("Variable"),
1293 name: String::from("Variable"),
1294 value: Value::String(String::from("Hello world")),
1295 }
1296 }
1297}
1298
1299impl Variable {
1300 #[inline]
1301 pub fn name(mut self, name: &str) -> Self {
1302 self.name = name.to_string();
1303 self
1304 }
1305
1306 #[inline]
1307 pub fn value<T: Into<Value>>(mut self, value: T) -> Self {
1308 self.value = value.into();
1309 self
1310 }
1311
1312 pub fn new<T: Into<Value>>(name: &str, value: T) -> Self {
1313 Self {
1314 discern_type: String::from("Variable"),
1315 name: String::from(name),
1316 value: value.into(),
1317 }
1318 }
1319
1320 pub fn from_bool(name: &str, value: bool) -> Self {
1321 Self {
1322 discern_type: String::from("Variable"),
1323 name: String::from(name),
1324 value: Value::Bool(value),
1325 }
1326 }
1327
1328 pub fn from_int(name: &str, value: i32) -> Self {
1329 Self {
1330 discern_type: String::from("Variable"),
1331 name: String::from(name),
1332 value: Value::Int(value),
1333 }
1334 }
1335
1336 pub fn from_uint(name: &str, value: u32) -> Self {
1337 Self {
1338 discern_type: String::from("Variable"),
1339 name: String::from(name),
1340 value: Value::UInt(value),
1341 }
1342 }
1343
1344 pub fn from_float(name: &str, value: f32) -> Self {
1345 Self {
1346 discern_type: String::from("Variable"),
1347 name: String::from(name),
1348 value: Value::Float(value),
1349 }
1350 }
1351
1352 pub fn from_vec(name: &str, value: Vec<Value>) -> Self {
1353 Self {
1354 discern_type: String::from("Variable"),
1355 name: String::from(name),
1356 value: Value::Vec(value),
1357 }
1358 }
1359
1360 pub fn from_string<T: Into<String>>(name: &str, value: T) -> Self {
1361 Self {
1362 discern_type: String::from("Variable"),
1363 name: String::from(name),
1364 value: Value::String(value.into()),
1365 }
1366 }
1367}
1368
1369#[derive(Debug, Clone, PartialEq)]
1371pub struct Font {
1372 pub name: String,
1373 pub discern_type: String,
1374 pub font_definitions: FontDefinitions,
1376 pub path: String,
1378}
1379
1380impl RustConstructorResource for Font {
1381 fn name(&self) -> &str {
1382 &self.name
1383 }
1384
1385 fn expose_type(&self) -> &str {
1386 &self.discern_type
1387 }
1388
1389 fn as_any(&self) -> &dyn Any {
1390 self
1391 }
1392
1393 fn as_any_mut(&mut self) -> &mut dyn Any {
1394 self
1395 }
1396}
1397
1398impl Default for Font {
1399 fn default() -> Self {
1400 Self {
1401 discern_type: String::from("Font"),
1402 name: String::from("Font"),
1403 font_definitions: FontDefinitions::default(),
1404 path: String::from(""),
1405 }
1406 }
1407}
1408
1409impl Font {
1410 #[inline]
1411 pub fn name(mut self, name: &str) -> Self {
1412 self.name = name.to_string();
1413 self
1414 }
1415
1416 #[inline]
1417 pub fn path(mut self, path: &str) -> Self {
1418 self.path = path.to_string();
1419 self
1420 }
1421}
1422
1423#[derive(Debug, Clone, PartialEq, PartialOrd)]
1425pub struct SplitTime {
1426 pub discern_type: String,
1427 pub name: String,
1428 pub time: [f32; 2],
1430}
1431
1432impl RustConstructorResource for SplitTime {
1433 fn name(&self) -> &str {
1434 &self.name
1435 }
1436
1437 fn expose_type(&self) -> &str {
1438 &self.discern_type
1439 }
1440
1441 fn as_any(&self) -> &dyn Any {
1442 self
1443 }
1444
1445 fn as_any_mut(&mut self) -> &mut dyn Any {
1446 self
1447 }
1448}
1449
1450impl Default for SplitTime {
1451 fn default() -> Self {
1452 Self {
1453 discern_type: String::from("SplitTime"),
1454 name: String::from("SplitTime"),
1455 time: [0_f32, 0_f32],
1456 }
1457 }
1458}
1459
1460impl SplitTime {
1461 #[inline]
1462 pub fn name(mut self, name: &str) -> Self {
1463 self.name = name.to_string();
1464 self
1465 }
1466}
1467
1468#[derive(Debug, Clone, PartialEq)]
1470pub struct Switch {
1471 pub discern_type: String,
1472 pub name: String,
1473 pub appearance: Vec<SwitchData>,
1475 pub fill_resource_name: String,
1477 pub fill_resource_type: String,
1479 pub enable_hover_click_fill_resource: [bool; 2],
1481 pub state: u32,
1483 pub click_method: Vec<SwitchClickAction>,
1485 pub last_time_hovered: bool,
1487 pub last_time_clicked: bool,
1489 pub last_time_clicked_index: usize,
1491 pub animation_count: u32,
1493 pub hint_text_name: String,
1495 pub text_name: String,
1497 pub text_origin_position: [f32; 2],
1499}
1500
1501impl RustConstructorResource for Switch {
1502 fn name(&self) -> &str {
1503 &self.name
1504 }
1505
1506 fn expose_type(&self) -> &str {
1507 &self.discern_type
1508 }
1509
1510 fn as_any(&self) -> &dyn Any {
1511 self
1512 }
1513
1514 fn as_any_mut(&mut self) -> &mut dyn Any {
1515 self
1516 }
1517}
1518
1519impl Default for Switch {
1520 fn default() -> Self {
1521 Self {
1522 discern_type: String::from("Switch"),
1523 name: String::from("Switch"),
1524 appearance: vec![],
1525 fill_resource_name: String::from("FillResource"),
1526 fill_resource_type: String::from("Image"),
1527 enable_hover_click_fill_resource: [false, false],
1528 state: 0,
1529 click_method: vec![],
1530 last_time_hovered: false,
1531 last_time_clicked: false,
1532 last_time_clicked_index: 5,
1533 animation_count: 0,
1534 hint_text_name: String::from("HintText"),
1535 text_name: String::from("Text"),
1536 text_origin_position: [0_f32, 0_f32],
1537 }
1538 }
1539}
1540
1541impl Switch {
1542 #[inline]
1543 pub fn name(mut self, name: &str) -> Self {
1544 self.name = name.to_string();
1545 self
1546 }
1547
1548 #[inline]
1549 pub fn appearance(mut self, appearance: Vec<SwitchData>) -> Self {
1550 self.appearance = appearance;
1551 self
1552 }
1553
1554 #[inline]
1555 pub fn enable_hover_click_fill_resource(
1556 mut self,
1557 enable_hover_fill_resource: bool,
1558 enable_click_fill_resource: bool,
1559 ) -> Self {
1560 self.enable_hover_click_fill_resource =
1561 [enable_hover_fill_resource, enable_click_fill_resource];
1562 self
1563 }
1564
1565 #[inline]
1566 pub fn click_method(mut self, click_method: Vec<SwitchClickAction>) -> Self {
1567 self.click_method = click_method;
1568 self
1569 }
1570}
1571
1572#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1574pub struct RenderResource {
1575 pub discern_type: String,
1576 pub name: String,
1577}
1578
1579#[derive(Debug, Clone, PartialEq, PartialOrd)]
1581pub struct SwitchData {
1582 pub image_config: ImageConfig,
1584 pub custom_rect_config: CustomRectConfig,
1586 pub text_config: TextConfig,
1588 pub texture: String,
1590 pub hint_text: String,
1592}
1593
1594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1596pub struct SwitchClickAction {
1597 pub click_method: PointerButton,
1599 pub action: bool,
1601}
1602
1603#[derive(Debug, Clone, PartialEq, PartialOrd)]
1605pub struct MessageBox {
1606 pub discern_type: String,
1607 pub name: String,
1608 pub size: [f32; 2],
1610 pub content_name: String,
1612 pub title_name: String,
1614 pub image_name: String,
1616 pub keep_existing: bool,
1618 pub existing_time: f32,
1620 pub exist: bool,
1622 pub speed: f32,
1624 pub restore_speed: f32,
1626 pub memory_offset: f32,
1628}
1629
1630impl RustConstructorResource for MessageBox {
1631 fn name(&self) -> &str {
1632 &self.name
1633 }
1634
1635 fn expose_type(&self) -> &str {
1636 &self.discern_type
1637 }
1638
1639 fn as_any(&self) -> &dyn Any {
1640 self
1641 }
1642
1643 fn as_any_mut(&mut self) -> &mut dyn Any {
1644 self
1645 }
1646}
1647
1648impl Default for MessageBox {
1649 fn default() -> Self {
1650 Self {
1651 discern_type: String::from("MessageBox"),
1652 name: String::from("MessageBox"),
1653 size: [100_f32, 100_f32],
1654 content_name: String::from("Content"),
1655 title_name: String::from("Title"),
1656 image_name: String::from("Image"),
1657 keep_existing: false,
1658 existing_time: 3_f32,
1659 exist: true,
1660 speed: 30_f32,
1661 restore_speed: 10_f32,
1662 memory_offset: 0_f32,
1663 }
1664 }
1665}
1666
1667impl MessageBox {
1668 #[inline]
1669 pub fn name(mut self, name: &str) -> Self {
1670 self.name = name.to_string();
1671 self
1672 }
1673
1674 #[inline]
1675 pub fn size(mut self, width: f32, height: f32) -> Self {
1676 self.size = [width, height];
1677 self
1678 }
1679
1680 #[inline]
1681 pub fn keep_existing(mut self, keep_existing: bool) -> Self {
1682 self.keep_existing = keep_existing;
1683 self
1684 }
1685
1686 #[inline]
1687 pub fn existing_time(mut self, existing_time: f32) -> Self {
1688 self.existing_time = existing_time;
1689 self
1690 }
1691
1692 #[inline]
1693 pub fn speed(mut self, speed: f32) -> Self {
1694 self.speed = speed;
1695 self
1696 }
1697
1698 #[inline]
1699 pub fn restore_speed(mut self, restore_speed: f32) -> Self {
1700 self.restore_speed = restore_speed;
1701 self
1702 }
1703}
1704
1705#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1707pub enum RustConstructorError {
1708 ImageGetFailed { image_path: String },
1710 ImageNotFound { image_name: String },
1712 ImageTextureNotFound { image_texture_name: String },
1714 TextNotFound { text_name: String },
1716 VariableNotFound { variable_name: String },
1718 VariableNotInt { variable_name: String },
1720 VariableNotUInt { variable_name: String },
1722 VariableNotFloat { variable_name: String },
1724 VariableNotVec { variable_name: String },
1726 VariableNotBool { variable_name: String },
1728 VariableNotString { variable_name: String },
1730 SplitTimeNotFound { split_time_name: String },
1732 SwitchAppearanceMismatch { switch_name: String, differ: u32 },
1734 SwitchFillResourceMismatch {
1736 switch_name: String,
1737 fill_resource_name: String,
1738 fill_resource_type: String,
1739 },
1740 SwitchNotFound { switch_name: String },
1742 MessageBoxAlreadyExists { message_box_name: String },
1744 FontGetFailed { font_path: String },
1746 FontNotFound { font_name: String },
1748 RectNotFound { rect_name: String },
1750 ResourceNotFound {
1752 resource_name: String,
1753 resource_type: String,
1754 },
1755 PageNotFound { page_name: String },
1757 CustomError {
1759 error_name: String,
1760 error_message: String,
1761 error_annotation: String,
1762 },
1763}
1764
1765impl Display for RustConstructorError {
1766 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1767 Debug::fmt(self, f)
1768 }
1769}
1770
1771impl Error for RustConstructorError {}
1772
1773impl Default for RustConstructorError {
1774 fn default() -> Self {
1775 RustConstructorError::ImageGetFailed {
1776 image_path: "".to_string(),
1777 }
1778 }
1779}
1780
1781#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1783pub enum HorizontalAlign {
1784 #[default]
1786 Left,
1787 Center,
1789 Right,
1791}
1792
1793#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1795pub enum VerticalAlign {
1796 #[default]
1798 Top,
1799 Center,
1801 Bottom,
1803}
1804
1805#[derive(Debug, Default)]
1807pub struct App {
1808 pub strict_mode: bool,
1810 pub rust_constructor_resource: Vec<Box<dyn RustConstructorResource>>,
1812 pub render_resource_list: Vec<RenderResource>,
1814 pub problem_list: Vec<Problem>,
1816 pub tick_interval: f32,
1818 pub current_page: String,
1820 pub timer: Timer,
1822 pub frame_times: Vec<f32>,
1824 pub last_frame_time: Option<f64>,
1826}
1827
1828impl App {
1829 #[inline]
1830 pub fn strict_mode(mut self, strict_mode: bool) -> Self {
1831 self.strict_mode = strict_mode;
1832 self
1833 }
1834
1835 #[inline]
1836 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
1837 self.tick_interval = tick_interval;
1838 self
1839 }
1840
1841 #[inline]
1842 pub fn current_page(mut self, current_page: &str) -> Self {
1843 self.current_page = current_page.to_string();
1844 self
1845 }
1846
1847 pub fn page_handler(&mut self, ctx: &Context) {
1849 self.update_frame_stats(ctx);
1851 self.render_resource_list = Vec::new();
1853 self.update_timer();
1855 if let Ok(pd) = self.get_resource::<PageData>(&self.current_page.clone(), "PageData")
1856 && pd.forced_update
1857 {
1858 ctx.request_repaint();
1860 };
1861 }
1862
1863 pub fn add_page(&mut self, mut page_data: PageData) {
1865 page_data.change_page_updated = false;
1866 page_data.enter_page_updated = false;
1867 self.rust_constructor_resource.push(Box::new(page_data));
1868 }
1869
1870 pub fn switch_page(&mut self, page: &str) -> Result<(), RustConstructorError> {
1872 if self.check_resource_exists(page, "PageData") {
1873 self.current_page = page.to_string();
1874 let pd = self.get_resource_mut::<PageData>(page, "PageData").unwrap();
1875 pd.enter_page_updated = false;
1876 self.timer.start_time = self.timer.total_time;
1877 self.update_timer();
1878 Ok(())
1879 } else {
1880 self.problem_report_custom(
1881 RustConstructorError::PageNotFound {
1882 page_name: page.to_string(),
1883 },
1884 SeverityLevel::SevereWarning,
1885 self.problem_list.clone(),
1886 );
1887 Err(RustConstructorError::PageNotFound {
1888 page_name: page.to_string(),
1889 })
1890 }
1891 }
1892
1893 pub fn replace_resource_custom<T>(
1895 &self,
1896 name: &str,
1897 discern_type: &str,
1898 resource: T,
1899 mut target: Vec<Box<dyn RustConstructorResource>>,
1900 ) -> Result<(), RustConstructorError>
1901 where
1902 T: RustConstructorResource + 'static,
1903 {
1904 if let Some(index) = self
1905 .rust_constructor_resource
1906 .iter()
1907 .position(|x| x.name() == name && x.expose_type() == discern_type)
1908 {
1909 target[index] = Box::new(resource);
1910 Ok(())
1911 } else {
1912 self.problem_report_custom(
1913 RustConstructorError::ResourceNotFound {
1914 resource_name: name.to_string(),
1915 resource_type: discern_type.to_string(),
1916 },
1917 SeverityLevel::SevereWarning,
1918 self.problem_list.clone(),
1919 );
1920 Err(RustConstructorError::ResourceNotFound {
1921 resource_name: name.to_string(),
1922 resource_type: discern_type.to_string(),
1923 })
1924 }
1925 }
1926
1927 pub fn replace_resource<T>(
1929 &mut self,
1930 name: &str,
1931 discern_type: &str,
1932 resource: T,
1933 ) -> Result<(), RustConstructorError>
1934 where
1935 T: RustConstructorResource + 'static,
1936 {
1937 if let Some(index) = self
1938 .rust_constructor_resource
1939 .iter()
1940 .position(|x| x.name() == name && x.expose_type() == discern_type)
1941 {
1942 self.rust_constructor_resource[index] = Box::new(resource);
1943 Ok(())
1944 } else {
1945 self.problem_report_custom(
1946 RustConstructorError::ResourceNotFound {
1947 resource_name: name.to_string(),
1948 resource_type: discern_type.to_string(),
1949 },
1950 SeverityLevel::SevereWarning,
1951 self.problem_list.clone(),
1952 );
1953 Err(RustConstructorError::ResourceNotFound {
1954 resource_name: name.to_string(),
1955 resource_type: discern_type.to_string(),
1956 })
1957 }
1958 }
1959
1960 pub fn get_resource<T>(
1962 &self,
1963 name: &str,
1964 discern_type: &str,
1965 ) -> Result<&T, RustConstructorError>
1966 where
1967 T: RustConstructorResource + 'static,
1968 {
1969 if self.check_resource_exists(name, discern_type) {
1970 Ok(self
1971 .rust_constructor_resource
1972 .iter()
1973 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
1974 .and_then(|resource| resource.as_any().downcast_ref::<T>())
1975 .unwrap())
1976 } else {
1977 self.problem_report_custom(
1978 RustConstructorError::ResourceNotFound {
1979 resource_name: name.to_string(),
1980 resource_type: discern_type.to_string(),
1981 },
1982 SeverityLevel::SevereWarning,
1983 self.problem_list.clone(),
1984 );
1985 Err(RustConstructorError::ResourceNotFound {
1986 resource_name: name.to_string(),
1987 resource_type: discern_type.to_string(),
1988 })
1989 }
1990 }
1991
1992 pub fn get_resource_mut<T>(
1994 &mut self,
1995 name: &str,
1996 discern_type: &str,
1997 ) -> Result<&mut T, RustConstructorError>
1998 where
1999 T: RustConstructorResource + 'static,
2000 {
2001 if self.check_resource_exists(name, discern_type) {
2002 Ok(self
2003 .rust_constructor_resource
2004 .iter_mut()
2005 .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2006 .and_then(|resource| resource.as_any_mut().downcast_mut::<T>())
2007 .unwrap())
2008 } else {
2009 self.problem_report_custom(
2010 RustConstructorError::ResourceNotFound {
2011 resource_name: name.to_string(),
2012 resource_type: discern_type.to_string(),
2013 },
2014 SeverityLevel::SevereWarning,
2015 self.problem_list.clone(),
2016 );
2017 Err(RustConstructorError::ResourceNotFound {
2018 resource_name: name.to_string(),
2019 resource_type: discern_type.to_string(),
2020 })
2021 }
2022 }
2023
2024 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> bool {
2026 self.rust_constructor_resource
2027 .iter()
2028 .any(|x| x.name() == name && x.expose_type() == discern_type)
2029 }
2030
2031 pub fn add_fonts(&mut self, mut font: Font) {
2033 let mut fonts = FontDefinitions::default();
2034 if let Ok(font_read_data) = read(font.path.clone()) {
2035 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
2036 fonts.font_data.insert(
2037 font.name.to_owned(),
2038 Arc::new(FontData::from_owned(
2039 Arc::try_unwrap(font_data).ok().unwrap(),
2040 )),
2041 );
2042
2043 fonts
2045 .families
2046 .entry(FontFamily::Proportional)
2047 .or_default()
2048 .insert(0, font.name.to_owned());
2049
2050 fonts
2051 .families
2052 .entry(FontFamily::Monospace)
2053 .or_default()
2054 .insert(0, font.name.to_owned());
2055
2056 font.font_definitions = fonts;
2057 self.rust_constructor_resource.push(Box::new(font));
2058 } else {
2059 self.problem_report_custom(
2060 RustConstructorError::FontGetFailed {
2061 font_path: font.path.to_string(),
2062 },
2063 SeverityLevel::SevereWarning,
2064 self.problem_list.clone(),
2065 );
2066 };
2067 }
2068
2069 pub fn font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
2071 if let Ok(f) = self.get_resource::<Font>(name, "Font") {
2072 return Ok(f.font_definitions.clone());
2073 }
2074 self.problem_report_custom(
2075 RustConstructorError::FontNotFound {
2076 font_name: name.to_string(),
2077 },
2078 SeverityLevel::SevereWarning,
2079 self.problem_list.clone(),
2080 );
2081 Err(RustConstructorError::FontNotFound {
2082 font_name: name.to_string(),
2083 })
2084 }
2085
2086 pub fn register_all_fonts(&mut self, ctx: &Context) {
2088 let mut font_definitions = FontDefinitions::default();
2089 let mut font_resources = Vec::new();
2090 for i in 0..self.rust_constructor_resource.len() {
2091 if let Some(f) = self.rust_constructor_resource[i]
2092 .as_any()
2093 .downcast_ref::<Font>()
2094 {
2095 font_resources.push(f.clone());
2096 };
2097 }
2098 for i in &font_resources {
2099 let font_name = i.name.clone();
2100 if let Ok(font_def) = self.font(&font_name) {
2102 if let Some(font_data) = font_def.font_data.get(&font_name) {
2104 font_definitions
2105 .font_data
2106 .insert(font_name.clone(), Arc::clone(font_data));
2107 font_definitions
2108 .families
2109 .entry(FontFamily::Name(font_name.clone().into()))
2110 .or_default()
2111 .push(font_name.clone());
2112 };
2113
2114 font_definitions
2116 .families
2117 .entry(FontFamily::Proportional)
2118 .or_default()
2119 .insert(0, font_name.to_owned());
2120
2121 font_definitions
2122 .families
2123 .entry(FontFamily::Monospace)
2124 .or_default()
2125 .insert(0, font_name.to_owned());
2126 };
2127 }
2128 ctx.set_fonts(font_definitions);
2129 }
2130
2131 pub fn problem_report(
2133 &mut self,
2134 problem_type: RustConstructorError,
2135 severity_level: SeverityLevel,
2136 ) {
2137 let (problem, annotation) = match problem_type.clone() {
2138 RustConstructorError::FontGetFailed { font_path } => (
2139 format!("Font get failed: {}", font_path,),
2140 "Please check if the font file exists and the path is correct.".to_string(),
2141 ),
2142 RustConstructorError::FontNotFound { font_name } => (
2143 format!("Font not found: {}", font_name,),
2144 "Please check whether the font has been added.".to_string(),
2145 ),
2146 RustConstructorError::ImageGetFailed { image_path } => (
2147 format!("Image get failed: {}", image_path,),
2148 "Please check whether the image path is correct and whether the image has been added.".to_string(),
2149 ),
2150 RustConstructorError::ImageNotFound { image_name } => (
2151 format!("Image not found: {}", image_name,),
2152 "Please check whether the image has been added.".to_string(),
2153 ),
2154 RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2155 format!("Image texture not found: {}", image_texture_name,),
2156 "Please check whether the image texture has been added.".to_string(),
2157 ),
2158 RustConstructorError::TextNotFound { text_name } => (
2159 format!("Text not found: {}", text_name,),
2160 "Please check whether the text has been added.".to_string(),
2161 ),
2162 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2163 format!("Message box already exists: {}", message_box_name,),
2164 "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2165 ),
2166 RustConstructorError::SplitTimeNotFound { split_time_name } => (
2167 format!("Split time not found: {}", split_time_name,),
2168 "Please check whether the split time has been added.".to_string(),
2169 ),
2170 RustConstructorError::SwitchAppearanceMismatch {
2171 switch_name,
2172 differ,
2173 } => (
2174 format!(
2175 "Switch appearance list's number of items is large / small {} more: {}",
2176 differ, switch_name
2177 ),
2178 "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2179 ),
2180 RustConstructorError::SwitchNotFound { switch_name } => (
2181 format!("Switch not found: {}", switch_name,),
2182 "Please check whether the switch has been added.".to_string(),
2183 ),
2184 RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2185 format!("Switch fill resource mismatch: Resource {} of switch {} is not of type {}", fill_resource_name, switch_name, fill_resource_type,),
2186 "Please check whether the imported fill resource is correctly typed.".to_string(),
2187 ),
2188 RustConstructorError::PageNotFound { page_name } => (
2189 format!("Page not found: {}", page_name,),
2190 "Please check whether the page has been added.".to_string(),
2191 ),
2192 RustConstructorError::VariableNotFound { variable_name } => (
2193 format!("Variable not found: {}", variable_name,),
2194 "Please check whether the variable has been added.".to_string(),
2195 ),
2196 RustConstructorError::VariableNotBool { variable_name } => (
2197 format!("Variable is not bool: {}", variable_name,),
2198 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2199 ),
2200 RustConstructorError::VariableNotFloat { variable_name } => (
2201 format!("Variable is not f32: {}", variable_name,),
2202 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2203 ),
2204 RustConstructorError::VariableNotInt { variable_name } => (
2205 format!("Variable is not int: {}", variable_name,),
2206 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2207 ),
2208 RustConstructorError::VariableNotString { variable_name } => (
2209 format!("Variable is not string: {}", variable_name,),
2210 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2211 ),
2212 RustConstructorError::VariableNotUInt { variable_name } => (
2213 format!("Variable is not uint: {}", variable_name,),
2214 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2215 ),
2216 RustConstructorError::VariableNotVec { variable_name } => (
2217 format!("Variable is not vec: {}", variable_name,),
2218 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2219 ),
2220 RustConstructorError::RectNotFound { rect_name } => (
2221 format!("Rect not found: {}", rect_name,),
2222 "Please check whether the rect has been added.".to_string(),
2223 ),
2224 RustConstructorError::ResourceNotFound {
2225 resource_name,
2226 resource_type,
2227 } => (
2228 format!(
2229 "Resource not found: {}(\"{}\")",
2230 resource_type, resource_name,
2231 ),
2232 "Please check whether the resource has been added.".to_string(),
2233 ),
2234 RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2235 format!("Custom error({}): {}", error_name, error_message),
2236 error_annotation
2237 )
2238 };
2239 if self.strict_mode {
2241 panic!("{}", problem);
2242 };
2243 self.problem_list.push(Problem {
2244 severity_level,
2245 problem,
2246 annotation,
2247 report_state: ReportState {
2248 current_page: self.current_page.clone(),
2249 current_total_runtime: self.timer.total_time,
2250 current_page_runtime: self.timer.now_time,
2251 },
2252 problem_type: problem_type.clone(),
2253 });
2254 }
2255
2256 pub fn problem_report_custom(
2258 &self,
2259 problem_type: RustConstructorError,
2260 severity_level: SeverityLevel,
2261 mut problem_storage: Vec<Problem>,
2262 ) {
2263 let (problem, annotation) = match problem_type.clone() {
2264 RustConstructorError::FontGetFailed { font_path } => (
2265 format!("Font get failed: {}", font_path,),
2266 "Please check if the font file exists and the path is correct.".to_string(),
2267 ),
2268 RustConstructorError::FontNotFound { font_name } => (
2269 format!("Font not found: {}", font_name,),
2270 "Please check whether the font has been added.".to_string(),
2271 ),
2272 RustConstructorError::ImageGetFailed { image_path } => (
2273 format!("Image get failed: {}", image_path,),
2274 "Please check whether the image path is correct and whether the image has been added.".to_string(),
2275 ),
2276 RustConstructorError::ImageNotFound { image_name } => (
2277 format!("Image not found: {}", image_name,),
2278 "Please check whether the image has been added.".to_string(),
2279 ),
2280 RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2281 format!("Image texture not found: {}", image_texture_name,),
2282 "Please check whether the image texture has been added.".to_string(),
2283 ),
2284 RustConstructorError::TextNotFound { text_name } => (
2285 format!("Text not found: {}", text_name,),
2286 "Please check whether the text has been added.".to_string(),
2287 ),
2288 RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2289 format!("Message box already exists: {}", message_box_name,),
2290 "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2291 ),
2292 RustConstructorError::SplitTimeNotFound { split_time_name } => (
2293 format!("Split time not found: {}", split_time_name,),
2294 "Please check whether the split time has been added.".to_string(),
2295 ),
2296 RustConstructorError::SwitchAppearanceMismatch {
2297 switch_name,
2298 differ,
2299 } => (
2300 format!(
2301 "Switch appearance list's number of items is large / small {} more: {}",
2302 differ, switch_name
2303 ),
2304 "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2305 ),
2306 RustConstructorError::SwitchNotFound { switch_name } => (
2307 format!("Switch not found: {}", switch_name,),
2308 "Please check whether the switch has been added.".to_string(),
2309 ),
2310 RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2311 format!("Switch fill resource mismatch: Resource {} of switch {} is not of type {}", fill_resource_name, switch_name, fill_resource_type,),
2312 "Please check whether the imported fill resource is correctly typed.".to_string(),
2313 ),
2314 RustConstructorError::PageNotFound { page_name } => (
2315 format!("Page not found: {}", page_name,),
2316 "Please check whether the page has been added.".to_string(),
2317 ),
2318 RustConstructorError::VariableNotFound { variable_name } => (
2319 format!("Variable not found: {}", variable_name,),
2320 "Please check whether the variable has been added.".to_string(),
2321 ),
2322 RustConstructorError::VariableNotBool { variable_name } => (
2323 format!("Variable is not bool: {}", variable_name,),
2324 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2325 ),
2326 RustConstructorError::VariableNotFloat { variable_name } => (
2327 format!("Variable is not f32: {}", variable_name,),
2328 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2329 ),
2330 RustConstructorError::VariableNotInt { variable_name } => (
2331 format!("Variable is not int: {}", variable_name,),
2332 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2333 ),
2334 RustConstructorError::VariableNotString { variable_name } => (
2335 format!("Variable is not string: {}", variable_name,),
2336 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2337 ),
2338 RustConstructorError::VariableNotUInt { variable_name } => (
2339 format!("Variable is not uint: {}", variable_name,),
2340 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2341 ),
2342 RustConstructorError::VariableNotVec { variable_name } => (
2343 format!("Variable is not vec: {}", variable_name,),
2344 "Please check whether the variable names and types are correct and whether there are duplicate items.".to_string(),
2345 ),
2346 RustConstructorError::RectNotFound { rect_name } => (
2347 format!("Rect not found: {}", rect_name,),
2348 "Please check whether the rect has been added.".to_string(),
2349 ),
2350 RustConstructorError::ResourceNotFound {
2351 resource_name,
2352 resource_type,
2353 } => (
2354 format!(
2355 "Resource not found: {}(\"{}\")",
2356 resource_type, resource_name,
2357 ),
2358 "Please check whether the resource has been added.".to_string(),
2359 ),
2360 RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2361 format!("Custom error({}): {}", error_name, error_message),
2362 error_annotation
2363 )
2364 };
2365 if self.strict_mode {
2367 panic!("{}", problem);
2368 };
2369 problem_storage.push(Problem {
2370 severity_level,
2371 problem,
2372 annotation,
2373 report_state: ReportState {
2374 current_page: self.current_page.clone(),
2375 current_total_runtime: self.timer.total_time,
2376 current_page_runtime: self.timer.now_time,
2377 },
2378 problem_type: problem_type.clone(),
2379 });
2380 }
2381
2382 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
2384 if self.check_resource_exists(name, "PageData") {
2385 let pd = self
2386 .get_resource::<PageData>(name, "PageData")
2387 .unwrap()
2388 .clone();
2389 if !pd.change_page_updated {
2390 self.new_page_update(name).unwrap();
2391 };
2392 Ok(pd.change_page_updated)
2393 } else {
2394 self.problem_report_custom(
2395 RustConstructorError::PageNotFound {
2396 page_name: name.to_string(),
2397 },
2398 SeverityLevel::SevereWarning,
2399 self.problem_list.clone(),
2400 );
2401 Err(RustConstructorError::PageNotFound {
2402 page_name: name.to_string(),
2403 })
2404 }
2405 }
2406
2407 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
2409 if self.check_resource_exists(name, "PageData") {
2410 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2411 let return_value = pd.enter_page_updated;
2412 pd.enter_page_updated = true;
2413 Ok(return_value)
2414 } else {
2415 self.problem_report_custom(
2416 RustConstructorError::PageNotFound {
2417 page_name: name.to_string(),
2418 },
2419 SeverityLevel::SevereWarning,
2420 self.problem_list.clone(),
2421 );
2422 Err(RustConstructorError::PageNotFound {
2423 page_name: name.to_string(),
2424 })
2425 }
2426 }
2427
2428 pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
2430 if self.check_resource_exists(name, "PageData") {
2431 self.timer.start_time = self.timer.total_time;
2432 self.update_timer();
2433 let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2434 pd.change_page_updated = true;
2435 Ok(())
2436 } else {
2437 self.problem_report_custom(
2438 RustConstructorError::PageNotFound {
2439 page_name: name.to_string(),
2440 },
2441 SeverityLevel::SevereWarning,
2442 self.problem_list.clone(),
2443 );
2444 Err(RustConstructorError::PageNotFound {
2445 page_name: name.to_string(),
2446 })
2447 }
2448 }
2449
2450 pub fn update_frame_stats(&mut self, ctx: &Context) {
2452 let current_time = ctx.input(|i| i.time);
2453 if let Some(last) = self.last_frame_time {
2454 let delta = (current_time - last) as f32;
2455 self.frame_times.push(delta);
2456 const MAX_SAMPLES: usize = 120;
2457 if self.frame_times.len() > MAX_SAMPLES {
2458 let remove_count = self.frame_times.len() - MAX_SAMPLES;
2459 self.frame_times.drain(0..remove_count);
2460 }
2461 }
2462 self.last_frame_time = Some(current_time);
2463 }
2464
2465 pub fn current_fps(&self) -> f32 {
2467 if self.frame_times.is_empty() {
2468 0.0
2469 } else {
2470 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
2471 }
2472 }
2473
2474 pub fn add_split_time(&mut self, mut split_time: SplitTime) {
2476 split_time.time = [self.timer.now_time, self.timer.total_time];
2477 self.rust_constructor_resource.push(Box::new(split_time));
2478 }
2479
2480 pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
2482 if self.check_resource_exists(name, "SplitTime") {
2483 let new_time = [self.timer.now_time, self.timer.total_time];
2484 let st = self
2485 .get_resource_mut::<SplitTime>(name, "SplitTime")
2486 .unwrap();
2487 st.time = new_time;
2488 Ok(())
2489 } else {
2490 self.problem_report_custom(
2491 RustConstructorError::SplitTimeNotFound {
2492 split_time_name: name.to_string(),
2493 },
2494 SeverityLevel::SevereWarning,
2495 self.problem_list.clone(),
2496 );
2497 Err(RustConstructorError::SplitTimeNotFound {
2498 split_time_name: name.to_string(),
2499 })
2500 }
2501 }
2502
2503 pub fn split_time(&self, name: &str) -> Result<[f32; 2], RustConstructorError> {
2505 if self.check_resource_exists(name, "SplitTime") {
2506 let st = self.get_resource::<SplitTime>(name, "SplitTime").unwrap();
2507 Ok(st.time)
2508 } else {
2509 self.problem_report_custom(
2510 RustConstructorError::SplitTimeNotFound {
2511 split_time_name: name.to_string(),
2512 },
2513 SeverityLevel::SevereWarning,
2514 self.problem_list.clone(),
2515 );
2516 Err(RustConstructorError::SplitTimeNotFound {
2517 split_time_name: name.to_string(),
2518 })
2519 }
2520 }
2521
2522 pub fn update_timer(&mut self) {
2524 let elapsed = self.timer.timer.elapsed();
2525 let seconds = elapsed.as_secs();
2526 let milliseconds = elapsed.subsec_millis();
2527 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
2528 self.timer.now_time = self.timer.total_time - self.timer.start_time
2529 }
2530
2531 pub fn add_custom_rect(&mut self, custom_rect: CustomRect) {
2533 self.rust_constructor_resource.push(Box::new(custom_rect));
2534 }
2535
2536 pub fn custom_rect(
2538 &mut self,
2539 name: &str,
2540 ui: &mut Ui,
2541 ctx: &Context,
2542 ) -> Result<(), RustConstructorError> {
2543 if self.check_resource_exists(name, "CustomRect") {
2544 let render_resource_list = &mut self.render_resource_list.clone();
2545 let cr = self
2546 .get_resource_mut::<CustomRect>(name, "CustomRect")
2547 .unwrap();
2548 cr.reg_render_resource(render_resource_list);
2549 cr.position[0] = match cr.x_grid[1] {
2550 0 => cr.origin_position[0],
2551 _ => {
2552 (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64
2553 * cr.x_grid[0] as f64) as f32
2554 + cr.origin_position[0]
2555 }
2556 };
2557 cr.position[1] = match cr.y_grid[1] {
2558 0 => cr.origin_position[1],
2559 _ => {
2560 (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64
2561 * cr.y_grid[0] as f64) as f32
2562 + cr.origin_position[1]
2563 }
2564 };
2565 match cr.center_display.0 {
2566 HorizontalAlign::Left => {}
2567 HorizontalAlign::Center => cr.position[0] -= cr.size[0] / 2.0,
2568 HorizontalAlign::Right => cr.position[0] -= cr.size[0],
2569 };
2570 match cr.center_display.1 {
2571 VerticalAlign::Top => {}
2572 VerticalAlign::Center => cr.position[1] -= cr.size[1] / 2.0,
2573 VerticalAlign::Bottom => cr.position[1] -= cr.size[1],
2574 };
2575 ui.painter().rect(
2576 Rect::from_min_max(
2577 Pos2::new(cr.position[0], cr.position[1]),
2578 Pos2::new(cr.position[0] + cr.size[0], cr.position[1] + cr.size[1]),
2579 ),
2580 cr.rounding,
2581 Color32::from_rgba_unmultiplied(cr.color[0], cr.color[1], cr.color[2], cr.color[3]),
2582 Stroke {
2583 width: cr.border_width,
2584 color: Color32::from_rgba_unmultiplied(
2585 cr.border_color[0],
2586 cr.border_color[1],
2587 cr.border_color[2],
2588 cr.border_color[3],
2589 ),
2590 },
2591 StrokeKind::Inside,
2592 );
2593 Ok(())
2594 } else {
2595 self.problem_report_custom(
2596 RustConstructorError::RectNotFound {
2597 rect_name: name.to_string(),
2598 },
2599 SeverityLevel::SevereWarning,
2600 self.problem_list.clone(),
2601 );
2602 Err(RustConstructorError::RectNotFound {
2603 rect_name: name.to_string(),
2604 })
2605 }
2606 }
2607
2608 pub fn add_text(&mut self, text: Text) {
2610 self.rust_constructor_resource.push(Box::new(text));
2611 }
2612
2613 pub fn text(
2615 &mut self,
2616 name: &str,
2617 ui: &mut Ui,
2618 ctx: &Context,
2619 ) -> Result<(), RustConstructorError> {
2620 if self.check_resource_exists(name, "Text") {
2621 let mut t = self.get_resource::<Text>(name, "Text").unwrap().clone();
2622 t.reg_render_resource(&mut self.render_resource_list);
2623 let galley: Arc<Galley> = ui.fonts_mut(|f| {
2625 f.layout(
2626 t.content.to_string(),
2627 if self.check_resource_exists(&t.font.clone(), "Font") {
2628 FontId::new(t.font_size, FontFamily::Name(t.font.clone().into()))
2629 } else {
2630 if !t.font.is_empty() {
2631 self.problem_report_custom(
2632 RustConstructorError::FontNotFound {
2633 font_name: t.font.clone(),
2634 },
2635 SeverityLevel::MildWarning,
2636 self.problem_list.clone(),
2637 );
2638 };
2639 FontId::proportional(t.font_size)
2640 },
2641 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]),
2642 t.wrap_width,
2643 )
2644 });
2645 let text_size = galley.size();
2646 t.position[0] = match t.x_grid[1] {
2647 0 => t.origin_position[0],
2648 _ => {
2649 (ctx.available_rect().width() as f64 / t.x_grid[1] as f64 * t.x_grid[0] as f64)
2650 as f32
2651 + t.origin_position[0]
2652 }
2653 };
2654 t.position[1] = match t.y_grid[1] {
2655 0 => t.origin_position[1],
2656 _ => {
2657 (ctx.available_rect().height() as f64 / t.y_grid[1] as f64 * t.y_grid[0] as f64)
2658 as f32
2659 + t.origin_position[1]
2660 }
2661 };
2662 let pos_x = match t.center_display.0 {
2663 HorizontalAlign::Left => t.position[0],
2664 HorizontalAlign::Center => t.position[0] - text_size.x / 2.0,
2665 HorizontalAlign::Right => t.position[0] - text_size.x,
2666 };
2667 let pos_y = match t.center_display.1 {
2668 VerticalAlign::Top => t.position[1],
2669 VerticalAlign::Center => t.position[1] - text_size.y / 2.0,
2670 VerticalAlign::Bottom => t.position[1] - text_size.y,
2671 };
2672 let position = Pos2::new(pos_x, pos_y);
2674
2675 let rect = Rect::from_min_size(position, text_size);
2676 ui.painter().rect_filled(
2678 rect,
2679 t.background_rounding,
2680 Color32::from_rgba_unmultiplied(
2681 t.background_color[0],
2682 t.background_color[1],
2683 t.background_color[2],
2684 t.background_color[3],
2685 ),
2686 ); ui.painter().galley(
2689 position,
2690 galley.clone(),
2691 Color32::from_rgba_unmultiplied(
2692 t.color[0], t.color[1], t.color[2], t.color[3], ),
2694 );
2695
2696 if t.last_frame_content != t.content {
2698 t.hyperlink_index.clear();
2699 for (text, method) in &t.hyperlink_text {
2700 let matches: Vec<(usize, &str)> = t.content.match_indices(text).collect();
2701 if let HyperlinkSelectMethod::All(url) = method {
2702 for (index, _) in matches {
2703 t.hyperlink_index
2704 .push((index, index + text.len(), url.clone()));
2705 }
2706 } else if let HyperlinkSelectMethod::Segment(list) = method {
2707 for (index, url) in list {
2708 if *index >= matches.len() {
2709 continue;
2710 };
2711 t.hyperlink_index.push((
2712 matches[*index].0,
2713 matches[*index].0 + text.len(),
2714 url.clone(),
2715 ));
2716 }
2717 };
2718 }
2719 };
2720
2721 for (start, end, _) in &t.hyperlink_index {
2723 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2725 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2726
2727 let start_pos = start_cursor.left_top();
2728 let end_pos = end_cursor.right_top();
2729 if start_cursor.min.y == end_cursor.min.y {
2732 let underline_y = position.y
2734 + start_pos.y
2735 + galley.rows.first().map_or(14.0, |row| row.height())
2736 - 2.0;
2737
2738 let color = Color32::from_rgba_unmultiplied(
2740 t.color[0], t.color[1], t.color[2], t.color[3],
2741 );
2742
2743 ui.painter().line_segment(
2744 [
2745 Pos2::new(position.x + start_pos.x, underline_y),
2746 Pos2::new(position.x + end_pos.x, underline_y),
2747 ],
2748 Stroke::new(t.font_size / 10_f32, color),
2749 );
2750 } else {
2751 let row_height = galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2756 let end_row = (end_pos.y / row_height).round() as usize;
2757
2758 for row in start_row..=end_row {
2759 let row_y = position.y + row as f32 * row_height + row_height - 2.0; if let Some(current_row) = galley.rows.get(row) {
2763 let row_rect = current_row.rect();
2764
2765 let color = Color32::from_rgba_unmultiplied(
2766 t.color[0], t.color[1], t.color[2], t.color[3],
2767 );
2768
2769 if row == start_row {
2770 ui.painter().line_segment(
2772 [
2773 Pos2::new(position.x + start_pos.x, row_y),
2774 Pos2::new(position.x + row_rect.max.x, row_y),
2775 ],
2776 Stroke::new(t.font_size / 10_f32, color),
2777 );
2778 } else if row == end_row {
2779 ui.painter().line_segment(
2781 [
2782 Pos2::new(position.x + row_rect.min.x, row_y),
2783 Pos2::new(position.x + end_pos.x, row_y),
2784 ],
2785 Stroke::new(t.font_size / 10_f32, color),
2786 );
2787 } else {
2788 ui.painter().line_segment(
2790 [
2791 Pos2::new(position.x + row_rect.min.x, row_y),
2792 Pos2::new(position.x + row_rect.max.x, row_y),
2793 ],
2794 Stroke::new(t.font_size / 10_f32, color),
2795 );
2796 };
2797 };
2798 }
2799 };
2800 }
2801
2802 if t.selectable {
2803 let rect = Rect::from_min_size(
2804 [position[0] - 20_f32, position[1] - 5_f32].into(),
2805 [text_size[0] + 40_f32, text_size[1] + 10_f32].into(),
2806 );
2807
2808 let rect2 = Rect::from_min_size(
2809 [0_f32, 0_f32].into(),
2810 [ctx.available_rect().width(), ctx.available_rect().height()].into(),
2811 );
2812
2813 let response = ui.interact(
2815 rect,
2816 Id::new(format!("text_{}_click_and_drag", t.name)),
2817 Sense::click_and_drag(),
2818 );
2819
2820 let response2 = ui.interact(
2821 rect2,
2822 Id::new(format!("text_{}_total", t.name)),
2823 Sense::click(),
2824 );
2825
2826 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2828 let relative_pos = pointer_pos - position.to_vec2();
2829 let cursor = galley.cursor_from_pos(relative_pos);
2830 cursor.index
2831 };
2832
2833 if !response.clicked() && response2.clicked() {
2834 t.selection = None;
2835 };
2836
2837 if response.clicked() || response.drag_started() {
2838 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
2839 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
2840 t.selection = Some((cursor, cursor));
2841 };
2842 response.request_focus();
2843 };
2844
2845 if response.dragged()
2846 && t.selection.is_some()
2847 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
2848 {
2849 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
2850 if let Some((start, _)) = t.selection {
2851 t.selection = Some((start, cursor));
2852 };
2853 };
2854
2855 if response.has_focus() {
2857 let copy_triggered = ui.input(|input| {
2859 let c_released = input.key_released(Key::C);
2860 let cmd_pressed = input.modifiers.command || input.modifiers.mac_cmd;
2861 let ctrl_pressed = input.modifiers.ctrl;
2862 c_released && (cmd_pressed || ctrl_pressed)
2863 });
2864 if copy_triggered && let Some((start, end)) = t.selection {
2865 let (start, end) = (start.min(end), start.max(end));
2866 let chars: Vec<char> = t.content.chars().collect();
2867 if start <= chars.len() && end <= chars.len() && start < end {
2868 let selected_text: String = chars[start..end].iter().collect();
2869 ui.ctx().copy_text(selected_text);
2870 };
2871 };
2872 };
2873
2874 if let Some((start, end)) = t.selection {
2876 let (start, end) = (start.min(end), start.max(end));
2877 if start != end {
2878 let start_cursor = galley.pos_from_cursor(CCursor::new(start));
2880 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
2881
2882 let start_pos = start_cursor.left_top();
2883 let end_pos = end_cursor.right_top();
2884 if start_pos.y == end_pos.y {
2886 let rows = &galley.rows;
2889 let row_height = if !rows.is_empty() {
2890 if let Some(row) = rows.first() {
2892 row.height()
2893 } else {
2894 text_size.y / t.content.lines().count() as f32
2895 }
2896 } else {
2897 text_size.y / t.content.lines().count() as f32
2898 };
2899
2900 let selection_rect = Rect::from_min_max(
2901 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
2902 Pos2::new(
2903 position.x + end_pos.x,
2904 position.y + start_pos.y + row_height,
2905 ),
2906 );
2907 ui.painter().rect_filled(
2908 selection_rect,
2909 0.0,
2910 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2911 );
2912 } else {
2913 let rows = &galley.rows;
2915 let row_height = if !rows.is_empty() {
2916 rows[0].height()
2917 } else {
2918 text_size.y / t.content.lines().count() as f32
2919 };
2920
2921 let selection_top = position.y + start_pos.y.min(end_pos.y);
2923 let selection_bottom = position.y + start_pos.y.max(end_pos.y);
2924
2925 let start_row_index = (start_pos.y / row_height).floor() as usize;
2927 let end_row_index = (end_pos.y / row_height).floor() as usize;
2928 let (first_row_index, last_row_index) =
2929 if start_row_index <= end_row_index {
2930 (start_row_index, end_row_index)
2931 } else {
2932 (end_row_index, start_row_index)
2933 };
2934
2935 for (i, row) in rows.iter().enumerate() {
2936 let row_y = position.y + row_height * i as f32;
2937 let row_bottom = row_y + row_height;
2938 if row_bottom > selection_top && row_y <= selection_bottom {
2940 let left = if i == first_row_index {
2941 position.x + start_pos.x
2943 } else {
2944 position.x + row.rect().min.x
2946 };
2947
2948 let right = if i == last_row_index {
2949 position.x + end_pos.x
2951 } else {
2952 position.x + row.rect().max.x
2954 };
2955
2956 let selection_rect = Rect::from_min_max(
2957 Pos2::new(left, row_y),
2958 Pos2::new(right, row_bottom),
2959 );
2960
2961 if selection_rect.width() > 0.0 && selection_rect.height() > 0.0
2963 {
2964 ui.painter().rect_filled(
2965 selection_rect,
2966 0.0,
2967 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2968 );
2969 };
2970 };
2971 }
2972 };
2973 };
2974 };
2975 };
2976
2977 for (start, end, url) in &t.hyperlink_index {
2979 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2981 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2982
2983 let start_pos = start_cursor.left_top();
2984 let end_pos = end_cursor.right_top();
2985
2986 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
2987
2988 let link_responses = if start_cursor.min.y == end_cursor.min.y {
2990 let link_rect = Rect::from_min_max(
2992 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
2993 Pos2::new(
2994 position.x + end_pos.x,
2995 position.y + start_pos.y + row_height,
2996 ),
2997 );
2998 vec![ui.interact(
2999 link_rect,
3000 egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
3001 egui::Sense::click(),
3002 )]
3003 } else {
3004 let start_row = (start_pos.y / row_height).round() as usize;
3006 let end_row = (end_pos.y / row_height).round() as usize;
3007 let mut responses = Vec::new();
3008
3009 for row in start_row..=end_row {
3010 if let Some(current_row) = galley.rows.get(row) {
3011 let row_rect = current_row.rect();
3012 let row_y = position.y + row as f32 * row_height;
3013
3014 let link_rect = if row == start_row {
3015 Rect::from_min_max(
3017 Pos2::new(position.x + start_pos.x, row_y),
3018 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3019 )
3020 } else if row == end_row {
3021 Rect::from_min_max(
3023 Pos2::new(position.x + row_rect.min.x, row_y),
3024 Pos2::new(position.x + end_pos.x, row_y + row_height),
3025 )
3026 } else {
3027 Rect::from_min_max(
3029 Pos2::new(position.x + row_rect.min.x, row_y),
3030 Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3031 )
3032 };
3033
3034 responses.push(ui.interact(
3035 link_rect,
3036 Id::new(format!("link_{}_{}_{}_row_{}", t.name, start, end, row)),
3037 Sense::click(),
3038 ));
3039 };
3040 }
3041 responses
3042 };
3043
3044 let mut is_pressing_link = false;
3046 for link_response in &link_responses {
3047 if link_response.is_pointer_button_down_on() && !link_response.drag_started() {
3048 t.selection = None;
3049 if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
3050 let relative_pos = pointer_pos - position.to_vec2();
3051 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3052 if cursor.index >= *start && cursor.index <= *end {
3053 is_pressing_link = true;
3054 break;
3055 };
3056 };
3057 };
3058 }
3059
3060 let mut clicked_on_link = false;
3062 for link_response in &link_responses {
3063 if link_response.clicked()
3064 && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3065 {
3066 let relative_pos = pointer_pos - position.to_vec2();
3067 let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3068 if cursor.index >= *start && cursor.index <= *end {
3069 clicked_on_link = true;
3070 break;
3071 };
3072 };
3073 }
3074
3075 if clicked_on_link {
3076 if !url.is_empty() {
3078 ui.ctx().open_url(OpenUrl::new_tab(url));
3079 };
3080 };
3081
3082 if is_pressing_link {
3084 if start_cursor.min.y == end_cursor.min.y {
3085 let selection_rect = Rect::from_min_max(
3087 Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3088 Pos2::new(
3089 position.x + end_pos.x,
3090 position.y
3091 + start_pos.y
3092 + galley.rows.first().map_or(14.0, |row| row.height()),
3093 ),
3094 );
3095 ui.painter().rect_filled(
3096 selection_rect,
3097 0.0,
3098 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3099 );
3100 } else {
3101 let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3103 let start_row = (start_pos.y / row_height).round() as usize;
3104 let end_row = (end_pos.y / row_height).round() as usize;
3105
3106 for row in start_row..=end_row {
3107 if let Some(current_row) = galley.rows.get(row) {
3108 let row_rect = current_row.rect();
3109
3110 if row == start_row {
3111 let selection_rect = Rect::from_min_max(
3113 Pos2::new(
3114 position.x + start_pos.x,
3115 position.y + row as f32 * row_height,
3116 ),
3117 Pos2::new(
3118 position.x + row_rect.max.x,
3119 position.y + row as f32 * row_height + row_height,
3120 ),
3121 );
3122 ui.painter().rect_filled(
3123 selection_rect,
3124 0.0,
3125 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3126 );
3127 } else if row == end_row {
3128 let selection_rect = Rect::from_min_max(
3130 Pos2::new(
3131 position.x + row_rect.min.x,
3132 position.y + row as f32 * row_height,
3133 ),
3134 Pos2::new(
3135 position.x + end_pos.x,
3136 position.y + row as f32 * row_height + row_height,
3137 ),
3138 );
3139 ui.painter().rect_filled(
3140 selection_rect,
3141 0.0,
3142 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3143 );
3144 } else {
3145 let selection_rect = Rect::from_min_max(
3147 Pos2::new(
3148 position.x + row_rect.min.x,
3149 position.y + row as f32 * row_height,
3150 ),
3151 Pos2::new(
3152 position.x + row_rect.max.x,
3153 position.y + row as f32 * row_height + row_height,
3154 ),
3155 );
3156 ui.painter().rect_filled(
3157 selection_rect,
3158 0.0,
3159 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3160 );
3161 };
3162 };
3163 }
3164 };
3165 };
3166 }
3167 t.last_frame_content = t.content.clone();
3168 self.replace_resource(name, "Text", t).unwrap();
3169 Ok(())
3170 } else {
3171 self.problem_report_custom(
3172 RustConstructorError::TextNotFound {
3173 text_name: name.to_string(),
3174 },
3175 SeverityLevel::SevereWarning,
3176 self.problem_list.clone(),
3177 );
3178 Err(RustConstructorError::TextNotFound {
3179 text_name: name.to_string(),
3180 })
3181 }
3182 }
3183
3184 pub fn get_text_size(&self, name: &str, ui: &mut Ui) -> Result<[f32; 2], RustConstructorError> {
3186 if self.check_resource_exists(name, "Text") {
3187 let t = self.get_resource::<Text>(name, "Text").unwrap();
3188 let galley = ui.fonts_mut(|f| {
3189 f.layout(
3190 t.content.to_string(),
3191 FontId::proportional(t.font_size),
3192 Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]),
3193 t.wrap_width,
3194 )
3195 });
3196 Ok([galley.size().x, galley.size().y])
3197 } else {
3198 self.problem_report_custom(
3199 RustConstructorError::TextNotFound {
3200 text_name: name.to_string(),
3201 },
3202 SeverityLevel::SevereWarning,
3203 self.problem_list.clone(),
3204 );
3205 Err(RustConstructorError::TextNotFound {
3206 text_name: name.to_string(),
3207 })
3208 }
3209 }
3210
3211 pub fn add_var(&mut self, variable: Variable) {
3213 self.rust_constructor_resource.push(Box::new(variable));
3214 }
3215
3216 pub fn modify_var<T: Into<Value>>(
3218 &mut self,
3219 name: &str,
3220 value: T,
3221 ) -> Result<(), RustConstructorError> {
3222 if self.check_resource_exists(name, "Variable") {
3223 let v = self.get_resource_mut::<Variable>(name, "Variable").unwrap();
3224 v.value = value.into();
3225 Ok(())
3226 } else {
3227 self.problem_report_custom(
3228 RustConstructorError::VariableNotFound {
3229 variable_name: name.to_string(),
3230 },
3231 SeverityLevel::SevereWarning,
3232 self.problem_list.clone(),
3233 );
3234 Err(RustConstructorError::VariableNotFound {
3235 variable_name: name.to_string(),
3236 })
3237 }
3238 }
3239
3240 pub fn var(&self, name: &str) -> Result<Value, RustConstructorError> {
3242 if self.check_resource_exists(name, "Variable") {
3243 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3244 Ok(v.value.clone())
3245 } else {
3246 self.problem_report_custom(
3247 RustConstructorError::VariableNotFound {
3248 variable_name: name.to_string(),
3249 },
3250 SeverityLevel::SevereWarning,
3251 self.problem_list.clone(),
3252 );
3253 Err(RustConstructorError::VariableNotFound {
3254 variable_name: name.to_string(),
3255 })
3256 }
3257 }
3258
3259 pub fn var_i(&self, name: &str) -> Result<i32, RustConstructorError> {
3261 if self.check_resource_exists(name, "Variable") {
3262 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3263 match &v.value {
3264 Value::Int(i) => Ok(*i),
3266 _ => {
3267 self.problem_report_custom(
3268 RustConstructorError::VariableNotInt {
3269 variable_name: name.to_string(),
3270 },
3271 SeverityLevel::SevereWarning,
3272 self.problem_list.clone(),
3273 );
3274 Err(RustConstructorError::VariableNotInt {
3275 variable_name: name.to_string(),
3276 })
3277 }
3278 }
3279 } else {
3280 self.problem_report_custom(
3281 RustConstructorError::VariableNotFound {
3282 variable_name: name.to_string(),
3283 },
3284 SeverityLevel::SevereWarning,
3285 self.problem_list.clone(),
3286 );
3287 Err(RustConstructorError::VariableNotFound {
3288 variable_name: name.to_string(),
3289 })
3290 }
3291 }
3292
3293 pub fn var_u(&self, name: &str) -> Result<u32, RustConstructorError> {
3295 if self.check_resource_exists(name, "Variable") {
3296 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3297 match &v.value {
3298 Value::UInt(u) => Ok(*u),
3300 _ => {
3301 self.problem_report_custom(
3302 RustConstructorError::VariableNotUInt {
3303 variable_name: name.to_string(),
3304 },
3305 SeverityLevel::SevereWarning,
3306 self.problem_list.clone(),
3307 );
3308 Err(RustConstructorError::VariableNotUInt {
3309 variable_name: name.to_string(),
3310 })
3311 }
3312 }
3313 } else {
3314 self.problem_report_custom(
3315 RustConstructorError::VariableNotFound {
3316 variable_name: name.to_string(),
3317 },
3318 SeverityLevel::SevereWarning,
3319 self.problem_list.clone(),
3320 );
3321 Err(RustConstructorError::VariableNotFound {
3322 variable_name: name.to_string(),
3323 })
3324 }
3325 }
3326
3327 pub fn var_f(&self, name: &str) -> Result<f32, RustConstructorError> {
3329 if self.check_resource_exists(name, "Variable") {
3330 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3331 match &v.value {
3332 Value::Float(f) => Ok(*f),
3334 _ => {
3335 self.problem_report_custom(
3336 RustConstructorError::VariableNotFloat {
3337 variable_name: name.to_string(),
3338 },
3339 SeverityLevel::SevereWarning,
3340 self.problem_list.clone(),
3341 );
3342 Err(RustConstructorError::VariableNotFloat {
3343 variable_name: name.to_string(),
3344 })
3345 }
3346 }
3347 } else {
3348 self.problem_report_custom(
3349 RustConstructorError::VariableNotFound {
3350 variable_name: name.to_string(),
3351 },
3352 SeverityLevel::SevereWarning,
3353 self.problem_list.clone(),
3354 );
3355 Err(RustConstructorError::VariableNotFound {
3356 variable_name: name.to_string(),
3357 })
3358 }
3359 }
3360
3361 pub fn var_b(&self, name: &str) -> Result<bool, RustConstructorError> {
3363 if self.check_resource_exists(name, "Variable") {
3364 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3365 match &v.value {
3366 Value::Bool(b) => Ok(*b),
3368 _ => {
3369 self.problem_report_custom(
3370 RustConstructorError::VariableNotBool {
3371 variable_name: name.to_string(),
3372 },
3373 SeverityLevel::SevereWarning,
3374 self.problem_list.clone(),
3375 );
3376 Err(RustConstructorError::VariableNotBool {
3377 variable_name: name.to_string(),
3378 })
3379 }
3380 }
3381 } else {
3382 self.problem_report_custom(
3383 RustConstructorError::VariableNotFound {
3384 variable_name: name.to_string(),
3385 },
3386 SeverityLevel::SevereWarning,
3387 self.problem_list.clone(),
3388 );
3389 Err(RustConstructorError::VariableNotFound {
3390 variable_name: name.to_string(),
3391 })
3392 }
3393 }
3394
3395 pub fn var_v(&self, name: &str) -> Result<Vec<Value>, RustConstructorError> {
3397 if self.check_resource_exists(name, "Variable") {
3398 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3399 match &v.value {
3400 Value::Vec(v) => Ok(v.clone()),
3402 _ => {
3403 self.problem_report_custom(
3404 RustConstructorError::VariableNotVec {
3405 variable_name: name.to_string(),
3406 },
3407 SeverityLevel::SevereWarning,
3408 self.problem_list.clone(),
3409 );
3410 Err(RustConstructorError::VariableNotVec {
3411 variable_name: name.to_string(),
3412 })
3413 }
3414 }
3415 } else {
3416 self.problem_report_custom(
3417 RustConstructorError::VariableNotFound {
3418 variable_name: name.to_string(),
3419 },
3420 SeverityLevel::SevereWarning,
3421 self.problem_list.clone(),
3422 );
3423 Err(RustConstructorError::VariableNotFound {
3424 variable_name: name.to_string(),
3425 })
3426 }
3427 }
3428
3429 pub fn var_s(&self, name: &str) -> Result<String, RustConstructorError> {
3431 if self.check_resource_exists(name, "Variable") {
3432 let v = self.get_resource::<Variable>(name, "Variable").unwrap();
3433 match &v.value {
3434 Value::String(s) => Ok(s.clone()),
3436 _ => {
3437 self.problem_report_custom(
3438 RustConstructorError::VariableNotString {
3439 variable_name: name.to_string(),
3440 },
3441 SeverityLevel::SevereWarning,
3442 self.problem_list.clone(),
3443 );
3444 Err(RustConstructorError::VariableNotString {
3445 variable_name: name.to_string(),
3446 })
3447 }
3448 }
3449 } else {
3450 self.problem_report_custom(
3451 RustConstructorError::VariableNotFound {
3452 variable_name: name.to_string(),
3453 },
3454 SeverityLevel::SevereWarning,
3455 self.problem_list.clone(),
3456 );
3457 Err(RustConstructorError::VariableNotFound {
3458 variable_name: name.to_string(),
3459 })
3460 }
3461 }
3462
3463 pub fn var_decode_b(&self, target: Value) -> Result<bool, RustConstructorError> {
3465 match target {
3466 Value::Bool(b) => {
3467 Ok(b)
3469 }
3470 _ => {
3471 self.problem_report_custom(
3472 RustConstructorError::VariableNotBool {
3473 variable_name: format!("{:?}", target),
3474 },
3475 SeverityLevel::SevereWarning,
3476 self.problem_list.clone(),
3477 );
3478 Err(RustConstructorError::VariableNotBool {
3479 variable_name: format!("{:?}", target),
3480 })
3481 }
3482 }
3483 }
3484
3485 pub fn var_decode_i(&self, target: Value) -> Result<i32, RustConstructorError> {
3487 match target {
3488 Value::Int(i) => {
3489 Ok(i)
3491 }
3492 _ => {
3493 self.problem_report_custom(
3494 RustConstructorError::VariableNotInt {
3495 variable_name: format!("{:?}", target),
3496 },
3497 SeverityLevel::SevereWarning,
3498 self.problem_list.clone(),
3499 );
3500 Err(RustConstructorError::VariableNotInt {
3501 variable_name: format!("{:?}", target),
3502 })
3503 }
3504 }
3505 }
3506
3507 pub fn var_decode_u(&self, target: Value) -> Result<u32, RustConstructorError> {
3509 match target {
3510 Value::UInt(u) => {
3511 Ok(u)
3513 }
3514 _ => {
3515 self.problem_report_custom(
3516 RustConstructorError::VariableNotUInt {
3517 variable_name: format!("{:?}", target),
3518 },
3519 SeverityLevel::SevereWarning,
3520 self.problem_list.clone(),
3521 );
3522 Err(RustConstructorError::VariableNotUInt {
3523 variable_name: format!("{:?}", target),
3524 })
3525 }
3526 }
3527 }
3528
3529 pub fn var_decode_f(&self, target: Value) -> Result<f32, RustConstructorError> {
3531 match target {
3532 Value::Float(f) => {
3533 Ok(f)
3535 }
3536 _ => {
3537 self.problem_report_custom(
3538 RustConstructorError::VariableNotFloat {
3539 variable_name: format!("{:?}", target),
3540 },
3541 SeverityLevel::SevereWarning,
3542 self.problem_list.clone(),
3543 );
3544 Err(RustConstructorError::VariableNotFloat {
3545 variable_name: format!("{:?}", target),
3546 })
3547 }
3548 }
3549 }
3550
3551 pub fn var_decode_s(&self, target: Value) -> Result<String, RustConstructorError> {
3553 match target {
3554 Value::String(s) => {
3555 Ok(s)
3557 }
3558 _ => {
3559 self.problem_report_custom(
3560 RustConstructorError::VariableNotString {
3561 variable_name: format!("{:?}", target),
3562 },
3563 SeverityLevel::SevereWarning,
3564 self.problem_list.clone(),
3565 );
3566 Err(RustConstructorError::VariableNotString {
3567 variable_name: format!("{:?}", target),
3568 })
3569 }
3570 }
3571 }
3572
3573 pub fn var_decode_v(&self, target: Value) -> Result<Vec<Value>, RustConstructorError> {
3575 match target {
3576 Value::Vec(v) => {
3577 Ok(v)
3579 }
3580 _ => {
3581 self.problem_report_custom(
3582 RustConstructorError::VariableNotVec {
3583 variable_name: format!("{:?}", target),
3584 },
3585 SeverityLevel::SevereWarning,
3586 self.problem_list.clone(),
3587 );
3588 Err(RustConstructorError::VariableNotVec {
3589 variable_name: format!("{:?}", target),
3590 })
3591 }
3592 }
3593 }
3594
3595 pub fn add_image_texture(
3597 &mut self,
3598 mut image_texture: ImageTexture,
3599 path: &str,
3600 flip: [bool; 2],
3601 ctx: &Context,
3602 ) {
3603 if let Ok(mut file) = File::open(path) {
3604 let mut buffer = Vec::new();
3605 file.read_to_end(&mut buffer).unwrap();
3606 let img_bytes = buffer;
3607 let img = image::load_from_memory(&img_bytes).unwrap();
3608 let color_data = match flip {
3609 [true, true] => img.fliph().flipv().into_rgba8(),
3610 [true, false] => img.fliph().into_rgba8(),
3611 [false, true] => img.flipv().into_rgba8(),
3612 _ => img.into_rgba8(),
3613 };
3614 let (w, h) = (color_data.width(), color_data.height());
3615 let raw_data: Vec<u8> = color_data.into_raw();
3616
3617 let color_image =
3618 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3619 let loaded_image_texture = ctx.load_texture(
3620 image_texture.name.clone(),
3621 color_image,
3622 TextureOptions::LINEAR,
3623 );
3624 image_texture.texture = Some(DebugTextureHandle::new(loaded_image_texture));
3625 image_texture.cite_path = path.to_string();
3626 self.rust_constructor_resource.push(Box::new(image_texture));
3627 } else {
3628 self.problem_report_custom(
3629 RustConstructorError::ImageGetFailed {
3630 image_path: path.to_string(),
3631 },
3632 SeverityLevel::SevereWarning,
3633 self.problem_list.clone(),
3634 );
3635 };
3636 }
3637
3638 pub fn image_texture(
3640 &self,
3641 name: &str,
3642 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3643 if self.check_resource_exists(name, "ImageTexture") {
3644 let it = self
3645 .get_resource::<ImageTexture>(name, "ImageTexture")
3646 .unwrap();
3647 Ok(it.texture.clone())
3648 } else {
3649 self.problem_report_custom(
3650 RustConstructorError::ImageNotFound {
3651 image_name: name.to_string(),
3652 },
3653 SeverityLevel::SevereWarning,
3654 self.problem_list.clone(),
3655 );
3656 Err(RustConstructorError::ImageNotFound {
3657 image_name: name.to_string(),
3658 })
3659 }
3660 }
3661
3662 pub fn reset_image_texture(
3664 &mut self,
3665 name: &str,
3666 path: &str,
3667 flip: [bool; 2],
3668 ctx: &Context,
3669 ) -> Result<(), RustConstructorError> {
3670 if self.check_resource_exists(name, "ImageTexture") {
3671 let it = self
3672 .get_resource_mut::<ImageTexture>(name, "ImageTexture")
3673 .unwrap();
3674 if let Ok(mut file) = File::open(path) {
3675 let mut buffer = Vec::new();
3676 file.read_to_end(&mut buffer).unwrap();
3677 let img_bytes = buffer;
3678 let img = image::load_from_memory(&img_bytes).unwrap();
3679 let color_data = match flip {
3680 [true, true] => img.fliph().flipv().into_rgba8(),
3681 [true, false] => img.fliph().into_rgba8(),
3682 [false, true] => img.flipv().into_rgba8(),
3683 _ => img.into_rgba8(),
3684 };
3685 let (w, h) = (color_data.width(), color_data.height());
3686 let raw_data: Vec<u8> = color_data.into_raw();
3687
3688 let color_image =
3689 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3690 let image_texture =
3691 ctx.load_texture(it.name.clone(), color_image, TextureOptions::LINEAR);
3692 it.texture = Some(DebugTextureHandle::new(image_texture));
3693 it.cite_path = path.to_string();
3694 } else {
3695 self.problem_report_custom(
3696 RustConstructorError::ImageGetFailed {
3697 image_path: path.to_string(),
3698 },
3699 SeverityLevel::SevereWarning,
3700 self.problem_list.clone(),
3701 );
3702 };
3703 Ok(())
3704 } else {
3705 self.problem_report_custom(
3706 RustConstructorError::ImageTextureNotFound {
3707 image_texture_name: name.to_string(),
3708 },
3709 SeverityLevel::SevereWarning,
3710 self.problem_list.clone(),
3711 );
3712 Err(RustConstructorError::ImageTextureNotFound {
3713 image_texture_name: name.to_string(),
3714 })
3715 }
3716 }
3717
3718 pub fn add_image(
3720 &mut self,
3721 mut image: Image,
3722 image_texture_name: &str,
3723 ) -> Result<(), RustConstructorError> {
3724 if self.check_resource_exists(image_texture_name, "ImageTexture") {
3725 let it = self
3726 .get_resource::<ImageTexture>(image_texture_name, "ImageTexture")
3727 .unwrap();
3728 image.texture = it.texture.clone();
3729 image.cite_texture = it.name.clone();
3730 image.last_frame_cite_texture = it.name.clone();
3731 self.rust_constructor_resource.push(Box::new(image));
3732 Ok(())
3733 } else {
3734 self.problem_report_custom(
3735 RustConstructorError::ImageTextureNotFound {
3736 image_texture_name: image_texture_name.to_string(),
3737 },
3738 SeverityLevel::SevereWarning,
3739 self.problem_list.clone(),
3740 );
3741 Err(RustConstructorError::ImageTextureNotFound {
3742 image_texture_name: image_texture_name.to_string(),
3743 })
3744 }
3745 }
3746
3747 pub fn image(
3749 &mut self,
3750 name: &str,
3751 ui: &mut Ui,
3752 ctx: &Context,
3753 ) -> Result<(), RustConstructorError> {
3754 if self.check_resource_exists(name, "Image") {
3755 let mut im = self
3756 .get_resource_mut::<Image>(name, "Image")
3757 .unwrap()
3758 .clone();
3759 if im.cite_texture != im.last_frame_cite_texture {
3760 if self.check_resource_exists(&im.cite_texture, "ImageTexture") {
3761 let it = self
3762 .get_resource::<ImageTexture>(&im.cite_texture, "ImageTexture")
3763 .unwrap();
3764 im.texture = it.texture.clone();
3765 } else {
3766 self.problem_report_custom(
3767 RustConstructorError::ImageTextureNotFound {
3768 image_texture_name: im.cite_texture.clone(),
3769 },
3770 SeverityLevel::MildWarning,
3771 self.problem_list.clone(),
3772 );
3773 };
3774 };
3775 im.reg_render_resource(&mut self.render_resource_list);
3776 im.position[0] = match im.x_grid[1] {
3777 0 => im.origin_position[0],
3778 _ => {
3779 (ctx.available_rect().width() as f64 / im.x_grid[1] as f64
3780 * im.x_grid[0] as f64) as f32
3781 + im.origin_position[0]
3782 }
3783 };
3784 im.position[1] = match im.y_grid[1] {
3785 0 => im.origin_position[1],
3786 _ => {
3787 (ctx.available_rect().height() as f64 / im.y_grid[1] as f64
3788 * im.y_grid[0] as f64) as f32
3789 + im.origin_position[1]
3790 }
3791 };
3792 match im.center_display.0 {
3793 HorizontalAlign::Left => {}
3794 HorizontalAlign::Center => im.position[0] -= im.size[0] / 2.0,
3795 HorizontalAlign::Right => im.position[0] -= im.size[0],
3796 };
3797 match im.center_display.1 {
3798 VerticalAlign::Top => {}
3799 VerticalAlign::Center => im.position[1] -= im.size[1] / 2.0,
3800 VerticalAlign::Bottom => im.position[1] -= im.size[1],
3801 };
3802 if let Some(texture) = &im.texture {
3803 let rect = Rect::from_min_size(
3804 Pos2::new(im.position[0], im.position[1]),
3805 Vec2::new(im.size[0], im.size[1]),
3806 );
3807
3808 egui::Image::new(ImageSource::Texture((&texture.0).into()))
3810 .tint(Color32::from_rgba_unmultiplied(
3811 im.overlay_color[0],
3812 im.overlay_color[1],
3813 im.overlay_color[2],
3814 (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
3816 ))
3817 .bg_fill(Color32::from_rgba_unmultiplied(
3818 im.background_color[0],
3819 im.background_color[1],
3820 im.background_color[2],
3821 im.background_color[3],
3822 ))
3823 .rotate(
3824 im.rotate_angle,
3825 [
3826 im.rotate_center[0] / im.size[0],
3827 im.rotate_center[1] / im.size[1],
3828 ]
3829 .into(),
3830 )
3831 .paint_at(ui, rect)
3832 };
3833 im.last_frame_cite_texture = im.cite_texture.clone();
3834 self.replace_resource(name, "Image", im).unwrap();
3835 Ok(())
3836 } else {
3837 self.problem_report_custom(
3838 RustConstructorError::ImageNotFound {
3839 image_name: name.to_string(),
3840 },
3841 SeverityLevel::SevereWarning,
3842 self.problem_list.clone(),
3843 );
3844 Err(RustConstructorError::ImageNotFound {
3845 image_name: name.to_string(),
3846 })
3847 }
3848 }
3849
3850 pub fn add_message_box(
3852 &mut self,
3853 mut message_box: MessageBox,
3854 title_name: &str,
3855 content_name: &str,
3856 image_name: &str,
3857 close_switch_fill_resource_name: &str,
3858 close_switch_fill_resource_type: &str,
3859 ) -> Result<(), RustConstructorError> {
3860 if !self.check_resource_exists(&message_box.name, "MessageBox") {
3861 message_box.exist = true;
3862 message_box.memory_offset = 0_f32;
3863
3864 if self.check_resource_exists(image_name, "Image") {
3865 let im = self.get_resource_mut::<Image>(image_name, "Image").unwrap();
3866 im.size = [message_box.size[1] - 15_f32, message_box.size[1] - 15_f32];
3867 im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
3868 im.x_grid = [1, 1];
3869 im.y_grid = [0, 1];
3870 im.name = format!("MessageBox{}", im.name);
3871 message_box.image_name = im.name.to_string();
3872 } else {
3873 self.problem_report_custom(
3874 RustConstructorError::ImageNotFound {
3875 image_name: image_name.to_string(),
3876 },
3877 SeverityLevel::SevereWarning,
3878 self.problem_list.clone(),
3879 );
3880 return Err(RustConstructorError::ImageNotFound {
3881 image_name: image_name.to_string(),
3882 });
3883 }
3884
3885 if self.check_resource_exists(title_name, "Text") {
3886 let t = self.get_resource_mut::<Text>(title_name, "Text").unwrap();
3887 t.x_grid = [1, 1];
3888 t.y_grid = [0, 1];
3889 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3890 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
3891 t.name = format!("MessageBox{}", t.name);
3892 message_box.title_name = t.name.to_string();
3893 } else {
3894 self.problem_report_custom(
3895 RustConstructorError::TextNotFound {
3896 text_name: title_name.to_string(),
3897 },
3898 SeverityLevel::SevereWarning,
3899 self.problem_list.clone(),
3900 );
3901 return Err(RustConstructorError::TextNotFound {
3902 text_name: title_name.to_string(),
3903 });
3904 }
3905
3906 if self.check_resource_exists(content_name, "Text") {
3907 let t = self.get_resource_mut::<Text>(content_name, "Text").unwrap();
3908 t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3909 t.x_grid = [1, 1];
3910 t.y_grid = [0, 1];
3911 t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
3912 t.name = format!("MessageBox{}", t.name);
3913 message_box.content_name = t.name.to_string();
3914 } else {
3915 self.problem_report_custom(
3916 RustConstructorError::TextNotFound {
3917 text_name: content_name.to_string(),
3918 },
3919 SeverityLevel::SevereWarning,
3920 self.problem_list.clone(),
3921 );
3922 return Err(RustConstructorError::TextNotFound {
3923 text_name: content_name.to_string(),
3924 });
3925 }
3926
3927 if !message_box.keep_existing {
3928 self.add_split_time(
3929 SplitTime::default().name(&format!("MessageBox{}", message_box.name)),
3930 );
3931 };
3932
3933 self.add_split_time(
3934 SplitTime::default().name(&format!("MessageBox{}Animation", message_box.name)),
3935 );
3936
3937 self.add_custom_rect(
3938 CustomRect::default()
3939 .name(&format!("MessageBox{}", message_box.name))
3940 .origin_position(0_f32, 0_f32)
3941 .size(message_box.size[0], message_box.size[1])
3942 .rounding(20_f32)
3943 .x_grid(1, 1)
3944 .y_grid(0, 1)
3945 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
3946 .color(100, 100, 100, 125)
3947 .border_width(0_f32),
3948 );
3949
3950 match close_switch_fill_resource_type {
3951 "Image" | "CustomRect" => {}
3952 &_ => {
3953 self.problem_report_custom(
3954 RustConstructorError::SwitchFillResourceMismatch {
3955 switch_name: format!("MessageBox{}Close", message_box.name),
3956 fill_resource_name: close_switch_fill_resource_name.to_string(),
3957 fill_resource_type: close_switch_fill_resource_type.to_string(),
3958 },
3959 SeverityLevel::SevereWarning,
3960 self.problem_list.clone(),
3961 );
3962 return Err(RustConstructorError::SwitchFillResourceMismatch {
3963 switch_name: format!("MessageBox{}Close", message_box.name),
3964 fill_resource_name: close_switch_fill_resource_name.to_string(),
3965 fill_resource_type: close_switch_fill_resource_type.to_string(),
3966 });
3967 }
3968 };
3969
3970 if !self.check_resource_exists(
3971 close_switch_fill_resource_name,
3972 close_switch_fill_resource_type,
3973 ) {
3974 self.problem_report_custom(
3975 RustConstructorError::ResourceNotFound {
3976 resource_name: close_switch_fill_resource_name.to_string(),
3977 resource_type: close_switch_fill_resource_type.to_string(),
3978 },
3979 SeverityLevel::SevereWarning,
3980 self.problem_list.clone(),
3981 );
3982 return Err(RustConstructorError::ResourceNotFound {
3983 resource_name: close_switch_fill_resource_name.to_string(),
3984 resource_type: close_switch_fill_resource_type.to_string(),
3985 });
3986 };
3987
3988 let (texture, image_config, custom_rect_config, color, border_color) =
3989 match close_switch_fill_resource_type {
3990 "Image" => {
3991 let im = self
3992 .get_resource_mut::<Image>(close_switch_fill_resource_name, "Image")
3993 .unwrap();
3994 im.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
3995 (
3996 im.cite_texture.clone(),
3997 ImageConfig::from_image(im.clone())
3998 .size(30_f32, 30_f32)
3999 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4000 CustomRectConfig::default(),
4001 im.overlay_color,
4002 [0, 0, 0, 0],
4003 )
4004 }
4005 "CustomRect" => {
4006 let cr = self
4007 .get_resource_mut::<CustomRect>(
4008 close_switch_fill_resource_name,
4009 "CustomRect",
4010 )
4011 .unwrap();
4012 cr.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4013 (
4014 String::new(),
4015 ImageConfig::default(),
4016 CustomRectConfig::from_custom_rect(cr.clone())
4017 .size(30_f32, 30_f32)
4018 .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4019 cr.color,
4020 cr.border_color,
4021 )
4022 }
4023 &_ => {
4024 unreachable!()
4025 }
4026 };
4027
4028 self.add_switch(
4029 Switch::default()
4030 .name(&format!("MessageBox{}Close", message_box.name))
4031 .appearance(vec![
4032 SwitchData {
4033 image_config: image_config
4034 .clone()
4035 .overlay_color(color[0], color[1], color[2], 0),
4036 custom_rect_config: custom_rect_config
4037 .clone()
4038 .color(color[0], color[1], color[2], 0)
4039 .border_color(border_color[0], border_color[1], border_color[2], 0),
4040 text_config: TextConfig::default(),
4041 texture: texture.clone(),
4042 hint_text: String::new(),
4043 },
4044 SwitchData {
4045 image_config: image_config.clone().overlay_color(
4046 (color[0] as u32 * 180 / 255) as u8,
4047 (color[1] as u32 * 180 / 255) as u8,
4048 (color[2] as u32 * 180 / 255) as u8,
4049 255,
4050 ),
4051 custom_rect_config: custom_rect_config
4052 .clone()
4053 .color(
4054 (color[0] as u32 * 180 / 255) as u8,
4055 (color[1] as u32 * 180 / 255) as u8,
4056 (color[2] as u32 * 180 / 255) as u8,
4057 255,
4058 )
4059 .border_color(
4060 (border_color[0] as u32 * 180 / 255) as u8,
4061 (border_color[1] as u32 * 180 / 255) as u8,
4062 (border_color[2] as u32 * 180 / 255) as u8,
4063 255,
4064 ),
4065 text_config: TextConfig::default(),
4066 texture: texture.clone(),
4067 hint_text: String::new(),
4068 },
4069 SwitchData {
4070 image_config: image_config.clone().overlay_color(0, 0, 0, 0),
4071 custom_rect_config: custom_rect_config
4072 .clone()
4073 .color(0, 0, 0, 0)
4074 .border_color(0, 0, 0, 0),
4075 text_config: TextConfig::default(),
4076 texture: texture.clone(),
4077 hint_text: String::new(),
4078 },
4079 SwitchData {
4080 image_config: image_config.overlay_color(0, 0, 0, 0),
4081 custom_rect_config: custom_rect_config
4082 .color(0, 0, 0, 0)
4083 .border_color(0, 0, 0, 0),
4084 text_config: TextConfig::default(),
4085 texture,
4086 hint_text: String::new(),
4087 },
4088 ])
4089 .enable_hover_click_fill_resource(false, true)
4090 .click_method(vec![SwitchClickAction {
4091 click_method: PointerButton::Primary,
4092 action: true,
4093 }]),
4094 &format!("MessageBox{}Close", close_switch_fill_resource_name),
4095 close_switch_fill_resource_type,
4096 "",
4097 )
4098 .unwrap();
4099 self.rust_constructor_resource
4100 .push(Box::new(message_box.clone()));
4101 Ok(())
4102 } else {
4103 self.problem_report_custom(
4104 RustConstructorError::MessageBoxAlreadyExists {
4105 message_box_name: message_box.name.to_string(),
4106 },
4107 SeverityLevel::SevereWarning,
4108 self.problem_list.clone(),
4109 );
4110 Err(RustConstructorError::MessageBoxAlreadyExists {
4111 message_box_name: message_box.name.to_string(),
4112 })
4113 }
4114 }
4115
4116 pub fn message_box_display(&mut self, ctx: &Context, ui: &mut Ui, safe_mode: bool) {
4118 let mut offset = 0_f32;
4119 let mut delete_count = 0;
4120 let mut index_list = Vec::new();
4121 for i in 0..self.rust_constructor_resource.len() {
4122 if self.rust_constructor_resource[i]
4123 .as_any()
4124 .downcast_ref::<MessageBox>()
4125 .is_some()
4126 {
4127 index_list.push(i);
4128 };
4129 }
4130 for u in 0..index_list.len() {
4131 let mut deleted = false;
4132 let i = u - delete_count;
4133 let mut mb = self.rust_constructor_resource[index_list[i]]
4134 .as_any()
4135 .downcast_ref::<MessageBox>()
4136 .unwrap()
4137 .clone();
4138 if safe_mode {
4139 if !self.check_resource_exists(&mb.image_name, "Image") {
4140 self.problem_report_custom(
4141 RustConstructorError::ImageNotFound {
4142 image_name: mb.image_name,
4143 },
4144 SeverityLevel::SevereWarning,
4145 self.problem_list.clone(),
4146 );
4147 continue;
4148 };
4149 if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "CustomRect") {
4150 self.problem_report_custom(
4151 RustConstructorError::RectNotFound {
4152 rect_name: format!("MessageBox{}", mb.name),
4153 },
4154 SeverityLevel::SevereWarning,
4155 self.problem_list.clone(),
4156 );
4157 continue;
4158 };
4159 if !self.check_resource_exists(&mb.title_name, "Text") {
4160 self.problem_report_custom(
4161 RustConstructorError::TextNotFound {
4162 text_name: mb.title_name,
4163 },
4164 SeverityLevel::SevereWarning,
4165 self.problem_list.clone(),
4166 );
4167 continue;
4168 };
4169 if !self.check_resource_exists(&mb.content_name, "Text") {
4170 self.problem_report_custom(
4171 RustConstructorError::TextNotFound {
4172 text_name: mb.content_name,
4173 },
4174 SeverityLevel::SevereWarning,
4175 self.problem_list.clone(),
4176 );
4177 continue;
4178 };
4179 if !self.check_resource_exists(&format!("MessageBox{}Close", mb.name), "Switch") {
4180 self.problem_report_custom(
4181 RustConstructorError::SwitchNotFound {
4182 switch_name: format!("MessageBox{}Close", mb.name),
4183 },
4184 SeverityLevel::SevereWarning,
4185 self.problem_list.clone(),
4186 );
4187 continue;
4188 };
4189 if !self
4190 .check_resource_exists(&format!("MessageBox{}Animation", mb.name), "SplitTime")
4191 {
4192 self.problem_report_custom(
4193 RustConstructorError::SplitTimeNotFound {
4194 split_time_name: format!("MessageBox{}Animation", mb.name),
4195 },
4196 SeverityLevel::SevereWarning,
4197 self.problem_list.clone(),
4198 );
4199 continue;
4200 };
4201 if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "SplitTime") {
4202 self.problem_report_custom(
4203 RustConstructorError::SplitTimeNotFound {
4204 split_time_name: format!("MessageBox{}", mb.name),
4205 },
4206 SeverityLevel::SevereWarning,
4207 self.problem_list.clone(),
4208 );
4209 continue;
4210 };
4211 };
4212 let mut im1 = self
4213 .get_resource::<Image>(&mb.image_name, "Image")
4214 .unwrap()
4215 .clone();
4216 let mut cr = self
4217 .get_resource::<CustomRect>(&format!("MessageBox{}", mb.name), "CustomRect")
4218 .unwrap()
4219 .clone();
4220 let mut t1 = self
4221 .get_resource::<Text>(&mb.title_name, "Text")
4222 .unwrap()
4223 .clone();
4224 let mut t2 = self
4225 .get_resource::<Text>(&mb.content_name, "Text")
4226 .unwrap()
4227 .clone();
4228 let mut s = self
4229 .get_resource::<Switch>(&format!("MessageBox{}Close", mb.name), "Switch")
4230 .unwrap()
4231 .clone();
4232 if safe_mode
4233 && !self.check_resource_exists(&s.fill_resource_name, &s.fill_resource_type)
4234 {
4235 self.problem_report_custom(
4236 RustConstructorError::ResourceNotFound {
4237 resource_name: s.fill_resource_name,
4238 resource_type: s.fill_resource_type,
4239 },
4240 SeverityLevel::SevereWarning,
4241 self.problem_list.clone(),
4242 );
4243 continue;
4244 };
4245 let fr: Box<dyn FrontResource> = match s.fill_resource_type.as_str() {
4246 "Image" => Box::new(
4247 self.get_resource::<Image>(&s.fill_resource_name, "Image")
4248 .unwrap()
4249 .clone(),
4250 ),
4251 "CustomRect" => Box::new(
4252 self.get_resource::<CustomRect>(&s.fill_resource_name, "CustomRect")
4253 .unwrap()
4254 .clone(),
4255 ),
4256 &_ => {
4257 self.problem_report_custom(
4258 RustConstructorError::SwitchFillResourceMismatch {
4259 switch_name: s.name,
4260 fill_resource_name: s.fill_resource_name,
4261 fill_resource_type: s.fill_resource_type,
4262 },
4263 SeverityLevel::SevereWarning,
4264 self.problem_list.clone(),
4265 );
4266 continue;
4267 }
4268 };
4269 mb.reg_render_resource(&mut self.render_resource_list.clone());
4270 if mb.size[1]
4271 < self.get_text_size(&mb.title_name.clone(), ui).unwrap()[1]
4272 + self.get_text_size(&mb.content_name.clone(), ui).unwrap()[1]
4273 + 10_f32
4274 {
4275 mb.size[1] = self.get_text_size(&mb.title_name.clone(), ui).unwrap()[1]
4276 + self.get_text_size(&mb.content_name.clone(), ui).unwrap()[1]
4277 + 10_f32;
4278 cr.size[1] = mb.size[1];
4279 im1.size = [mb.size[1] - 15_f32, mb.size[1] - 15_f32];
4280 t1.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4281 t2.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4282 };
4283 if self.timer.total_time
4284 - self
4285 .split_time(&format!("MessageBox{}Animation", mb.name))
4286 .unwrap()[1]
4287 >= self.tick_interval
4288 {
4289 self.reset_split_time(&format!("MessageBox{}Animation", mb.name))
4290 .unwrap();
4291 if offset != mb.memory_offset {
4292 if mb.memory_offset < offset {
4293 if mb.memory_offset + mb.restore_speed >= offset {
4294 mb.memory_offset = offset;
4295 } else {
4296 mb.memory_offset += mb.restore_speed;
4297 };
4298 } else if mb.memory_offset - mb.restore_speed <= offset {
4299 mb.memory_offset = offset;
4300 } else {
4301 mb.memory_offset -= mb.restore_speed;
4302 };
4303 };
4304 if cr.origin_position[0] != -mb.size[0] - 5_f32 {
4305 if mb.exist {
4306 if cr.origin_position[0] - mb.speed <= -mb.size[0] - 5_f32 {
4307 cr.origin_position[0] = -mb.size[0] - 5_f32;
4308 if self.check_resource_exists(
4309 &format!("MessageBox{}", mb.name),
4310 "SplitTime",
4311 ) {
4312 self.reset_split_time(&format!("MessageBox{}", mb.name))
4313 .unwrap();
4314 };
4315 } else {
4316 cr.origin_position[0] -= mb.speed;
4317 };
4318 } else if cr.origin_position[0] + mb.speed >= 15_f32 {
4319 cr.origin_position[0] = 15_f32;
4320 delete_count += 1;
4321 deleted = true;
4322 } else {
4323 cr.origin_position[0] += mb.speed;
4324 };
4325 };
4326 };
4327 cr.origin_position[1] = mb.memory_offset + 20_f32;
4328 im1.origin_position = [
4329 cr.origin_position[0] + 5_f32,
4330 cr.origin_position[1] + mb.size[1] / 2_f32,
4331 ];
4332 t1.origin_position = [
4333 im1.origin_position[0] + im1.size[0] + 5_f32,
4334 cr.origin_position[1] + 5_f32,
4335 ];
4336 t2.origin_position = [
4337 im1.origin_position[0] + im1.size[0] + 5_f32,
4338 t1.origin_position[1] + self.get_text_size(&mb.title_name.clone(), ui).unwrap()[1],
4339 ];
4340 for sd in &mut s.appearance {
4341 sd.image_config.origin_position = cr.position;
4342 sd.custom_rect_config.origin_position = cr.position;
4343 }
4344 if !mb.keep_existing
4345 && self.timer.total_time
4346 - self.split_time(&format!("MessageBox{}", mb.name)).unwrap()[1]
4347 >= mb.existing_time
4348 && cr.origin_position[0] == -mb.size[0] - 5_f32
4349 {
4350 mb.exist = false;
4351 if cr.origin_position[0] + mb.speed >= 15_f32 {
4352 cr.origin_position[0] = 15_f32;
4353 } else {
4354 cr.origin_position[0] += mb.speed;
4355 };
4356 };
4357 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4358 let rect = Rect::from_min_size(
4359 Pos2 {
4360 x: fr.position()[0],
4361 y: fr.position()[1],
4362 },
4363 Vec2 {
4364 x: cr.size[0] + 15_f32,
4365 y: cr.size[1] + 15_f32,
4366 },
4367 );
4368 if rect.contains(mouse_pos) {
4369 s.appearance[0].image_config.overlay_color[3] = 255;
4370 s.appearance[0].custom_rect_config.color[3] = 255;
4371 s.appearance[0].custom_rect_config.border_color[3] = 255;
4372 } else {
4373 s.appearance[0].image_config.overlay_color[3] = 0;
4374 s.appearance[0].custom_rect_config.color[3] = 0;
4375 s.appearance[0].custom_rect_config.border_color[3] = 0;
4376 };
4377 };
4378 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4379 self.replace_resource(&mb.image_name, "Image", im1.clone())
4380 .unwrap();
4381 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4382 .unwrap();
4383 self.replace_resource(&mb.title_name, "Text", t1.clone())
4384 .unwrap();
4385 self.replace_resource(&mb.content_name, "Text", t2.clone())
4386 .unwrap();
4387 self.replace_resource(&format!("MessageBox{}Close", mb.name), "Switch", s.clone())
4388 .unwrap();
4389 match s.fill_resource_type.as_str() {
4390 "Image" => {
4391 self.replace_resource(
4392 &s.fill_resource_name,
4393 &s.fill_resource_type,
4394 fr.as_any().downcast_ref::<Image>().unwrap().clone(),
4395 )
4396 .unwrap();
4397 }
4398 "CustomRect" => {
4399 self.replace_resource(
4400 &s.fill_resource_name,
4401 &s.fill_resource_type,
4402 fr.as_any().downcast_ref::<CustomRect>().unwrap().clone(),
4403 )
4404 .unwrap();
4405 }
4406 &_ => {
4407 unreachable!()
4408 }
4409 };
4410 self.custom_rect(&format!("MessageBox{}", mb.name), ui, ctx)
4411 .unwrap();
4412 self.image(&mb.image_name.clone(), ui, ctx).unwrap();
4413 self.text(&t1.name.clone(), ui, ctx).unwrap();
4414 self.text(&t2.name.clone(), ui, ctx).unwrap();
4415 self.switch(
4416 &format!("MessageBox{}Close", mb.name),
4417 ui,
4418 ctx,
4419 s.state == 0 && mb.exist,
4420 safe_mode,
4421 )
4422 .unwrap();
4423 if self
4424 .check_switch_click_index(&format!("MessageBox{}Close", mb.name))
4425 .unwrap()
4426 == 0
4427 && self
4428 .check_switch_state(&format!("MessageBox{}Close", mb.name))
4429 .unwrap()
4430 == 1
4431 {
4432 mb.exist = false;
4433 if cr.origin_position[0] + mb.speed >= 15_f32 {
4434 cr.origin_position[0] = 15_f32;
4435 } else {
4436 cr.origin_position[0] += mb.speed;
4437 };
4438 self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4439 self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4440 .unwrap();
4441 };
4442 if deleted {
4443 self.rust_constructor_resource.remove(
4444 self.rust_constructor_resource
4445 .iter()
4446 .position(|x| x.expose_type() == "Image" && x.name() == mb.image_name)
4447 .unwrap(),
4448 );
4449 self.rust_constructor_resource.remove(
4450 self.rust_constructor_resource
4451 .iter()
4452 .position(|x| {
4453 x.expose_type() == "CustomRect"
4454 && x.name() == format!("MessageBox{}", mb.name)
4455 })
4456 .unwrap(),
4457 );
4458 self.rust_constructor_resource.remove(
4459 self.rust_constructor_resource
4460 .iter()
4461 .position(|x| x.expose_type() == "Text" && x.name() == mb.title_name)
4462 .unwrap(),
4463 );
4464 self.rust_constructor_resource.remove(
4465 self.rust_constructor_resource
4466 .iter()
4467 .position(|x| x.expose_type() == "Text" && x.name() == mb.content_name)
4468 .unwrap(),
4469 );
4470 self.rust_constructor_resource.remove(
4471 self.rust_constructor_resource
4472 .iter()
4473 .position(|x| {
4474 x.expose_type() == "Switch"
4475 && x.name() == format!("MessageBox{}Close", mb.name)
4476 })
4477 .unwrap(),
4478 );
4479 self.rust_constructor_resource.remove(
4480 self.rust_constructor_resource
4481 .iter()
4482 .position(|x| {
4483 x.expose_type() == s.fill_resource_type
4484 && x.name() == s.fill_resource_name
4485 })
4486 .unwrap(),
4487 );
4488 self.rust_constructor_resource.remove(
4489 self.rust_constructor_resource
4490 .iter()
4491 .position(|x| {
4492 x.expose_type() == "SplitTime"
4493 && x.name() == format!("MessageBox{}Animation", mb.name)
4494 })
4495 .unwrap(),
4496 );
4497 if !mb.keep_existing {
4498 self.rust_constructor_resource.remove(
4499 self.rust_constructor_resource
4500 .iter()
4501 .position(|x| {
4502 x.expose_type() == "SplitTime"
4503 && x.name() == format!("MessageBox{}", mb.name)
4504 })
4505 .unwrap(),
4506 );
4507 };
4508 self.rust_constructor_resource.remove(
4509 self.rust_constructor_resource
4510 .iter()
4511 .position(|x| x.expose_type() == "MessageBox" && x.name() == mb.name)
4512 .unwrap(),
4513 );
4514 } else {
4515 offset += mb.size[1] + 15_f32;
4516 };
4517 }
4518 }
4519
4520 pub fn add_switch(
4522 &mut self,
4523 mut switch: Switch,
4524 fill_resource_name: &str,
4525 fill_resource_type: &str,
4526 text_name: &str,
4527 ) -> Result<(), RustConstructorError> {
4528 let mut count = 1;
4529 if switch.enable_hover_click_fill_resource[0] {
4530 count += 1;
4531 };
4532 if switch.enable_hover_click_fill_resource[1] {
4533 count += 1;
4534 };
4535 if switch.appearance.len() < count {
4536 self.problem_report_custom(
4537 RustConstructorError::SwitchAppearanceMismatch {
4538 switch_name: switch.name.clone(),
4539 differ: count as u32 - switch.appearance.len() as u32,
4540 },
4541 SeverityLevel::SevereWarning,
4542 self.problem_list.clone(),
4543 );
4544 return Err(RustConstructorError::SwitchAppearanceMismatch {
4545 switch_name: switch.name.clone(),
4546 differ: count as u32 - switch.appearance.len() as u32,
4547 });
4548 };
4549 for _ in 0..switch.appearance.len() % count {
4550 switch.appearance.pop();
4551 }
4552 if self.check_resource_exists(text_name, "Text") {
4553 let t = self.get_resource_mut::<Text>(text_name, "Text").unwrap();
4554 switch.text_name = text_name.to_string();
4555 switch.text_origin_position = t.origin_position;
4556 t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
4557 t.x_grid = [0, 0];
4558 t.y_grid = [0, 0];
4559 } else if !text_name.is_empty() {
4560 self.problem_report_custom(
4561 RustConstructorError::TextNotFound {
4562 text_name: text_name.to_string(),
4563 },
4564 SeverityLevel::SevereWarning,
4565 self.problem_list.clone(),
4566 );
4567 };
4568 if self.check_resource_exists(fill_resource_name, fill_resource_type) {
4569 match fill_resource_type {
4570 "Image" | "CustomRect" => {
4571 switch.fill_resource_name = fill_resource_name.to_string();
4572 switch.fill_resource_type = fill_resource_type.to_string();
4573 }
4574 &_ => {
4575 self.problem_report_custom(
4576 RustConstructorError::SwitchFillResourceMismatch {
4577 switch_name: switch.name.clone(),
4578 fill_resource_name: fill_resource_name.to_string(),
4579 fill_resource_type: fill_resource_type.to_string(),
4580 },
4581 SeverityLevel::SevereWarning,
4582 self.problem_list.clone(),
4583 );
4584 return Err(RustConstructorError::SwitchFillResourceMismatch {
4585 switch_name: switch.name.clone(),
4586 fill_resource_name: fill_resource_name.to_string(),
4587 fill_resource_type: fill_resource_type.to_string(),
4588 });
4589 }
4590 };
4591 } else {
4592 self.problem_report_custom(
4593 RustConstructorError::ResourceNotFound {
4594 resource_name: fill_resource_name.to_string(),
4595 resource_type: fill_resource_type.to_string(),
4596 },
4597 SeverityLevel::SevereWarning,
4598 self.problem_list.clone(),
4599 );
4600 return Err(RustConstructorError::ResourceNotFound {
4601 resource_name: fill_resource_name.to_string(),
4602 resource_type: fill_resource_type.to_string(),
4603 });
4604 };
4605 switch.hint_text_name = String::new();
4606 if switch
4607 .appearance
4608 .iter()
4609 .filter(|x| !x.hint_text.is_empty())
4610 .count()
4611 > 0
4612 {
4613 switch.hint_text_name = format!("{}Hint", switch.name);
4614 self.add_text(
4615 Text::default()
4616 .name(&format!("{}Hint", switch.name))
4617 .content("")
4618 .origin_position(0_f32, 0_f32)
4619 .font_size(25_f32)
4620 .wrap_width(300_f32)
4621 .background_rounding(10_f32)
4622 .color(255, 255, 255, 0)
4623 .background_color([0, 0, 0, 255])
4624 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4625 .selectable(false),
4626 );
4627 self.add_split_time(
4628 SplitTime::default().name(&format!("{}StartHoverTime", switch.name)),
4629 );
4630 self.add_split_time(
4631 SplitTime::default().name(&format!("{}HintFadeAnimation", switch.name)),
4632 );
4633 };
4634 switch.state = 0;
4635 switch.animation_count = count as u32;
4636 self.rust_constructor_resource.push(Box::new(switch));
4637 Ok(())
4638 }
4639
4640 pub fn switch(
4642 &mut self,
4643 name: &str,
4644 ui: &mut Ui,
4645 ctx: &Context,
4646 enable: bool,
4647 safe_mode: bool,
4648 ) -> Result<(), RustConstructorError> {
4649 let mut appearance_count = 0;
4650 if safe_mode && !self.check_resource_exists(name, "Switch") {
4651 self.problem_report_custom(
4652 RustConstructorError::SwitchNotFound {
4653 switch_name: name.to_string(),
4654 },
4655 SeverityLevel::SevereWarning,
4656 self.problem_list.clone(),
4657 );
4658 return Err(RustConstructorError::SwitchNotFound {
4659 switch_name: name.to_string(),
4660 });
4661 };
4662 let mut s = self.get_resource::<Switch>(name, "Switch").unwrap().clone();
4663 if safe_mode {
4664 if !self.check_resource_exists(&s.fill_resource_name.clone(), &s.fill_resource_type) {
4665 self.problem_report_custom(
4666 RustConstructorError::ResourceNotFound {
4667 resource_name: s.fill_resource_name.clone(),
4668 resource_type: s.fill_resource_type.clone(),
4669 },
4670 SeverityLevel::SevereWarning,
4671 self.problem_list.clone(),
4672 );
4673 return Err(RustConstructorError::ResourceNotFound {
4674 resource_name: s.fill_resource_name,
4675 resource_type: s.fill_resource_type,
4676 });
4677 };
4678 if !s.hint_text_name.is_empty() {
4679 if !self.check_resource_exists(&format!("{}StartHoverTime", s.name), "SplitTime") {
4680 self.problem_report_custom(
4681 RustConstructorError::SplitTimeNotFound {
4682 split_time_name: format!("{}StartHoverTime", s.name),
4683 },
4684 SeverityLevel::MildWarning,
4685 self.problem_list.clone(),
4686 );
4687 self.add_split_time(
4688 SplitTime::default().name(&format!("{}StartHoverTime", s.name)),
4689 );
4690 };
4691 if !self.check_resource_exists(&format!("{}HintFadeAnimation", s.name), "SplitTime")
4692 {
4693 self.problem_report_custom(
4694 RustConstructorError::SplitTimeNotFound {
4695 split_time_name: format!("{}HintFadeAnimation", s.name),
4696 },
4697 SeverityLevel::MildWarning,
4698 self.problem_list.clone(),
4699 );
4700 self.add_split_time(
4701 SplitTime::default().name(&format!("{}HintFadeAnimation", s.name)),
4702 );
4703 };
4704 if !self.check_resource_exists(&s.hint_text_name, "Text") {
4705 self.problem_report_custom(
4706 RustConstructorError::TextNotFound {
4707 text_name: s.hint_text_name.clone(),
4708 },
4709 SeverityLevel::MildWarning,
4710 self.problem_list.clone(),
4711 );
4712 self.add_text(
4713 Text::default()
4714 .name(&s.hint_text_name)
4715 .content("")
4716 .origin_position(0_f32, 0_f32)
4717 .font_size(25_f32)
4718 .wrap_width(300_f32)
4719 .background_rounding(10_f32)
4720 .color(255, 255, 255, 0)
4721 .background_color([0, 0, 0, 255])
4722 .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4723 .selectable(false),
4724 );
4725 };
4726 };
4727 };
4728 let fr: Box<dyn FrontResource> = match &*s.fill_resource_type {
4729 "Image" => Box::new(
4730 self.get_resource::<Image>(&s.fill_resource_name.clone(), &s.fill_resource_type)
4731 .unwrap()
4732 .clone(),
4733 ),
4734 "CustomRect" => Box::new(
4735 self.get_resource::<CustomRect>(
4736 &s.fill_resource_name.clone(),
4737 &s.fill_resource_type,
4738 )
4739 .unwrap()
4740 .clone(),
4741 ),
4742 &_ => {
4743 self.problem_report_custom(
4744 RustConstructorError::SwitchFillResourceMismatch {
4745 switch_name: name.to_string(),
4746 fill_resource_name: s.fill_resource_name.clone(),
4747 fill_resource_type: s.fill_resource_type.clone(),
4748 },
4749 SeverityLevel::SevereWarning,
4750 self.problem_list.clone(),
4751 );
4752 return Err(RustConstructorError::SwitchFillResourceMismatch {
4753 switch_name: name.to_string(),
4754 fill_resource_name: s.fill_resource_name,
4755 fill_resource_type: s.fill_resource_type,
4756 });
4757 }
4758 };
4759 s.reg_render_resource(&mut self.render_resource_list);
4760 let rect = Rect::from_min_size(
4761 Pos2::new(fr.position()[0], fr.position()[1]),
4762 Vec2::new(fr.size()[0], fr.size()[1]),
4763 );
4764 let mut hovered = false;
4765 if enable {
4766 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4767 if rect.contains(mouse_pos) {
4769 if !s.hint_text_name.is_empty() {
4770 if self.check_resource_exists(&s.hint_text_name, "Text") {
4771 let mut t = self
4772 .get_resource::<Text>(&s.hint_text_name, "Text")
4773 .unwrap()
4774 .clone();
4775 if !s.last_time_hovered {
4776 self.reset_split_time(&format!("{}StartHoverTime", s.name))
4777 .unwrap();
4778 } else if self.timer.total_time
4779 - self
4780 .split_time(&format!("{}StartHoverTime", s.name))
4781 .unwrap()[1]
4782 >= 2_f32
4783 || t.color[3] != 0
4784 {
4785 t.color[3] = 255;
4786 t.origin_position = [mouse_pos.x, mouse_pos.y];
4787 };
4788 t.center_display.0 = if mouse_pos.x
4789 + self.get_text_size(&s.hint_text_name, ui).unwrap()[0]
4790 <= ctx.available_rect().width()
4791 {
4792 HorizontalAlign::Left
4793 } else {
4794 HorizontalAlign::Right
4795 };
4796 t.center_display.1 = if mouse_pos.y
4797 + self.get_text_size(&s.hint_text_name, ui).unwrap()[1]
4798 <= ctx.available_rect().height()
4799 {
4800 VerticalAlign::Top
4801 } else {
4802 VerticalAlign::Bottom
4803 };
4804 self.replace_resource(&s.hint_text_name, "Text", t.clone())
4805 .unwrap();
4806 } else {
4807 self.problem_report_custom(
4808 RustConstructorError::TextNotFound {
4809 text_name: s.hint_text_name.clone(),
4810 },
4811 SeverityLevel::SevereWarning,
4812 self.problem_list.clone(),
4813 );
4814 return Err(RustConstructorError::TextNotFound {
4815 text_name: s.hint_text_name.clone(),
4816 });
4817 };
4818 };
4819 hovered = true;
4820 let mut clicked = vec![];
4821 let mut active = false;
4822 for u in 0..s.click_method.len() as u32 {
4823 clicked.push(ui.input(|i| {
4824 i.pointer
4825 .button_down(s.click_method[u as usize].click_method)
4826 }));
4827 if clicked[u as usize] {
4828 active = true;
4829 s.last_time_clicked_index = u as usize;
4830 break;
4831 };
4832 }
4833 if active {
4834 s.last_time_clicked = true;
4835 if s.enable_hover_click_fill_resource[1] {
4836 if s.enable_hover_click_fill_resource[0] {
4837 appearance_count = 2;
4838 } else {
4839 appearance_count = 1;
4840 };
4841 } else if !s.enable_hover_click_fill_resource[0] {
4842 appearance_count = 0;
4843 };
4844 } else {
4845 if s.last_time_clicked {
4846 if s.click_method[s.last_time_clicked_index].action {
4847 if s.state
4848 < (s.appearance.len() / s.animation_count as usize - 1) as u32
4849 {
4850 s.state += 1;
4851 } else {
4852 s.state = 0;
4853 };
4854 };
4855 s.last_time_clicked = false;
4856 };
4857 if s.enable_hover_click_fill_resource[0] {
4858 appearance_count = 1;
4859 } else {
4860 appearance_count = 0;
4861 };
4862 };
4863 } else {
4864 s.last_time_clicked = false;
4865 appearance_count = 0;
4866 };
4867 } else {
4868 s.last_time_clicked = false;
4869 appearance_count = 0;
4870 };
4871 } else {
4872 s.last_time_clicked = false;
4873 appearance_count = 0;
4874 };
4875 if !hovered && !s.hint_text_name.is_empty() {
4876 if s.last_time_hovered {
4877 self.reset_split_time(&format!("{}HintFadeAnimation", s.name))
4878 .unwrap();
4879 };
4880 if self.check_resource_exists(&s.hint_text_name, "Text") {
4881 let mut t = self
4882 .get_resource::<Text>(&s.hint_text_name, "Text")
4883 .unwrap()
4884 .clone();
4885 if self.timer.total_time
4886 - self
4887 .split_time(&format!("{}HintFadeAnimation", s.name))
4888 .unwrap()[1]
4889 >= self.tick_interval
4890 {
4891 self.reset_split_time(&format!("{}HintFadeAnimation", s.name))
4892 .unwrap();
4893 t.color[3] = t.color[3].saturating_sub(10);
4894 };
4895 self.replace_resource(&s.hint_text_name, "Text", t.clone())
4896 .unwrap();
4897 } else {
4898 self.problem_report_custom(
4899 RustConstructorError::TextNotFound {
4900 text_name: s.hint_text_name.clone(),
4901 },
4902 SeverityLevel::SevereWarning,
4903 self.problem_list.clone(),
4904 );
4905 return Err(RustConstructorError::TextNotFound {
4906 text_name: s.hint_text_name.clone(),
4907 });
4908 };
4909 };
4910 let fr: Box<dyn FrontResource> = match &*s.fill_resource_type {
4911 "Image" => {
4912 let mut im = Box::new(
4913 fr.as_any()
4914 .downcast_ref::<Image>()
4915 .unwrap()
4916 .clone()
4917 .from_config(
4918 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
4919 .image_config
4920 .clone(),
4921 ),
4922 );
4923 if self.check_resource_exists(
4924 &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
4925 .texture
4926 .clone(),
4927 "ImageTexture",
4928 ) {
4929 im.cite_texture = s.appearance
4930 [(s.state * s.animation_count + appearance_count) as usize]
4931 .texture
4932 .clone();
4933 } else {
4934 self.problem_report_custom(
4935 RustConstructorError::ImageTextureNotFound {
4936 image_texture_name: s.appearance
4937 [(s.state * s.animation_count + appearance_count) as usize]
4938 .texture
4939 .clone(),
4940 },
4941 SeverityLevel::SevereWarning,
4942 self.problem_list.clone(),
4943 );
4944 return Err(RustConstructorError::ImageTextureNotFound {
4945 image_texture_name: s.appearance
4946 [(s.state * s.animation_count + appearance_count) as usize]
4947 .texture
4948 .clone(),
4949 });
4950 };
4951 im
4952 }
4953 "CustomRect" => Box::new(
4954 fr.as_any()
4955 .downcast_ref::<CustomRect>()
4956 .unwrap()
4957 .clone()
4958 .name(&s.fill_resource_name)
4959 .from_config(
4960 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
4961 .custom_rect_config
4962 .clone(),
4963 ),
4964 ),
4965 &_ => {
4966 self.problem_report_custom(
4967 RustConstructorError::SwitchFillResourceMismatch {
4968 switch_name: name.to_string(),
4969 fill_resource_name: s.fill_resource_name.clone(),
4970 fill_resource_type: s.fill_resource_type.clone(),
4971 },
4972 SeverityLevel::SevereWarning,
4973 self.problem_list.clone(),
4974 );
4975 return Err(RustConstructorError::SwitchFillResourceMismatch {
4976 switch_name: name.to_string(),
4977 fill_resource_name: s.fill_resource_name,
4978 fill_resource_type: s.fill_resource_type,
4979 });
4980 }
4981 };
4982 if !s.hint_text_name.is_empty() {
4983 if self.check_resource_exists(&s.hint_text_name, "Text") {
4984 let mut t = self
4985 .get_resource::<Text>(&s.hint_text_name, "Text")
4986 .unwrap()
4987 .clone();
4988 t.background_color[3] = t.color[3];
4989 t.content = s.appearance[(s.state * s.animation_count + appearance_count) as usize]
4990 .hint_text
4991 .clone();
4992 self.replace_resource(&s.hint_text_name, "Text", t.clone())
4993 .unwrap();
4994 } else {
4995 self.problem_report_custom(
4996 RustConstructorError::TextNotFound {
4997 text_name: s.hint_text_name.clone(),
4998 },
4999 SeverityLevel::SevereWarning,
5000 self.problem_list.clone(),
5001 );
5002 return Err(RustConstructorError::TextNotFound {
5003 text_name: s.hint_text_name,
5004 });
5005 };
5006 };
5007 s.last_time_hovered = hovered;
5008 self.replace_resource(name, "Switch", s.clone()).unwrap();
5009 match s.fill_resource_type.as_str() {
5010 "Image" => {
5011 let im = fr.as_any().downcast_ref::<Image>().unwrap().clone();
5012 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, im)
5013 .unwrap();
5014 self.image(&s.fill_resource_name.clone(), ui, ctx).unwrap();
5015 }
5016 "CustomRect" => {
5017 let cr = fr.as_any().downcast_ref::<CustomRect>().unwrap().clone();
5018 self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, cr)
5019 .unwrap();
5020 self.custom_rect(&s.fill_resource_name.clone(), ui, ctx)
5021 .unwrap();
5022 }
5023 &_ => {}
5024 }
5025 if self.check_resource_exists(&s.text_name, "Text") {
5026 let mut t = self
5027 .get_resource::<Text>(&s.text_name, "Text")
5028 .unwrap()
5029 .clone();
5030 s.text_origin_position = s.appearance
5031 [(s.state * s.animation_count + appearance_count) as usize]
5032 .text_config
5033 .origin_position;
5034 t.origin_position = [
5035 fr.position()[0] + s.text_origin_position[0],
5036 fr.position()[1] + s.text_origin_position[1],
5037 ];
5038 t = t.from_config(
5039 s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5040 .text_config
5041 .clone(),
5042 );
5043 self.replace_resource(&s.text_name, "Text", t.clone())
5044 .unwrap();
5045 self.text(&s.text_name, ui, ctx).unwrap();
5046 };
5047 if self.check_resource_exists(&s.hint_text_name, "Text") {
5048 self.text(&s.hint_text_name, ui, ctx).unwrap();
5049 };
5050 Ok(())
5051 }
5052
5053 pub fn check_switch_click_index(&self, name: &str) -> Result<usize, RustConstructorError> {
5055 if self.check_resource_exists(name, "Switch") {
5056 let s = self.get_resource::<Switch>(name, "Switch").unwrap();
5057 Ok(s.last_time_clicked_index)
5058 } else {
5059 self.problem_report_custom(
5060 RustConstructorError::SwitchNotFound {
5061 switch_name: name.to_string(),
5062 },
5063 SeverityLevel::SevereWarning,
5064 self.problem_list.clone(),
5065 );
5066 Err(RustConstructorError::SwitchNotFound {
5067 switch_name: name.to_string(),
5068 })
5069 }
5070 }
5071
5072 pub fn check_switch_state(&self, name: &str) -> Result<u32, RustConstructorError> {
5074 if self.check_resource_exists(name, "Switch") {
5075 let s = self.get_resource::<Switch>(name, "Switch").unwrap();
5076 Ok(s.state)
5077 } else {
5078 self.problem_report_custom(
5079 RustConstructorError::SwitchNotFound {
5080 switch_name: name.to_string(),
5081 },
5082 SeverityLevel::SevereWarning,
5083 self.problem_list.clone(),
5084 );
5085 Err(RustConstructorError::SwitchNotFound {
5086 switch_name: name.to_string(),
5087 })
5088 }
5089 }
5090}