1use eframe::{
23 Result,
24 emath::Rect,
25 epaint::{Stroke, textures::TextureOptions},
26};
27use egui::{
28 Color32, ColorImage, Context, CornerRadius, FontData, FontDefinitions, FontFamily, FontId,
29 Galley, Id, ImageSource, Key, OpenUrl, Pos2, Sense, StrokeKind, TextureHandle, Ui, Vec2,
30 text::CCursor,
31};
32use std::{
33 any::{Any, type_name_of_val},
34 char,
35 collections::HashMap,
36 error::Error,
37 fmt::{Debug, Display, Formatter},
38 fs::{File, read},
39 io::Read,
40 sync::Arc,
41 time::Instant,
42 vec::Vec,
43};
44
45pub trait RustConstructorResource: Debug {
47 fn as_any(&self) -> &dyn Any;
49
50 fn as_any_mut(&mut self) -> &mut dyn Any;
52
53 fn display_display_info(&self) -> Option<DisplayInfo>;
55
56 fn modify_display_info(&mut self, display_info: DisplayInfo);
58
59 fn display_tags(&self) -> Vec<[String; 2]>;
61
62 fn modify_tags(&mut self, tags: &[[String; 2]]);
64}
65
66pub trait BasicFrontResource: RustConstructorResource {
68 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig;
70
71 fn display_position_size_config(&self) -> PositionSizeConfig;
73
74 fn display_clip_rect(&self) -> Option<PositionSizeConfig>;
76
77 fn modify_basic_front_resource_config(
79 &mut self,
80 basic_front_resource_config: BasicFrontResourceConfig,
81 );
82
83 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig);
85
86 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>);
88}
89
90#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
92pub struct RustConstructorId {
93 pub name: String,
95 pub discern_type: String,
97}
98
99#[derive(Debug)]
101pub struct RustConstructorResourceBox {
102 pub id: RustConstructorId,
104 pub content: Box<dyn RustConstructorResource>,
106}
107
108impl RustConstructorResourceBox {
109 pub fn new(name: &str, discern_type: &str, content: Box<dyn RustConstructorResource>) -> Self {
110 Self {
111 id: RustConstructorId {
112 name: name.to_string(),
113 discern_type: discern_type.to_string(),
114 },
115 content,
116 }
117 }
118}
119
120#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
122pub struct BasicFrontResourceConfig {
123 pub position_size_config: PositionSizeConfig,
125 pub clip_rect: Option<PositionSizeConfig>,
127}
128
129impl BasicFrontResourceConfig {
130 #[inline]
131 pub fn position_size_config(mut self, position_size_config: PositionSizeConfig) -> Self {
132 self.position_size_config = position_size_config;
133 self
134 }
135
136 #[inline]
137 pub fn clip_rect(mut self, clip_rect: Option<PositionSizeConfig>) -> Self {
138 self.clip_rect = clip_rect;
139 self
140 }
141}
142
143#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
145pub struct PositionSizeConfig {
146 pub position: [f32; 2],
148 pub size: [f32; 2],
150 pub origin_position: [f32; 2],
152 pub origin_size: [f32; 2],
154 pub x_location_grid: [f32; 2],
156 pub y_location_grid: [f32; 2],
158 pub x_size_grid: [f32; 2],
160 pub y_size_grid: [f32; 2],
162 pub display_method: (HorizontalAlign, VerticalAlign),
164 pub offset: [f32; 2],
166}
167
168impl Default for PositionSizeConfig {
169 fn default() -> Self {
170 PositionSizeConfig {
171 position: [0_f32, 0_f32],
172 size: [0_f32, 0_f32],
173 origin_position: [0_f32, 0_f32],
174 origin_size: [0_f32, 0_f32],
175 x_location_grid: [0_f32, 0_f32],
176 y_location_grid: [0_f32, 0_f32],
177 x_size_grid: [0_f32, 0_f32],
178 y_size_grid: [0_f32, 0_f32],
179 display_method: (HorizontalAlign::default(), VerticalAlign::default()),
180 offset: [0_f32, 0_f32],
181 }
182 }
183}
184
185impl PositionSizeConfig {
186 #[inline]
187 pub fn origin_position(mut self, x: f32, y: f32) -> Self {
188 self.origin_position = [x, y];
189 self
190 }
191
192 #[inline]
193 pub fn origin_size(mut self, width: f32, height: f32) -> Self {
194 self.origin_size = [width, height];
195 self
196 }
197
198 #[inline]
199 pub fn x_size_grid(mut self, fetch: f32, total: f32) -> Self {
200 self.x_size_grid = [fetch, total];
201 self
202 }
203
204 #[inline]
205 pub fn y_size_grid(mut self, fetch: f32, total: f32) -> Self {
206 self.y_size_grid = [fetch, total];
207 self
208 }
209
210 #[inline]
211 pub fn x_location_grid(mut self, fetch: f32, total: f32) -> Self {
212 self.x_location_grid = [fetch, total];
213 self
214 }
215
216 #[inline]
217 pub fn y_location_grid(mut self, fetch: f32, total: f32) -> Self {
218 self.y_location_grid = [fetch, total];
219 self
220 }
221
222 #[inline]
223 pub fn display_method(
224 mut self,
225 horizontal_align: HorizontalAlign,
226 vertical_align: VerticalAlign,
227 ) -> Self {
228 self.display_method = (horizontal_align, vertical_align);
229 self
230 }
231
232 #[inline]
233 pub fn offset(mut self, x: f32, y: f32) -> Self {
234 self.offset = [x, y];
235 self
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, PartialOrd)]
241pub struct EventState {
242 pub current_page: String,
244 pub current_total_runtime: f32,
246 pub current_page_runtime: f32,
248}
249
250#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
252pub enum NeedPlaceholder {
253 Yes(u32),
255 #[default]
257 No,
258}
259
260#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
262pub struct PageData {
263 pub forced_update: bool,
265 pub change_page_updated: bool,
267 pub enter_page_updated: bool,
269 pub tags: Vec<[String; 2]>,
271}
272
273impl RustConstructorResource for PageData {
274 fn as_any(&self) -> &dyn Any {
275 self
276 }
277
278 fn as_any_mut(&mut self) -> &mut dyn Any {
279 self
280 }
281
282 fn display_display_info(&self) -> Option<DisplayInfo> {
283 None
284 }
285
286 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
287
288 fn display_tags(&self) -> Vec<[String; 2]> {
289 self.tags.clone()
290 }
291
292 fn modify_tags(&mut self, tags: &[[String; 2]]) {
293 self.tags = tags.to_owned();
294 }
295}
296
297impl Default for PageData {
298 fn default() -> Self {
299 PageData {
300 forced_update: true,
301 change_page_updated: false,
302 enter_page_updated: false,
303 tags: Vec::new(),
304 }
305 }
306}
307
308impl PageData {
309 #[inline]
310 pub fn forced_update(mut self, forced_update: bool) -> Self {
311 self.forced_update = forced_update;
312 self
313 }
314
315 #[inline]
316 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
317 self.tags = tags.to_owned();
318 self
319 }
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
324pub struct Timer {
325 pub start_time: f32,
327 pub total_time: f32,
329 pub timer: Instant,
331 pub now_time: f32,
333}
334
335impl Default for Timer {
336 fn default() -> Self {
337 Timer {
338 start_time: 0_f32,
339 total_time: 0_f32,
340 timer: Instant::now(),
341 now_time: 0_f32,
342 }
343 }
344}
345
346#[derive(Clone, PartialEq, Eq, Hash)]
348pub struct DebugTextureHandle(TextureHandle);
349
350impl Debug for DebugTextureHandle {
351 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
352 f.debug_struct("DebugTextureHandle").finish()
354 }
355}
356
357impl DebugTextureHandle {
358 pub fn new(texture_handle: &TextureHandle) -> Self {
359 Self(texture_handle.clone())
360 }
361}
362
363#[derive(Clone, Debug, Default, PartialEq)]
365pub struct ImageTexture {
366 pub texture: Option<DebugTextureHandle>,
368 pub cite_path: String,
370 pub flip: [bool; 2],
372 pub context: Context,
374 pub tags: Vec<[String; 2]>,
376}
377
378impl RustConstructorResource for ImageTexture {
379 fn as_any(&self) -> &dyn Any {
380 self
381 }
382
383 fn as_any_mut(&mut self) -> &mut dyn Any {
384 self
385 }
386
387 fn display_display_info(&self) -> Option<DisplayInfo> {
388 None
389 }
390
391 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
392
393 fn display_tags(&self) -> Vec<[String; 2]> {
394 self.tags.clone()
395 }
396
397 fn modify_tags(&mut self, tags: &[[String; 2]]) {
398 self.tags = tags.to_owned();
399 }
400}
401
402impl ImageTexture {
403 #[inline]
404 pub fn cite_path(mut self, cite_path: &str) -> Self {
405 self.cite_path = cite_path.to_string();
406 self
407 }
408
409 #[inline]
410 pub fn flip(mut self, horizontal_flip: bool, vertical_flip: bool) -> Self {
411 self.flip = [horizontal_flip, vertical_flip];
412 self
413 }
414
415 #[inline]
416 pub fn ctx(mut self, context: &Context) -> Self {
417 self.context = context.clone();
418 self
419 }
420
421 #[inline]
422 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
423 self.tags = tags.to_owned();
424 self
425 }
426}
427
428#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
430pub enum BorderKind {
431 #[default]
433 Inside,
434 Middle,
436 Outside,
438}
439
440#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
442pub struct CustomRectConfig {
443 pub position_size_config: Option<PositionSizeConfig>,
445 pub clip_rect: Option<Option<PositionSizeConfig>>,
447 pub hidden: Option<bool>,
449 pub ignore_render_layer: Option<bool>,
451 pub rounding: Option<f32>,
453 pub color: Option<[u8; 4]>,
455 pub border_width: Option<f32>,
457 pub border_color: Option<[u8; 4]>,
459 pub border_kind: Option<BorderKind>,
461 pub tags: Option<Vec<[String; 2]>>,
463}
464
465impl CustomRectConfig {
466 pub fn from_custom_rect(custom_rect: &CustomRect) -> Self {
467 Self {
468 position_size_config: Some(
469 custom_rect.basic_front_resource_config.position_size_config,
470 ),
471 clip_rect: Some(custom_rect.basic_front_resource_config.clip_rect),
472 hidden: Some(custom_rect.display_info.hidden),
473 ignore_render_layer: Some(custom_rect.display_info.ignore_render_layer),
474 rounding: Some(custom_rect.rounding),
475 color: Some(custom_rect.color),
476 border_width: Some(custom_rect.border_width),
477 border_color: Some(custom_rect.border_color),
478 border_kind: Some(custom_rect.border_kind),
479 tags: Some(custom_rect.tags.clone()),
480 }
481 }
482
483 #[inline]
484 pub fn position_size_config(
485 mut self,
486 position_size_config: Option<PositionSizeConfig>,
487 ) -> Self {
488 self.position_size_config = position_size_config;
489 self
490 }
491
492 #[inline]
493 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
494 self.clip_rect = clip_rect;
495 self
496 }
497
498 #[inline]
499 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
500 self.hidden = hidden;
501 self
502 }
503
504 #[inline]
505 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
506 self.ignore_render_layer = ignore_render_layer;
507 self
508 }
509
510 #[inline]
511 pub fn rounding(mut self, rounding: Option<f32>) -> Self {
512 self.rounding = rounding;
513 self
514 }
515
516 #[inline]
517 pub fn color(mut self, color: Option<[u8; 4]>) -> Self {
518 self.color = color;
519 self
520 }
521
522 #[inline]
523 pub fn border_width(mut self, border_width: Option<f32>) -> Self {
524 self.border_width = border_width;
525 self
526 }
527
528 #[inline]
529 pub fn border_color(mut self, border_color: Option<[u8; 4]>) -> Self {
530 self.border_color = border_color;
531 self
532 }
533
534 #[inline]
535 pub fn border_kind(mut self, border_kind: Option<BorderKind>) -> Self {
536 self.border_kind = border_kind;
537 self
538 }
539
540 #[inline]
541 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
542 self.tags = tags;
543 self
544 }
545}
546
547#[derive(Debug, Clone, PartialEq, PartialOrd)]
549pub struct CustomRect {
550 pub basic_front_resource_config: BasicFrontResourceConfig,
552 pub display_info: DisplayInfo,
554 pub rounding: f32,
556 pub color: [u8; 4],
558 pub border_width: f32,
560 pub border_color: [u8; 4],
562 pub border_kind: BorderKind,
564 pub tags: Vec<[String; 2]>,
566}
567
568impl RustConstructorResource for CustomRect {
569 fn as_any(&self) -> &dyn Any {
570 self
571 }
572
573 fn as_any_mut(&mut self) -> &mut dyn Any {
574 self
575 }
576
577 fn display_display_info(&self) -> Option<DisplayInfo> {
578 Some(self.display_info)
579 }
580
581 fn modify_display_info(&mut self, display_info: DisplayInfo) {
582 self.display_info = display_info;
583 }
584
585 fn display_tags(&self) -> Vec<[String; 2]> {
586 self.tags.clone()
587 }
588
589 fn modify_tags(&mut self, tags: &[[String; 2]]) {
590 self.tags = tags.to_owned();
591 }
592}
593
594impl BasicFrontResource for CustomRect {
595 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
596 self.basic_front_resource_config.clone()
597 }
598
599 fn display_position_size_config(&self) -> PositionSizeConfig {
600 self.basic_front_resource_config.position_size_config
601 }
602
603 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
604 self.basic_front_resource_config.clip_rect
605 }
606
607 fn modify_basic_front_resource_config(
608 &mut self,
609 basic_front_resource_config: BasicFrontResourceConfig,
610 ) {
611 self.basic_front_resource_config = basic_front_resource_config;
612 }
613
614 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
615 self.basic_front_resource_config.position_size_config = position_size_config;
616 }
617
618 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
619 self.basic_front_resource_config.clip_rect = clip_rect;
620 }
621}
622
623impl Default for CustomRect {
624 fn default() -> Self {
625 Self {
626 basic_front_resource_config: BasicFrontResourceConfig::default(),
627 display_info: DisplayInfo::default(),
628 rounding: 2_f32,
629 color: [255, 255, 255, 255],
630 border_width: 2_f32,
631 border_color: [0, 0, 0, 255],
632 border_kind: BorderKind::default(),
633 tags: Vec::new(),
634 }
635 }
636}
637
638impl CustomRect {
639 pub fn from_config(mut self, config: &CustomRectConfig) -> Self {
640 if let Some(position_size_config) = config.position_size_config {
641 self.basic_front_resource_config.position_size_config = position_size_config;
642 };
643 if let Some(clip_rect) = config.clip_rect {
644 self.basic_front_resource_config.clip_rect = clip_rect;
645 };
646 if let Some(hidden) = config.hidden {
647 self.display_info.hidden = hidden;
648 };
649 if let Some(ignore_render_layer) = config.ignore_render_layer {
650 self.display_info.ignore_render_layer = ignore_render_layer;
651 };
652 if let Some(rounding) = config.rounding {
653 self.rounding = rounding;
654 };
655 if let Some(color) = config.color {
656 self.color = color;
657 };
658 if let Some(border_width) = config.border_width {
659 self.border_width = border_width;
660 };
661 if let Some(border_color) = config.border_color {
662 self.border_color = border_color;
663 };
664 if let Some(border_kind) = config.border_kind {
665 self.border_kind = border_kind;
666 };
667 if let Some(tags) = config.tags.clone() {
668 self.tags = tags;
669 };
670 self
671 }
672
673 #[inline]
674 pub fn basic_front_resource_config(
675 mut self,
676 basic_front_resource_config: &BasicFrontResourceConfig,
677 ) -> Self {
678 self.basic_front_resource_config = basic_front_resource_config.clone();
679 self
680 }
681
682 #[inline]
683 pub fn hidden(mut self, hidden: bool) -> Self {
684 self.display_info.hidden = hidden;
685 self
686 }
687
688 #[inline]
689 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
690 self.display_info.ignore_render_layer = ignore_render_layer;
691 self
692 }
693
694 #[inline]
695 pub fn rounding(mut self, rounding: f32) -> Self {
696 self.rounding = rounding;
697 self
698 }
699
700 #[inline]
701 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
702 self.color = [r, g, b, a];
703 self
704 }
705
706 #[inline]
707 pub fn border_width(mut self, border_width: f32) -> Self {
708 self.border_width = border_width;
709 self
710 }
711
712 #[inline]
713 pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
714 self.border_color = [r, g, b, a];
715 self
716 }
717
718 #[inline]
719 pub fn border_kind(mut self, border_kind: BorderKind) -> Self {
720 self.border_kind = border_kind;
721 self
722 }
723
724 #[inline]
725 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
726 self.tags = tags.to_owned();
727 self
728 }
729}
730
731#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
733pub struct ImageConfig {
734 pub position_size_config: Option<PositionSizeConfig>,
736 pub clip_rect: Option<Option<PositionSizeConfig>>,
738 pub hidden: Option<bool>,
740 pub ignore_render_layer: Option<bool>,
742 pub alpha: Option<u8>,
744 pub overlay_color: Option<[u8; 4]>,
746 pub background_color: Option<[u8; 4]>,
748 pub rotate_angle: Option<f32>,
750 pub rotate_center: Option<[f32; 2]>,
752 pub cite_texture: Option<String>,
754 pub tags: Option<Vec<[String; 2]>>,
756}
757
758impl ImageConfig {
759 pub fn from_image(image: &Image) -> Self {
760 Self {
761 position_size_config: Some(image.basic_front_resource_config.position_size_config),
762 clip_rect: Some(image.basic_front_resource_config.clip_rect),
763 hidden: Some(image.display_info.hidden),
764 ignore_render_layer: Some(image.display_info.ignore_render_layer),
765 alpha: Some(image.alpha),
766 overlay_color: Some(image.overlay_color),
767 background_color: Some(image.background_color),
768 rotate_angle: Some(image.rotate_angle),
769 rotate_center: Some(image.rotate_center),
770 cite_texture: Some(image.cite_texture.clone()),
771 tags: Some(image.tags.clone()),
772 }
773 }
774
775 #[inline]
776 pub fn position_size_config(
777 mut self,
778 position_size_config: Option<PositionSizeConfig>,
779 ) -> Self {
780 self.position_size_config = position_size_config;
781 self
782 }
783
784 #[inline]
785 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
786 self.clip_rect = clip_rect;
787 self
788 }
789
790 #[inline]
791 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
792 self.hidden = hidden;
793 self
794 }
795
796 #[inline]
797 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
798 self.ignore_render_layer = ignore_render_layer;
799 self
800 }
801
802 #[inline]
803 pub fn alpha(mut self, alpha: Option<u8>) -> Self {
804 self.alpha = alpha;
805 self
806 }
807
808 #[inline]
809 pub fn overlay_color(mut self, overlay_color: Option<[u8; 4]>) -> Self {
810 self.overlay_color = overlay_color;
811 self
812 }
813
814 #[inline]
815 pub fn background_color(mut self, background_color: Option<[u8; 4]>) -> Self {
816 self.background_color = background_color;
817 self
818 }
819
820 #[inline]
821 pub fn rotate_angle(mut self, rotate_angle: Option<f32>) -> Self {
822 self.rotate_angle = rotate_angle;
823 self
824 }
825
826 #[inline]
827 pub fn rotate_center(mut self, rotate_center: Option<[f32; 2]>) -> Self {
828 self.rotate_center = rotate_center;
829 self
830 }
831
832 #[inline]
833 pub fn cite_texture(mut self, cite_texture: Option<String>) -> Self {
834 self.cite_texture = cite_texture;
835 self
836 }
837
838 #[inline]
839 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
840 self.tags = tags;
841 self
842 }
843}
844
845#[derive(Debug, Clone, PartialEq)]
847pub struct Image {
848 pub basic_front_resource_config: BasicFrontResourceConfig,
850 pub display_info: DisplayInfo,
852 pub texture: Option<DebugTextureHandle>,
854 pub alpha: u8,
856 pub overlay_color: [u8; 4],
858 pub background_color: [u8; 4],
860 pub rotate_angle: f32,
862 pub rotate_center: [f32; 2],
864 pub cite_texture: String,
866 pub last_frame_cite_texture: String,
868 pub tags: Vec<[String; 2]>,
870}
871
872impl RustConstructorResource for Image {
873 fn as_any(&self) -> &dyn Any {
874 self
875 }
876
877 fn as_any_mut(&mut self) -> &mut dyn Any {
878 self
879 }
880
881 fn display_display_info(&self) -> Option<DisplayInfo> {
882 Some(self.display_info)
883 }
884
885 fn modify_display_info(&mut self, display_info: DisplayInfo) {
886 self.display_info = display_info;
887 }
888
889 fn display_tags(&self) -> Vec<[String; 2]> {
890 self.tags.clone()
891 }
892
893 fn modify_tags(&mut self, tags: &[[String; 2]]) {
894 self.tags = tags.to_owned();
895 }
896}
897
898impl BasicFrontResource for Image {
899 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
900 self.basic_front_resource_config.clone()
901 }
902
903 fn display_position_size_config(&self) -> PositionSizeConfig {
904 self.basic_front_resource_config.position_size_config
905 }
906
907 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
908 self.basic_front_resource_config.clip_rect
909 }
910
911 fn modify_basic_front_resource_config(
912 &mut self,
913 basic_front_resource_config: BasicFrontResourceConfig,
914 ) {
915 self.basic_front_resource_config = basic_front_resource_config;
916 }
917
918 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
919 self.basic_front_resource_config.position_size_config = position_size_config;
920 }
921
922 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
923 self.basic_front_resource_config.clip_rect = clip_rect;
924 }
925}
926
927impl Default for Image {
928 fn default() -> Self {
929 Self {
930 basic_front_resource_config: BasicFrontResourceConfig::default(),
931 display_info: DisplayInfo::default(),
932 texture: None,
933 alpha: 255,
934 overlay_color: [255, 255, 255, 255],
935 background_color: [0, 0, 0, 0],
936 rotate_angle: 0_f32,
937 rotate_center: [0_f32, 0_f32],
938 cite_texture: String::from("rust_constructor::ImageTexture"),
939 last_frame_cite_texture: String::from("rust_constructor::ImageTexture"),
940 tags: Vec::new(),
941 }
942 }
943}
944
945impl Image {
946 pub fn from_config(mut self, config: &ImageConfig) -> Self {
947 if let Some(position_size_config) = config.position_size_config {
948 self.basic_front_resource_config.position_size_config = position_size_config;
949 };
950 if let Some(clip_rect) = config.clip_rect {
951 self.basic_front_resource_config.clip_rect = clip_rect;
952 };
953 if let Some(hidden) = config.hidden {
954 self.display_info.hidden = hidden;
955 };
956 if let Some(ignore_render_layer) = config.ignore_render_layer {
957 self.display_info.ignore_render_layer = ignore_render_layer;
958 };
959 if let Some(alpha) = config.alpha {
960 self.alpha = alpha;
961 };
962 if let Some(overlay_color) = config.overlay_color {
963 self.overlay_color = overlay_color;
964 };
965 if let Some(background_color) = config.background_color {
966 self.background_color = background_color;
967 };
968 if let Some(rotate_angle) = config.rotate_angle {
969 self.rotate_angle = rotate_angle;
970 };
971 if let Some(rotate_center) = config.rotate_center {
972 self.rotate_center = rotate_center;
973 };
974 if let Some(cite_texture) = config.cite_texture.clone() {
975 self.cite_texture = cite_texture;
976 };
977 if let Some(tags) = config.tags.clone() {
978 self.tags = tags;
979 };
980 self
981 }
982
983 #[inline]
984 pub fn basic_front_resource_config(
985 mut self,
986 basic_front_resource_config: &BasicFrontResourceConfig,
987 ) -> Self {
988 self.basic_front_resource_config = basic_front_resource_config.clone();
989 self
990 }
991
992 #[inline]
993 pub fn hidden(mut self, hidden: bool) -> Self {
994 self.display_info.hidden = hidden;
995 self
996 }
997
998 #[inline]
999 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
1000 self.display_info.ignore_render_layer = ignore_render_layer;
1001 self
1002 }
1003
1004 #[inline]
1005 pub fn alpha(mut self, alpha: u8) -> Self {
1006 self.alpha = alpha;
1007 self
1008 }
1009
1010 #[inline]
1011 pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1012 self.overlay_color = [r, g, b, a];
1013 self
1014 }
1015
1016 #[inline]
1017 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1018 self.background_color = [r, g, b, a];
1019 self
1020 }
1021
1022 #[inline]
1023 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1024 self.rotate_angle = rotate_angle;
1025 self
1026 }
1027
1028 #[inline]
1029 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1030 self.rotate_center = [x, y];
1031 self
1032 }
1033
1034 #[inline]
1035 pub fn cite_texture(mut self, cite_texture: &str) -> Self {
1036 self.cite_texture = cite_texture.to_string();
1037 self
1038 }
1039
1040 #[inline]
1041 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
1042 self.tags = tags.to_owned();
1043 self
1044 }
1045}
1046
1047#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1049pub enum HyperlinkSelectMethod {
1050 All(String),
1052 Segment(Vec<(usize, String)>),
1054}
1055
1056#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1058pub struct TextConfig {
1059 pub position_size_config: Option<PositionSizeConfig>,
1061 pub clip_rect: Option<Option<PositionSizeConfig>>,
1063 pub hidden: Option<bool>,
1065 pub ignore_render_layer: Option<bool>,
1067 pub content: Option<String>,
1069 pub font_size: Option<f32>,
1071 pub color: Option<[u8; 4]>,
1073 pub background_color: Option<[u8; 4]>,
1075 pub background_rounding: Option<f32>,
1077 pub font: Option<String>,
1079 pub selectable: Option<bool>,
1081 pub hyperlink_text: Option<Vec<(String, HyperlinkSelectMethod)>>,
1083 pub truncate: Option<bool>,
1085 pub tags: Option<Vec<[String; 2]>>,
1087}
1088
1089impl TextConfig {
1090 pub fn from_text(text: &Text) -> Self {
1091 Self {
1092 position_size_config: Some(text.basic_front_resource_config.position_size_config),
1093 clip_rect: Some(text.basic_front_resource_config.clip_rect),
1094 hidden: Some(text.display_info.hidden),
1095 ignore_render_layer: Some(text.display_info.ignore_render_layer),
1096 content: Some(text.content.clone()),
1097 font_size: Some(text.font_size),
1098 color: Some(text.color),
1099 background_color: Some(text.background_color),
1100 background_rounding: Some(text.background_rounding),
1101 font: Some(text.font.clone()),
1102 selectable: Some(text.selectable),
1103 hyperlink_text: Some(text.hyperlink_text.clone()),
1104 truncate: Some(text.truncate),
1105 tags: Some(text.tags.clone()),
1106 }
1107 }
1108
1109 #[inline]
1110 pub fn position_size_config(
1111 mut self,
1112 position_size_config: Option<PositionSizeConfig>,
1113 ) -> Self {
1114 self.position_size_config = position_size_config;
1115 self
1116 }
1117
1118 #[inline]
1119 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
1120 self.clip_rect = clip_rect;
1121 self
1122 }
1123
1124 #[inline]
1125 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
1126 self.hidden = hidden;
1127 self
1128 }
1129
1130 #[inline]
1131 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
1132 self.ignore_render_layer = ignore_render_layer;
1133 self
1134 }
1135
1136 #[inline]
1137 pub fn content(mut self, content: Option<String>) -> Self {
1138 self.content = content;
1139 self
1140 }
1141
1142 #[inline]
1143 pub fn font_size(mut self, font_size: Option<f32>) -> Self {
1144 self.font_size = font_size;
1145 self
1146 }
1147
1148 #[inline]
1149 pub fn color(mut self, color: Option<[u8; 4]>) -> Self {
1150 self.color = color;
1151 self
1152 }
1153
1154 #[inline]
1155 pub fn background_color(mut self, background_color: Option<[u8; 4]>) -> Self {
1156 self.background_color = background_color;
1157 self
1158 }
1159
1160 #[inline]
1161 pub fn background_rounding(mut self, background_rounding: Option<f32>) -> Self {
1162 self.background_rounding = background_rounding;
1163 self
1164 }
1165
1166 #[inline]
1167 pub fn font(mut self, font: Option<String>) -> Self {
1168 self.font = font;
1169 self
1170 }
1171
1172 #[inline]
1173 pub fn selectable(mut self, selectable: Option<bool>) -> Self {
1174 self.selectable = selectable;
1175 self
1176 }
1177
1178 #[inline]
1179 pub fn hyperlink_text(
1180 mut self,
1181 hyperlink_text: Option<Vec<(String, HyperlinkSelectMethod)>>,
1182 ) -> Self {
1183 self.hyperlink_text = hyperlink_text;
1184 self
1185 }
1186
1187 #[inline]
1188 pub fn truncate(mut self, truncate: Option<bool>) -> Self {
1189 self.truncate = truncate;
1190 self
1191 }
1192
1193 #[inline]
1194 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
1195 self.tags = tags;
1196 self
1197 }
1198}
1199
1200#[derive(Debug, Clone, PartialEq, PartialOrd)]
1202pub struct Text {
1203 pub basic_front_resource_config: BasicFrontResourceConfig,
1205 pub display_info: DisplayInfo,
1207 pub content: String,
1209 pub font_size: f32,
1211 pub actual_size: [f32; 2],
1213 pub color: [u8; 4],
1215 pub background_color: [u8; 4],
1217 pub background_rounding: f32,
1219 pub font: String,
1221 pub selection: Option<(usize, usize)>,
1223 pub selectable: bool,
1225 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1227 pub hyperlink_index: Vec<(usize, usize, String)>,
1229 pub last_frame_content: String,
1231 pub truncate: bool,
1233 pub tags: Vec<[String; 2]>,
1235}
1236
1237impl RustConstructorResource for Text {
1238 fn as_any(&self) -> &dyn Any {
1239 self
1240 }
1241
1242 fn as_any_mut(&mut self) -> &mut dyn Any {
1243 self
1244 }
1245
1246 fn display_display_info(&self) -> Option<DisplayInfo> {
1247 Some(self.display_info)
1248 }
1249
1250 fn modify_display_info(&mut self, display_info: DisplayInfo) {
1251 self.display_info = display_info;
1252 }
1253
1254 fn display_tags(&self) -> Vec<[String; 2]> {
1255 self.tags.clone()
1256 }
1257
1258 fn modify_tags(&mut self, tags: &[[String; 2]]) {
1259 self.tags = tags.to_owned();
1260 }
1261}
1262
1263impl BasicFrontResource for Text {
1264 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
1265 self.basic_front_resource_config.clone()
1266 }
1267
1268 fn display_position_size_config(&self) -> PositionSizeConfig {
1269 self.basic_front_resource_config.position_size_config
1270 }
1271
1272 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
1273 self.basic_front_resource_config.clip_rect
1274 }
1275
1276 fn modify_basic_front_resource_config(
1277 &mut self,
1278 basic_front_resource_config: BasicFrontResourceConfig,
1279 ) {
1280 self.basic_front_resource_config = basic_front_resource_config;
1281 }
1282
1283 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
1284 self.basic_front_resource_config.position_size_config = position_size_config;
1285 }
1286
1287 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
1288 self.basic_front_resource_config.clip_rect = clip_rect;
1289 }
1290}
1291
1292impl Default for Text {
1293 fn default() -> Self {
1294 Self {
1295 basic_front_resource_config: BasicFrontResourceConfig::default(),
1296 display_info: DisplayInfo::default(),
1297 content: String::from("Hello world"),
1298 font_size: 16_f32,
1299 actual_size: [0_f32, 0_f32],
1300 color: [255, 255, 255, 255],
1301 background_color: [0, 0, 0, 0],
1302 background_rounding: 2_f32,
1303 font: String::new(),
1304 selection: None,
1305 selectable: true,
1306 hyperlink_text: Vec::new(),
1307 hyperlink_index: Vec::new(),
1308 last_frame_content: String::from(""),
1309 truncate: false,
1310 tags: Vec::new(),
1311 }
1312 }
1313}
1314
1315impl Text {
1316 pub fn from_config(mut self, config: &TextConfig) -> Self {
1317 if let Some(position_size_config) = config.position_size_config {
1318 self.basic_front_resource_config.position_size_config = position_size_config;
1319 };
1320 if let Some(clip_rect) = config.clip_rect {
1321 self.basic_front_resource_config.clip_rect = clip_rect;
1322 };
1323 if let Some(hidden) = config.hidden {
1324 self.display_info.hidden = hidden;
1325 };
1326 if let Some(ignore_render_layer) = config.ignore_render_layer {
1327 self.display_info.ignore_render_layer = ignore_render_layer;
1328 };
1329 if let Some(content) = config.content.clone() {
1330 self.content = content;
1331 };
1332 if let Some(font_size) = config.font_size {
1333 self.font_size = font_size;
1334 };
1335 if let Some(color) = config.color {
1336 self.color = color;
1337 };
1338 if let Some(background_color) = config.background_color {
1339 self.background_color = background_color;
1340 };
1341 if let Some(background_rounding) = config.background_rounding {
1342 self.background_rounding = background_rounding;
1343 };
1344 if let Some(font) = config.font.clone() {
1345 self.font = font;
1346 };
1347 if let Some(selectable) = config.selectable {
1348 self.selectable = selectable;
1349 };
1350 if let Some(hyperlink_text) = config.hyperlink_text.clone() {
1351 self.hyperlink_text = hyperlink_text;
1352 };
1353 if let Some(truncate) = config.truncate {
1354 self.truncate = truncate;
1355 };
1356 if let Some(tags) = config.tags.clone() {
1357 self.tags = tags;
1358 };
1359 self
1360 }
1361
1362 #[inline]
1363 pub fn basic_front_resource_config(
1364 mut self,
1365 basic_front_resource_config: &BasicFrontResourceConfig,
1366 ) -> Self {
1367 self.basic_front_resource_config = basic_front_resource_config.clone();
1368 self
1369 }
1370
1371 #[inline]
1372 pub fn hidden(mut self, hidden: bool) -> Self {
1373 self.display_info.hidden = hidden;
1374 self
1375 }
1376
1377 #[inline]
1378 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
1379 self.display_info.ignore_render_layer = ignore_render_layer;
1380 self
1381 }
1382
1383 #[inline]
1384 pub fn content(mut self, content: &str) -> Self {
1385 self.content = content.to_string();
1386 self
1387 }
1388
1389 #[inline]
1390 pub fn font_size(mut self, font_size: f32) -> Self {
1391 self.font_size = font_size;
1392 self
1393 }
1394
1395 #[inline]
1396 pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1397 self.color = [r, g, b, a];
1398 self
1399 }
1400
1401 #[inline]
1402 pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1403 self.background_color = [r, g, b, a];
1404 self
1405 }
1406
1407 #[inline]
1408 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1409 self.background_rounding = background_rounding;
1410 self
1411 }
1412
1413 #[inline]
1414 pub fn font(mut self, font: &str) -> Self {
1415 self.font = font.to_string();
1416 self
1417 }
1418
1419 #[inline]
1420 pub fn selectable(mut self, selectable: bool) -> Self {
1421 self.selectable = selectable;
1422 self
1423 }
1424
1425 #[inline]
1426 pub fn hyperlink_text(
1427 mut self,
1428 target_text: &str,
1429 select_method: HyperlinkSelectMethod,
1430 ) -> Self {
1431 self.hyperlink_text
1432 .push((target_text.to_string(), select_method));
1433 self
1434 }
1435
1436 #[inline]
1437 pub fn truncate(mut self, truncate: bool) -> Self {
1438 self.truncate = truncate;
1439 self
1440 }
1441
1442 #[inline]
1443 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
1444 self.tags = tags.to_owned();
1445 self
1446 }
1447}
1448
1449#[derive(Debug, Clone, PartialEq, PartialOrd)]
1451pub struct Variable<T> {
1452 pub value: Option<T>,
1454 pub tags: Vec<[String; 2]>,
1456}
1457
1458impl<T: Debug + 'static> RustConstructorResource for Variable<T> {
1459 fn as_any(&self) -> &dyn Any {
1460 self
1461 }
1462
1463 fn as_any_mut(&mut self) -> &mut dyn Any {
1464 self
1465 }
1466
1467 fn display_display_info(&self) -> Option<DisplayInfo> {
1468 None
1469 }
1470
1471 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1472
1473 fn display_tags(&self) -> Vec<[String; 2]> {
1474 self.tags.clone()
1475 }
1476
1477 fn modify_tags(&mut self, tags: &[[String; 2]]) {
1478 self.tags = tags.to_owned();
1479 }
1480}
1481
1482impl<T> Default for Variable<T> {
1483 fn default() -> Self {
1484 Variable {
1485 value: None,
1486 tags: Vec::new(),
1487 }
1488 }
1489}
1490
1491impl<T> Variable<T> {
1492 #[inline]
1493 pub fn value(mut self, value: Option<T>) -> Self {
1494 self.value = value;
1495 self
1496 }
1497
1498 #[inline]
1499 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
1500 self.tags = tags.to_owned();
1501 self
1502 }
1503}
1504
1505#[derive(Clone, Debug, Default, PartialEq)]
1507pub struct Font {
1508 pub font_definitions: FontDefinitions,
1510 pub path: String,
1512 pub tags: Vec<[String; 2]>,
1514}
1515
1516impl RustConstructorResource for Font {
1517 fn as_any(&self) -> &dyn Any {
1518 self
1519 }
1520
1521 fn as_any_mut(&mut self) -> &mut dyn Any {
1522 self
1523 }
1524
1525 fn display_display_info(&self) -> Option<DisplayInfo> {
1526 None
1527 }
1528
1529 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1530
1531 fn display_tags(&self) -> Vec<[String; 2]> {
1532 self.tags.clone()
1533 }
1534
1535 fn modify_tags(&mut self, tags: &[[String; 2]]) {
1536 self.tags = tags.to_owned();
1537 }
1538}
1539
1540impl Font {
1541 #[inline]
1542 pub fn path(mut self, path: &str) -> Self {
1543 self.path = path.to_string();
1544 self
1545 }
1546
1547 #[inline]
1548 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
1549 self.tags = tags.to_owned();
1550 self
1551 }
1552}
1553
1554#[derive(Debug, Clone, PartialEq, PartialOrd)]
1556pub struct SplitTime {
1557 pub time: [f32; 2],
1559 pub tags: Vec<[String; 2]>,
1561}
1562
1563impl RustConstructorResource for SplitTime {
1564 fn as_any(&self) -> &dyn Any {
1565 self
1566 }
1567
1568 fn as_any_mut(&mut self) -> &mut dyn Any {
1569 self
1570 }
1571
1572 fn display_display_info(&self) -> Option<DisplayInfo> {
1573 None
1574 }
1575
1576 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1577
1578 fn display_tags(&self) -> Vec<[String; 2]> {
1579 self.tags.clone()
1580 }
1581
1582 fn modify_tags(&mut self, tags: &[[String; 2]]) {
1583 self.tags = tags.to_owned();
1584 }
1585}
1586
1587impl Default for SplitTime {
1588 fn default() -> Self {
1589 Self {
1590 time: [0_f32, 0_f32],
1591 tags: Vec::new(),
1592 }
1593 }
1594}
1595
1596impl SplitTime {
1597 #[inline]
1598 pub fn tags(mut self, tags: &[[String; 2]]) -> Self {
1599 self.tags = tags.to_owned();
1600 self
1601 }
1602}
1603
1604#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1606pub struct RustConstructorError {
1607 pub error_id: String,
1609 pub description: String,
1611}
1612
1613impl Display for RustConstructorError {
1614 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1615 Debug::fmt(self, f)
1616 }
1617}
1618
1619impl Error for RustConstructorError {}
1620
1621#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1623pub enum HorizontalAlign {
1624 #[default]
1626 Left,
1627 Center,
1629 Right,
1631}
1632
1633#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1635pub enum VerticalAlign {
1636 #[default]
1638 Top,
1639 Center,
1641 Bottom,
1643}
1644
1645#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
1647pub enum RenderConfig {
1648 Line(f32, [u8; 4]),
1649 Rect([u8; 4], [u8; 4], [u8; 4], f32, BorderKind),
1650}
1651
1652#[derive(Debug, Clone, PartialEq)]
1654pub struct Event {
1655 pub id: String,
1657 pub description: String,
1659 pub tag: HashMap<String, String>,
1661 pub event_state: EventState,
1663 pub auto_delete: bool,
1665 pub handled: bool,
1667}
1668
1669#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1671pub struct DisplayInfo {
1672 pub enable: bool,
1674 pub hidden: bool,
1676 pub ignore_render_layer: bool,
1678}
1679
1680#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1682pub enum RequestMethod {
1683 Id(RustConstructorId),
1685 Citer(RustConstructorId),
1687}
1688
1689#[derive(Debug)]
1691pub struct App {
1692 pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
1694 pub tick_interval: f32,
1696 pub current_page: String,
1698 pub timer: Timer,
1700 pub frame_times: Vec<f32>,
1702 pub last_frame_time: Option<f32>,
1704 pub basic_front_resource_list: Vec<String>,
1706 pub render_layer: Vec<(RustConstructorId, [[f32; 2]; 2], bool)>,
1708 pub active_list: Vec<RustConstructorId>,
1710 pub render_list: Vec<RustConstructorId>,
1712 pub event_list: Vec<Event>,
1714 pub event_map: Vec<[String; 2]>,
1716}
1717
1718impl Default for App {
1719 fn default() -> Self {
1720 App {
1721 rust_constructor_resource: Vec::new(),
1722 tick_interval: 0.05,
1723 current_page: String::new(),
1724 timer: Timer::default(),
1725 frame_times: Vec::new(),
1726 last_frame_time: None,
1727 basic_front_resource_list: vec![
1728 String::from("rust_constructor::Image"),
1729 String::from("rust_constructor::Text"),
1730 String::from("rust_constructor::CustomRect"),
1731 ],
1732 render_layer: Vec::new(),
1733 active_list: Vec::new(),
1734 render_list: Vec::new(),
1735 event_list: Vec::new(),
1736 event_map: vec![
1737 [
1738 "rust_constructor::001".to_string(),
1739 "Attempting to create an external resource.".to_string(),
1740 ],
1741 [
1742 "rust_constructor::002".to_string(),
1743 "Attempting to remove an external resource.".to_string(),
1744 ],
1745 [
1746 "rust_constructor::003".to_string(),
1747 "Attempting to use an external resource.".to_string(),
1748 ],
1749 ],
1750 }
1751 }
1752}
1753
1754impl App {
1755 const PLACEHOLDER: [&str; 2] = ["PLACEHOLDER", "rust_constructor::Placeholder"];
1756 #[inline]
1757 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
1758 self.tick_interval = tick_interval;
1759 self
1760 }
1761
1762 #[inline]
1763 pub fn current_page(mut self, current_page: &str) -> Self {
1764 self.current_page = current_page.to_string();
1765 self
1766 }
1767
1768 pub fn add_event(&mut self, id: &str, tag: HashMap<&str, &str>, auto_delete: bool) {
1770 self.event_list.push(Event {
1771 id: id.to_string(),
1772 tag: tag
1773 .into_iter()
1774 .map(|s| (s.0.to_string(), s.1.to_string()))
1775 .collect(),
1776 description: if let Some(index) = self.event_map.iter().position(|x| x[0] == id) {
1777 self.event_map[index][1].clone()
1778 } else {
1779 "This event has no description.".to_string()
1780 },
1781 event_state: EventState {
1782 current_page: self.current_page.clone(),
1783 current_total_runtime: self.timer.total_time,
1784 current_page_runtime: self.timer.now_time,
1785 },
1786 auto_delete,
1787 handled: false,
1788 });
1789 }
1790
1791 pub fn update_event_list(&mut self) {
1793 let mut count = 0;
1794 for event in &mut self.event_list.clone() {
1795 if event.handled && event.auto_delete {
1796 self.event_list.remove(count);
1797 continue;
1798 };
1799 count += 1;
1800 }
1801 }
1802
1803 pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
1805 for i in 0..self.render_list.len() {
1806 #[allow(warnings)]
1807 self.draw_resource_by_index(ui, ctx, i);
1808 }
1809 }
1810
1811 pub fn draw_resource_by_index(
1813 &mut self,
1814 ui: &mut Ui,
1815 ctx: &Context,
1816 index: usize,
1817 ) -> Result<(), RustConstructorError> {
1818 if index < self.render_list.len() {
1819 let render_resource = &self.render_list.clone()[index];
1820 match &*render_resource.discern_type {
1821 "rust_constructor::Image" => {
1822 let image = self
1823 .get_resource::<Image>(&render_resource.name, "rust_constructor::Image")?;
1824 if image.display_info.enable {
1825 let mut image = image.clone();
1826 if image.cite_texture != image.last_frame_cite_texture {
1827 let image_texture = self.get_resource::<ImageTexture>(
1828 &image.cite_texture,
1829 "rust_constructor::ImageTexture",
1830 )?;
1831 image.texture = image_texture.texture.clone();
1832 };
1833 [
1834 image
1835 .basic_front_resource_config
1836 .position_size_config
1837 .position,
1838 image.basic_front_resource_config.position_size_config.size,
1839 ] = self.position_size_processor(
1840 image.basic_front_resource_config.position_size_config,
1841 ctx,
1842 );
1843 if !image.display_info.hidden {
1844 if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
1845 let [min, size] = self.position_size_processor(clip_rect, ctx);
1846 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
1847 };
1848 if let Some(texture) = &image.texture {
1849 let rect = Rect::from_min_size(
1850 Pos2::new(
1851 image
1852 .basic_front_resource_config
1853 .position_size_config
1854 .position[0],
1855 image
1856 .basic_front_resource_config
1857 .position_size_config
1858 .position[1],
1859 ),
1860 Vec2::new(
1861 image.basic_front_resource_config.position_size_config.size
1862 [0],
1863 image.basic_front_resource_config.position_size_config.size
1864 [1],
1865 ),
1866 );
1867
1868 egui::Image::new(ImageSource::Texture((&texture.0).into()))
1870 .tint(Color32::from_rgba_unmultiplied(
1871 image.overlay_color[0],
1872 image.overlay_color[1],
1873 image.overlay_color[2],
1874 (image.alpha as f32 * image.overlay_color[3] as f32 / 255.0)
1876 as u8,
1877 ))
1878 .bg_fill(Color32::from_rgba_unmultiplied(
1879 image.background_color[0],
1880 image.background_color[1],
1881 image.background_color[2],
1882 image.background_color[3],
1883 ))
1884 .rotate(
1885 image.rotate_angle,
1886 [
1887 image.rotate_center[0]
1888 / image
1889 .basic_front_resource_config
1890 .position_size_config
1891 .size[0],
1892 image.rotate_center[1]
1893 / image
1894 .basic_front_resource_config
1895 .position_size_config
1896 .size[1],
1897 ]
1898 .into(),
1899 )
1900 .paint_at(ui, rect)
1901 };
1902 if image.basic_front_resource_config.clip_rect.is_some() {
1903 ui.set_clip_rect(Rect::from_min_size(
1904 [0_f32, 0_f32].into(),
1905 [ctx.available_rect().width(), ctx.available_rect().height()]
1906 .into(),
1907 ));
1908 };
1909 };
1910 image.last_frame_cite_texture = image.cite_texture.clone();
1911 self.replace_resource(&render_resource.name, image)?;
1912 };
1913 }
1914 "rust_constructor::Text" => {
1915 let text =
1916 self.get_resource::<Text>(&render_resource.name, "rust_constructor::Text")?;
1917 if text.display_info.enable {
1918 let mut text = text.clone();
1919 [
1920 text.basic_front_resource_config
1921 .position_size_config
1922 .position,
1923 text.basic_front_resource_config.position_size_config.size,
1924 ] = self.position_size_processor(
1925 text.basic_front_resource_config.position_size_config,
1926 ctx,
1927 );
1928 let display_content = if text.truncate {
1929 let original_galley = ui.fonts_mut(|f| {
1930 f.layout(
1931 text.content.to_string(),
1932 FontId::proportional(text.font_size),
1933 Color32::default(),
1934 text.basic_front_resource_config.position_size_config.size[0],
1935 )
1936 });
1937
1938 let mut truncated = text.content.to_string();
1939 let mut ellipsis = "";
1940 if original_galley.size().y
1941 > text.basic_front_resource_config.position_size_config.size[1]
1942 {
1943 ellipsis = "...";
1945
1946 while !truncated.is_empty() {
1947 let test_text = format!("{}{}", truncated, ellipsis);
1948 let test_galley = ui.fonts_mut(|f| {
1949 f.layout(
1950 test_text,
1951 FontId::proportional(text.font_size),
1952 Color32::default(),
1953 text.basic_front_resource_config
1954 .position_size_config
1955 .size[0],
1956 )
1957 });
1958
1959 if test_galley.size().y
1960 <= text
1961 .basic_front_resource_config
1962 .position_size_config
1963 .size[1]
1964 {
1965 break;
1966 }
1967
1968 truncated.pop();
1970 }
1971 };
1972 format!("{}{}", truncated, ellipsis)
1973 } else {
1974 text.content.to_string()
1975 };
1976 let galley: Arc<Galley> = ui.fonts_mut(|f| {
1978 f.layout(
1979 display_content.to_string(),
1980 if !text.font.is_empty() {
1981 if self
1982 .check_resource_exists(&text.font, "rust_constructor::Font")
1983 .is_none()
1984 {
1985 FontId::new(
1986 text.font_size,
1987 FontFamily::Name(text.font.clone().into()),
1988 )
1989 } else {
1990 FontId::proportional(text.font_size)
1991 }
1992 } else {
1993 FontId::proportional(text.font_size)
1994 },
1995 Color32::from_rgba_unmultiplied(
1996 text.color[0],
1997 text.color[1],
1998 text.color[2],
1999 text.color[3],
2000 ),
2001 text.basic_front_resource_config.position_size_config.size[0],
2002 )
2003 });
2004 text.actual_size = [galley.size().x, galley.size().y];
2005 if text.last_frame_content != display_content {
2007 text.hyperlink_index.clear();
2008
2009 let byte_to_char_map: std::collections::HashMap<usize, usize> =
2011 display_content
2012 .char_indices()
2013 .enumerate()
2014 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2015 .collect();
2016
2017 for (hyperlink_text, method) in &text.hyperlink_text {
2018 let matches: Vec<(usize, &str)> =
2019 display_content.match_indices(hyperlink_text).collect();
2020 let text_char_count = hyperlink_text.chars().count();
2021
2022 if let HyperlinkSelectMethod::All(url) = method {
2023 for (byte_index, _) in matches {
2024 if let Some(&start_char_index) =
2025 byte_to_char_map.get(&byte_index)
2026 {
2027 text.hyperlink_index.push((
2028 start_char_index,
2029 start_char_index + text_char_count,
2030 url.clone(),
2031 ));
2032 };
2033 }
2034 } else if let HyperlinkSelectMethod::Segment(list) = method {
2035 for (index, url) in list {
2036 if *index >= matches.len() {
2037 continue;
2038 };
2039 let (byte_index, _) = matches[*index];
2040 if let Some(&start_char_index) =
2041 byte_to_char_map.get(&byte_index)
2042 {
2043 text.hyperlink_index.push((
2044 start_char_index,
2045 start_char_index + text_char_count,
2046 url.clone(),
2047 ));
2048 };
2049 }
2050 };
2051 }
2052 };
2053 if !text.display_info.hidden {
2054 let rect = Rect::from_min_size(
2056 text.basic_front_resource_config
2057 .position_size_config
2058 .position
2059 .into(),
2060 text.actual_size.into(),
2061 );
2062 ui.painter().rect_filled(
2064 rect,
2065 text.background_rounding,
2066 Color32::from_rgba_unmultiplied(
2067 text.background_color[0],
2068 text.background_color[1],
2069 text.background_color[2],
2070 text.background_color[3],
2071 ),
2072 );
2073
2074 if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2075 let [min, size] = self.position_size_processor(clip_rect, ctx);
2076 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2077 };
2078
2079 ui.painter().galley(
2081 text.basic_front_resource_config
2082 .position_size_config
2083 .position
2084 .into(),
2085 galley.clone(),
2086 Color32::from_rgba_unmultiplied(
2087 text.color[0],
2088 text.color[1],
2089 text.color[2],
2090 text.color[3],
2091 ),
2092 );
2093
2094 for (start, end, _) in &text.hyperlink_index {
2096 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2098 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2099
2100 let start_pos = start_cursor.left_top();
2101 let end_pos = end_cursor.right_top();
2102 if start_cursor.min.y == end_cursor.min.y {
2105 let underline_y = text
2107 .basic_front_resource_config
2108 .position_size_config
2109 .position[1]
2110 + start_pos.y
2111 + galley.rows.first().map_or(14.0, |row| row.height())
2112 - 2.0;
2113
2114 let color = Color32::from_rgba_unmultiplied(
2116 text.color[0],
2117 text.color[1],
2118 text.color[2],
2119 text.color[3],
2120 );
2121
2122 ui.painter().line_segment(
2123 [
2124 Pos2::new(
2125 text.basic_front_resource_config
2126 .position_size_config
2127 .position[0]
2128 + start_pos.x,
2129 underline_y,
2130 ),
2131 Pos2::new(
2132 text.basic_front_resource_config
2133 .position_size_config
2134 .position[0]
2135 + end_pos.x,
2136 underline_y,
2137 ),
2138 ],
2139 Stroke::new(text.font_size / 10_f32, color),
2140 );
2141 } else {
2142 let row_height =
2144 galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2148 let end_row = (end_pos.y / row_height).round() as usize;
2149
2150 for row in start_row..=end_row {
2151 let row_y = text
2152 .basic_front_resource_config
2153 .position_size_config
2154 .position[1]
2155 + row as f32 * row_height
2156 + row_height
2157 - 2.0; if let Some(current_row) = galley.rows.get(row) {
2161 let row_rect = current_row.rect();
2162
2163 let color = Color32::from_rgba_unmultiplied(
2164 text.color[0],
2165 text.color[1],
2166 text.color[2],
2167 text.color[3],
2168 );
2169
2170 if row == start_row {
2171 ui.painter().line_segment(
2173 [
2174 Pos2::new(
2175 text.basic_front_resource_config
2176 .position_size_config
2177 .position[0]
2178 + start_pos.x,
2179 row_y,
2180 ),
2181 Pos2::new(
2182 text.basic_front_resource_config
2183 .position_size_config
2184 .position[0]
2185 + row_rect.max.x,
2186 row_y,
2187 ),
2188 ],
2189 Stroke::new(text.font_size / 10_f32, color),
2190 );
2191 } else if row == end_row {
2192 ui.painter().line_segment(
2194 [
2195 Pos2::new(
2196 text.basic_front_resource_config
2197 .position_size_config
2198 .position[0]
2199 + row_rect.min.x,
2200 row_y,
2201 ),
2202 Pos2::new(
2203 text.basic_front_resource_config
2204 .position_size_config
2205 .position[0]
2206 + end_pos.x,
2207 row_y,
2208 ),
2209 ],
2210 Stroke::new(text.font_size / 10_f32, color),
2211 );
2212 } else {
2213 ui.painter().line_segment(
2215 [
2216 Pos2::new(
2217 text.basic_front_resource_config
2218 .position_size_config
2219 .position[0]
2220 + row_rect.min.x,
2221 row_y,
2222 ),
2223 Pos2::new(
2224 text.basic_front_resource_config
2225 .position_size_config
2226 .position[0]
2227 + row_rect.max.x,
2228 row_y,
2229 ),
2230 ],
2231 Stroke::new(text.font_size / 10_f32, color),
2232 );
2233 };
2234 };
2235 }
2236 };
2237 }
2238
2239 if text.selectable {
2240 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2242 let relative_pos = pointer_pos
2243 - text
2244 .basic_front_resource_config
2245 .position_size_config
2246 .position
2247 .into();
2248 let cursor = galley.cursor_from_pos(relative_pos);
2249 cursor.index
2250 };
2251
2252 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
2253 let rect = Rect::from_min_size(
2254 text.basic_front_resource_config
2255 .position_size_config
2256 .position
2257 .into(),
2258 text.actual_size.into(),
2259 );
2260 let detect_result = ui.interact(
2261 rect,
2262 Id::new(&render_resource.name),
2263 Sense::click_and_drag(),
2264 );
2265
2266 if !detect_result.clicked()
2267 && (fullscreen_detect_result.any_click()
2268 || fullscreen_detect_result.any_pressed())
2269 {
2270 text.selection = None;
2271 };
2272
2273 if let Some(index) = self.get_render_layer_resource(
2274 &render_resource.name,
2275 "rust_constructor::Text",
2276 ) && let Some(mouse_pos) =
2277 fullscreen_detect_result.interact_pos()
2278 && self.resource_get_focus(index, mouse_pos.into())
2279 && (detect_result.clicked() || detect_result.drag_started())
2280 {
2281 let cursor = cursor_at_pointer(mouse_pos.to_vec2());
2282 text.selection = Some((cursor, cursor));
2283 };
2284
2285 if detect_result.dragged()
2286 && text.selection.is_some()
2287 && let Some(pointer_pos) =
2288 ui.input(|i| i.pointer.interact_pos())
2289 {
2290 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
2291 if let Some((start, _)) = text.selection {
2292 text.selection = Some((start, cursor));
2293 };
2294 };
2295
2296 if text.selection.is_some()
2297 && ui.input(|input| {
2298 input.key_released(Key::A) && input.modifiers.command
2299 })
2300 {
2301 text.selection = Some((0, display_content.chars().count()));
2302 };
2303
2304 let copy_triggered = ui.input(|input| {
2306 let c_released = input.key_released(Key::C);
2307 let cmd_pressed = input.modifiers.command;
2308 c_released && cmd_pressed
2309 });
2310 if copy_triggered && let Some((start, end)) = text.selection {
2311 let (start, end) = (start.min(end), start.max(end));
2312 let chars: Vec<char> = display_content.chars().collect();
2313 if start <= chars.len() && end <= chars.len() && start < end {
2314 let selected_text: String =
2315 chars[start..end].iter().collect();
2316 ui.ctx().copy_text(selected_text);
2317 };
2318 };
2319
2320 if let Some((start, end)) = text.selection {
2322 let (start, end) = (start.min(end), start.max(end));
2323 if start != end {
2324 let start_cursor =
2326 galley.pos_from_cursor(CCursor::new(start));
2327 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
2328
2329 let start_pos = start_cursor.left_top();
2330 let end_pos = end_cursor.right_top();
2331 if start_pos.y == end_pos.y {
2333 let rows = &galley.rows;
2335 let row_height = if !rows.is_empty() {
2336 if let Some(row) = rows.first() {
2338 row.height()
2339 } else {
2340 text.actual_size[1]
2341 / display_content.lines().count() as f32
2342 }
2343 } else {
2344 text.actual_size[1]
2345 / display_content.lines().count() as f32
2346 };
2347
2348 let selection_rect = Rect::from_min_max(
2349 Pos2::new(
2350 text.basic_front_resource_config
2351 .position_size_config
2352 .position[0]
2353 + start_pos.x,
2354 text.basic_front_resource_config
2355 .position_size_config
2356 .position[1]
2357 + start_pos.y,
2358 ),
2359 Pos2::new(
2360 text.basic_front_resource_config
2361 .position_size_config
2362 .position[0]
2363 + end_pos.x,
2364 text.basic_front_resource_config
2365 .position_size_config
2366 .position[1]
2367 + start_pos.y
2368 + row_height,
2369 ),
2370 );
2371 ui.painter().rect_filled(
2372 selection_rect,
2373 0.0,
2374 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2375 );
2376 } else {
2377 let rows = &galley.rows;
2379 let row_height = if !rows.is_empty() {
2380 rows[0].height()
2381 } else {
2382 text.actual_size[1]
2383 / display_content.lines().count() as f32
2384 };
2385
2386 let selection_top = text
2388 .basic_front_resource_config
2389 .position_size_config
2390 .position[1]
2391 + start_pos.y.min(end_pos.y);
2392 let selection_bottom = text
2393 .basic_front_resource_config
2394 .position_size_config
2395 .position[1]
2396 + start_pos.y.max(end_pos.y);
2397
2398 let start_row_index =
2400 (start_pos.y / row_height).floor() as usize;
2401 let end_row_index =
2402 (end_pos.y / row_height).floor() as usize;
2403 let (first_row_index, last_row_index) =
2404 if start_row_index <= end_row_index {
2405 (start_row_index, end_row_index)
2406 } else {
2407 (end_row_index, start_row_index)
2408 };
2409
2410 for (i, row) in rows.iter().enumerate() {
2411 let row_y = text
2412 .basic_front_resource_config
2413 .position_size_config
2414 .position[1]
2415 + row_height * i as f32;
2416 let row_bottom = row_y + row_height;
2417 if row_bottom > selection_top
2419 && row_y <= selection_bottom
2420 {
2421 let left = if i == first_row_index {
2422 text.basic_front_resource_config
2424 .position_size_config
2425 .position[0]
2426 + start_pos.x
2427 } else {
2428 text.basic_front_resource_config
2430 .position_size_config
2431 .position[0]
2432 + row.rect().min.x
2433 };
2434
2435 let right = if i == last_row_index {
2436 text.basic_front_resource_config
2438 .position_size_config
2439 .position[0]
2440 + end_pos.x
2441 } else {
2442 text.basic_front_resource_config
2444 .position_size_config
2445 .position[0]
2446 + row.rect().max.x
2447 };
2448
2449 let selection_rect = Rect::from_min_max(
2450 Pos2::new(left, row_y),
2451 Pos2::new(right, row_bottom),
2452 );
2453
2454 if selection_rect.width() > 0.0
2456 && selection_rect.height() > 0.0
2457 {
2458 ui.painter().rect_filled(
2459 selection_rect,
2460 0.0,
2461 Color32::from_rgba_unmultiplied(
2462 0, 120, 255, 100,
2463 ),
2464 );
2465 };
2466 };
2467 }
2468 };
2469 };
2470 };
2471 };
2472
2473 for (start, end, url) in &text.hyperlink_index {
2475 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2477 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2478
2479 let start_pos = start_cursor.left_top();
2480 let end_pos = end_cursor.right_top();
2481
2482 let row_height =
2483 galley.rows.first().map_or(14.0, |row| row.height());
2484
2485 let link_responses = if start_cursor.min.y == end_cursor.min.y {
2487 let link_rect = Rect::from_min_max(
2489 Pos2::new(
2490 text.basic_front_resource_config
2491 .position_size_config
2492 .position[0]
2493 + start_pos.x,
2494 text.basic_front_resource_config
2495 .position_size_config
2496 .position[1]
2497 + start_pos.y,
2498 ),
2499 Pos2::new(
2500 text.basic_front_resource_config
2501 .position_size_config
2502 .position[0]
2503 + end_pos.x,
2504 text.basic_front_resource_config
2505 .position_size_config
2506 .position[1]
2507 + start_pos.y
2508 + row_height,
2509 ),
2510 );
2511 vec![ui.interact(
2512 link_rect,
2513 egui::Id::new(format!(
2514 "link_{}_{}_{}",
2515 render_resource.name, start, end
2516 )),
2517 egui::Sense::click(),
2518 )]
2519 } else {
2520 let start_row = (start_pos.y / row_height).round() as usize;
2522 let end_row = (end_pos.y / row_height).round() as usize;
2523 let mut responses = Vec::new();
2524
2525 for row in start_row..=end_row {
2526 if let Some(current_row) = galley.rows.get(row) {
2527 let row_rect = current_row.rect();
2528 let row_y = text
2529 .basic_front_resource_config
2530 .position_size_config
2531 .position[1]
2532 + row as f32 * row_height;
2533
2534 let link_rect = if row == start_row {
2535 Rect::from_min_max(
2537 Pos2::new(
2538 text.basic_front_resource_config
2539 .position_size_config
2540 .position[0]
2541 + start_pos.x,
2542 row_y,
2543 ),
2544 Pos2::new(
2545 text.basic_front_resource_config
2546 .position_size_config
2547 .position[0]
2548 + row_rect.max.x,
2549 row_y + row_height,
2550 ),
2551 )
2552 } else if row == end_row {
2553 Rect::from_min_max(
2555 Pos2::new(
2556 text.basic_front_resource_config
2557 .position_size_config
2558 .position[0]
2559 + row_rect.min.x,
2560 row_y,
2561 ),
2562 Pos2::new(
2563 text.basic_front_resource_config
2564 .position_size_config
2565 .position[0]
2566 + end_pos.x,
2567 row_y + row_height,
2568 ),
2569 )
2570 } else {
2571 Rect::from_min_max(
2573 Pos2::new(
2574 text.basic_front_resource_config
2575 .position_size_config
2576 .position[0]
2577 + row_rect.min.x,
2578 row_y,
2579 ),
2580 Pos2::new(
2581 text.basic_front_resource_config
2582 .position_size_config
2583 .position[0]
2584 + row_rect.max.x,
2585 row_y + row_height,
2586 ),
2587 )
2588 };
2589
2590 responses.push(ui.interact(
2591 link_rect,
2592 Id::new(format!(
2593 "link_{}_{}_{}_row_{}",
2594 render_resource.name, start, end, row
2595 )),
2596 Sense::click(),
2597 ));
2598 };
2599 }
2600 responses
2601 };
2602
2603 let mut is_pressing_link = false;
2605 for link_response in &link_responses {
2606 if let Some(index) = self.get_render_layer_resource(
2607 &render_resource.name,
2608 "rust_constructor::Text",
2609 ) && let Some(mouse_pos) =
2610 ui.input(|i| i.pointer.interact_pos())
2611 && self.resource_get_focus(index, mouse_pos.into())
2612 {
2613 if link_response.is_pointer_button_down_on()
2614 && !link_response.drag_started()
2615 {
2616 text.selection = None;
2617 if let Some(pointer_pos) =
2618 ui.input(|i| i.pointer.interact_pos())
2619 {
2620 let relative_pos = pointer_pos
2621 - <[f32; 2] as Into<Pos2>>::into(
2622 text.basic_front_resource_config
2623 .position_size_config
2624 .position,
2625 );
2626 let cursor = galley.cursor_from_pos(relative_pos);
2627 if cursor.index >= *start && cursor.index <= *end {
2628 is_pressing_link = true;
2629 break;
2630 };
2631 };
2632 };
2633 let mut clicked_on_link = false;
2635 for link_response in &link_responses {
2636 if link_response.clicked()
2637 && let Some(pointer_pos) =
2638 ui.input(|i| i.pointer.interact_pos())
2639 {
2640 let relative_pos = pointer_pos
2641 - <[f32; 2] as Into<Pos2>>::into(
2642 text.basic_front_resource_config
2643 .position_size_config
2644 .position,
2645 );
2646 let cursor = galley.cursor_from_pos(relative_pos);
2647 if cursor.index >= *start && cursor.index <= *end {
2648 clicked_on_link = true;
2649 break;
2650 };
2651 };
2652 }
2653
2654 if clicked_on_link {
2655 if !url.is_empty() {
2657 ui.ctx().open_url(OpenUrl::new_tab(url));
2658 };
2659 };
2660 };
2661 }
2662
2663 if is_pressing_link {
2665 if start_cursor.min.y == end_cursor.min.y {
2666 let selection_rect = Rect::from_min_max(
2668 Pos2::new(
2669 text.basic_front_resource_config
2670 .position_size_config
2671 .position[0]
2672 + start_pos.x,
2673 text.basic_front_resource_config
2674 .position_size_config
2675 .position[1]
2676 + start_pos.y,
2677 ),
2678 Pos2::new(
2679 text.basic_front_resource_config
2680 .position_size_config
2681 .position[0]
2682 + end_pos.x,
2683 text.basic_front_resource_config
2684 .position_size_config
2685 .position[1]
2686 + start_pos.y
2687 + galley
2688 .rows
2689 .first()
2690 .map_or(14.0, |row| row.height()),
2691 ),
2692 );
2693 ui.painter().rect_filled(
2694 selection_rect,
2695 0.0,
2696 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2697 );
2698 } else {
2699 let row_height =
2701 galley.rows.first().map_or(14.0, |row| row.height());
2702 let start_row = (start_pos.y / row_height).round() as usize;
2703 let end_row = (end_pos.y / row_height).round() as usize;
2704
2705 for row in start_row..=end_row {
2706 if let Some(current_row) = galley.rows.get(row) {
2707 let row_rect = current_row.rect();
2708
2709 if row == start_row {
2710 let selection_rect = Rect::from_min_max(
2712 Pos2::new(
2713 text.basic_front_resource_config
2714 .position_size_config
2715 .position[0]
2716 + start_pos.x,
2717 text.basic_front_resource_config
2718 .position_size_config
2719 .position[1]
2720 + row as f32 * row_height,
2721 ),
2722 Pos2::new(
2723 text.basic_front_resource_config
2724 .position_size_config
2725 .position[0]
2726 + row_rect.max.x,
2727 text.basic_front_resource_config
2728 .position_size_config
2729 .position[1]
2730 + row as f32 * row_height
2731 + row_height,
2732 ),
2733 );
2734 ui.painter().rect_filled(
2735 selection_rect,
2736 0.0,
2737 Color32::from_rgba_unmultiplied(
2738 0, 120, 255, 100,
2739 ),
2740 );
2741 } else if row == end_row {
2742 let selection_rect = Rect::from_min_max(
2744 Pos2::new(
2745 text.basic_front_resource_config
2746 .position_size_config
2747 .position[0]
2748 + row_rect.min.x,
2749 text.basic_front_resource_config
2750 .position_size_config
2751 .position[1]
2752 + row as f32 * row_height,
2753 ),
2754 Pos2::new(
2755 text.basic_front_resource_config
2756 .position_size_config
2757 .position[0]
2758 + end_pos.x,
2759 text.basic_front_resource_config
2760 .position_size_config
2761 .position[1]
2762 + row as f32 * row_height
2763 + row_height,
2764 ),
2765 );
2766 ui.painter().rect_filled(
2767 selection_rect,
2768 0.0,
2769 Color32::from_rgba_unmultiplied(
2770 0, 120, 255, 100,
2771 ),
2772 );
2773 } else {
2774 let selection_rect = Rect::from_min_max(
2776 Pos2::new(
2777 text.basic_front_resource_config
2778 .position_size_config
2779 .position[0]
2780 + row_rect.min.x,
2781 text.basic_front_resource_config
2782 .position_size_config
2783 .position[1]
2784 + row as f32 * row_height,
2785 ),
2786 Pos2::new(
2787 text.basic_front_resource_config
2788 .position_size_config
2789 .position[0]
2790 + row_rect.max.x,
2791 text.basic_front_resource_config
2792 .position_size_config
2793 .position[1]
2794 + row as f32 * row_height
2795 + row_height,
2796 ),
2797 );
2798 ui.painter().rect_filled(
2799 selection_rect,
2800 0.0,
2801 Color32::from_rgba_unmultiplied(
2802 0, 120, 255, 100,
2803 ),
2804 );
2805 };
2806 };
2807 }
2808 };
2809 };
2810 }
2811 if text.basic_front_resource_config.clip_rect.is_some() {
2812 ui.set_clip_rect(Rect::from_min_size(
2813 [0_f32, 0_f32].into(),
2814 [ctx.available_rect().width(), ctx.available_rect().height()]
2815 .into(),
2816 ));
2817 };
2818 } else {
2819 text.selection = None;
2820 };
2821 text.last_frame_content = display_content;
2822 self.replace_resource(&render_resource.name, text)?;
2823 };
2824 }
2825 "rust_constructor::CustomRect" => {
2826 let custom_rect = self.get_resource::<CustomRect>(
2827 &render_resource.name,
2828 "rust_constructor::CustomRect",
2829 )?;
2830 if custom_rect.display_info.enable {
2831 let mut custom_rect = custom_rect.clone();
2832 [
2833 custom_rect
2834 .basic_front_resource_config
2835 .position_size_config
2836 .position,
2837 custom_rect
2838 .basic_front_resource_config
2839 .position_size_config
2840 .size,
2841 ] = self.position_size_processor(
2842 custom_rect.basic_front_resource_config.position_size_config,
2843 ctx,
2844 );
2845 if !custom_rect.display_info.hidden {
2846 if let Some(clip_rect) =
2847 custom_rect.basic_front_resource_config.clip_rect
2848 {
2849 let [min, size] = self.position_size_processor(clip_rect, ctx);
2850 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2851 };
2852 ui.painter().rect(
2853 Rect::from_min_max(
2854 Pos2::new(
2855 custom_rect
2856 .basic_front_resource_config
2857 .position_size_config
2858 .position[0],
2859 custom_rect
2860 .basic_front_resource_config
2861 .position_size_config
2862 .position[1],
2863 ),
2864 Pos2::new(
2865 custom_rect
2866 .basic_front_resource_config
2867 .position_size_config
2868 .position[0]
2869 + custom_rect
2870 .basic_front_resource_config
2871 .position_size_config
2872 .size[0],
2873 custom_rect
2874 .basic_front_resource_config
2875 .position_size_config
2876 .position[1]
2877 + custom_rect
2878 .basic_front_resource_config
2879 .position_size_config
2880 .size[1],
2881 ),
2882 ),
2883 custom_rect.rounding,
2884 Color32::from_rgba_unmultiplied(
2885 custom_rect.color[0],
2886 custom_rect.color[1],
2887 custom_rect.color[2],
2888 custom_rect.color[3],
2889 ),
2890 Stroke {
2891 width: custom_rect.border_width,
2892 color: Color32::from_rgba_unmultiplied(
2893 custom_rect.border_color[0],
2894 custom_rect.border_color[1],
2895 custom_rect.border_color[2],
2896 custom_rect.border_color[3],
2897 ),
2898 },
2899 match custom_rect.border_kind {
2900 BorderKind::Inside => StrokeKind::Inside,
2901 BorderKind::Middle => StrokeKind::Middle,
2902 BorderKind::Outside => StrokeKind::Outside,
2903 },
2904 );
2905 if custom_rect.basic_front_resource_config.clip_rect.is_some() {
2906 ui.set_clip_rect(Rect::from_min_size(
2907 [0_f32, 0_f32].into(),
2908 [ctx.available_rect().width(), ctx.available_rect().height()]
2909 .into(),
2910 ));
2911 };
2912 };
2913 self.replace_resource(&render_resource.name, custom_rect)?;
2914 };
2915 }
2916 _ => {
2917 unreachable!()
2918 }
2919 }
2920 Ok(())
2921 } else {
2922 Err(RustConstructorError {
2923 error_id: "IndexOutOfRange".to_string(),
2924 description: format!(
2925 "The maximum index of the target list is {}, but the index is {index}.",
2926 self.render_list.len() - 1
2927 ),
2928 })
2929 }
2930 }
2931
2932 pub fn active_list_info(&self, display_complex_info: bool, format: bool) -> String {
2934 let mut text = String::from("Resource Active Info:\n");
2935 for info in &self.active_list {
2936 if display_complex_info {
2937 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
2938 text += &if format {
2939 format!(
2940 "\nName: {}\nType: {}\nDetail: {:#?}\n",
2941 info.name, info.discern_type, self.rust_constructor_resource[index],
2942 )
2943 } else {
2944 format!(
2945 "\nName: {}\nType: {}\nDetail: {:?}\n",
2946 info.name, info.discern_type, self.rust_constructor_resource[index],
2947 )
2948 };
2949 };
2950 } else {
2951 text += &format!("\nName: {}\nType: {}\n", info.name, info.discern_type);
2952 };
2953 }
2954 text
2955 }
2956
2957 pub fn render_layer_info(&self) -> String {
2959 let mut text = String::from("Render Layer Info:\n");
2960 for (
2961 RustConstructorId { name, discern_type },
2962 [min_position, max_position],
2963 ignore_render_layer,
2964 ) in &self.render_layer
2965 {
2966 text += &format!(
2967 "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
2968 name, discern_type, min_position, max_position, ignore_render_layer
2969 );
2970 }
2971 text
2972 }
2973
2974 pub fn render_list_info(&self) -> String {
2976 let mut text = String::from("Render List Info:\n");
2977 for RustConstructorId { name, discern_type } in &self.render_list {
2978 text += &format!("\nName: {:?}\nType: {:?}\n", name, discern_type);
2979 }
2980 text
2981 }
2982
2983 pub fn update_render_list(&mut self) {
2985 if self.render_list.is_empty() {
2986 for info in &self.active_list {
2987 if self.basic_front_resource_list.contains(&info.discern_type) {
2988 self.render_list.push(RustConstructorId {
2989 name: info.name.clone(),
2990 discern_type: info.discern_type.clone(),
2991 });
2992 };
2993 }
2994 } else {
2995 let mut count = 0;
2996 for render_resource in &self.render_list.clone() {
2997 if !self.active_list.contains(render_resource) {
2998 self.render_list.remove(count);
2999 } else {
3000 count += 1;
3001 };
3002 }
3003 let mut insert_index = 0;
3004 for info in &self.active_list {
3005 if self.basic_front_resource_list.contains(&info.discern_type) {
3006 if !self.render_list.contains(info) {
3007 self.render_list.insert(
3008 insert_index,
3009 RustConstructorId {
3010 name: info.name.clone(),
3011 discern_type: info.discern_type.clone(),
3012 },
3013 );
3014 } else {
3015 insert_index += 1;
3016 }
3017 };
3018 }
3019 };
3020 }
3021
3022 pub fn unsafe_request_jump_render_list(&mut self, requester: RequestMethod) {
3024 #[allow(warnings)]
3025 self.request_jump_render_list(requester);
3026 }
3027
3028 pub fn request_jump_render_list(
3030 &mut self,
3031 requester: RequestMethod,
3032 ) -> Result<(), RustConstructorError> {
3033 match requester {
3034 RequestMethod::Id(RustConstructorId { name, discern_type }) => {
3035 if let Some(index) = self
3036 .render_list
3037 .iter()
3038 .position(|x| x.name == name && x.discern_type == discern_type)
3039 {
3040 self.render_list.remove(index);
3041 self.render_list
3042 .push(RustConstructorId { name, discern_type });
3043 Ok(())
3044 } else {
3045 Err(RustConstructorError {
3046 error_id: "RenderResourceNotFound".to_string(),
3047 description: format!(
3048 "Render resource \"{name}({discern_type})\" not found.",
3049 ),
3050 })
3051 }
3052 }
3053 RequestMethod::Citer(RustConstructorId { name, discern_type }) => {
3054 for (i, render_resource) in self.render_list.iter().enumerate() {
3055 let tags = self
3056 .get_box_resource(&render_resource.name, &render_resource.discern_type)?
3057 .display_tags();
3058 if let [Some(tag_name), Some(tag_type)] = [
3059 tags.iter().find(|x| x[0] == "citer_name"),
3060 tags.iter().find(|x| x[0] == "citer_type"),
3061 ] && tag_name[1] == name
3062 && tag_type[1] == discern_type
3063 {
3064 self.render_list.remove(i);
3065 self.render_list
3066 .push(RustConstructorId { name, discern_type });
3067 return Ok(());
3068 };
3069 }
3070 Err(RustConstructorError {
3071 error_id: "RenderResourceNotFound".to_string(),
3072 description: format!("Render resource \"{name}({discern_type})\" not found.",),
3073 })
3074 }
3075 }
3076 }
3077
3078 pub fn update_render_layer(&mut self) {
3080 self.render_layer.clear();
3081 for info in &self.render_list {
3082 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3083 let basic_front_resource: Box<dyn BasicFrontResource> = match &*info.discern_type {
3084 "rust_constructor::Image" => Box::new(
3085 self.rust_constructor_resource[index]
3086 .content
3087 .as_any()
3088 .downcast_ref::<Image>()
3089 .unwrap()
3090 .clone(),
3091 ),
3092 "rust_constructor::Text" => Box::new(
3093 self.rust_constructor_resource[index]
3094 .content
3095 .as_any()
3096 .downcast_ref::<Text>()
3097 .unwrap()
3098 .clone(),
3099 ),
3100 "rust_constructor::CustomRect" => Box::new(
3101 self.rust_constructor_resource[index]
3102 .content
3103 .as_any()
3104 .downcast_ref::<CustomRect>()
3105 .unwrap()
3106 .clone(),
3107 ),
3108 _ => {
3109 unreachable!()
3110 }
3111 };
3112 if let Some(display_info) = basic_front_resource.display_display_info() {
3113 self.render_layer.push((
3114 info.clone(),
3115 [
3116 basic_front_resource.display_position_size_config().position,
3117 [
3118 basic_front_resource.display_position_size_config().position[0]
3119 + basic_front_resource.display_position_size_config().size[0],
3120 basic_front_resource.display_position_size_config().position[1]
3121 + basic_front_resource.display_position_size_config().size[1],
3122 ],
3123 ],
3124 display_info.ignore_render_layer,
3125 ));
3126 };
3127 };
3128 }
3129 }
3130
3131 pub fn display_render_layer(
3133 &self,
3134 ui: &mut Ui,
3135 render_config: &RenderConfig,
3136 ignore_render_config: &RenderConfig,
3137 ) {
3138 for (_, point, ignore_render_layer) in &self.render_layer {
3139 match if *ignore_render_layer {
3140 ignore_render_config
3141 } else {
3142 render_config
3143 } {
3144 RenderConfig::Rect(
3145 corner_radius,
3146 fill_color,
3147 border_color,
3148 border_width,
3149 border_kind,
3150 ) => {
3151 let rect = Rect::from_min_max(point[0].into(), point[1].into());
3152 ui.painter().rect(
3153 rect,
3154 CornerRadius {
3155 nw: corner_radius[0],
3156 ne: corner_radius[1],
3157 sw: corner_radius[2],
3158 se: corner_radius[3],
3159 },
3160 Color32::from_rgba_unmultiplied(
3161 fill_color[0],
3162 fill_color[1],
3163 fill_color[2],
3164 fill_color[3],
3165 ),
3166 Stroke::new(
3167 *border_width,
3168 Color32::from_rgba_unmultiplied(
3169 border_color[0],
3170 border_color[1],
3171 border_color[2],
3172 border_color[3],
3173 ),
3174 ),
3175 match *border_kind {
3176 BorderKind::Inside => StrokeKind::Inside,
3177 BorderKind::Middle => StrokeKind::Middle,
3178 BorderKind::Outside => StrokeKind::Outside,
3179 },
3180 );
3181 }
3182 RenderConfig::Line(width, color) => {
3183 ui.painter().line_segment(
3184 [point[0].into(), point[1].into()],
3185 Stroke::new(
3186 *width,
3187 Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3188 ),
3189 );
3190 }
3191 };
3192 }
3193 }
3194
3195 pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3197 self.render_layer
3198 .iter()
3199 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
3200 }
3201
3202 pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3204 for i in index + 1..self.render_layer.len() {
3205 let point = self.render_layer[i].1;
3206 if mouse_pos[0] > point[0][0]
3207 && mouse_pos[1] > point[0][1]
3208 && mouse_pos[0] < point[1][0]
3209 && mouse_pos[1] < point[1][1]
3210 && !self.render_layer[i].2
3211 {
3212 return false;
3213 };
3214 }
3215 true
3216 }
3217
3218 pub fn add_active_resource(
3220 &mut self,
3221 name: &str,
3222 discern_type: &str,
3223 ) -> Result<(), RustConstructorError> {
3224 let is_placeholder = name == Self::PLACEHOLDER[0] && discern_type == Self::PLACEHOLDER[1];
3225 if self.check_resource_exists(name, discern_type).is_some() || is_placeholder {
3226 if let Some(index) = self.active_list.iter().position(|x| {
3227 x.name == Self::PLACEHOLDER[0] && x.discern_type == Self::PLACEHOLDER[1]
3228 }) && !is_placeholder
3229 {
3230 self.active_list.remove(index);
3231 self.active_list.insert(
3232 index,
3233 RustConstructorId {
3234 name: name.to_string(),
3235 discern_type: discern_type.to_string(),
3236 },
3237 );
3238 } else {
3239 self.active_list.push(RustConstructorId {
3240 name: name.to_string(),
3241 discern_type: discern_type.to_string(),
3242 });
3243 };
3244 Ok(())
3245 } else {
3246 Err(RustConstructorError {
3247 error_id: "ResourceNotFound".to_string(),
3248 description: format!("Resource \"{name}({discern_type})\" not found."),
3249 })
3250 }
3251 }
3252
3253 pub fn add_resource<T: RustConstructorResource + 'static>(
3255 &mut self,
3256 name: &str,
3257 mut resource: T,
3258 ) -> Result<(), RustConstructorError> {
3259 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3260 list.0
3261 } else {
3262 type_name_of_val(&resource)
3263 };
3264 if self.check_resource_exists(name, discern_type).is_some() {
3265 return Err(RustConstructorError {
3266 error_id: "ResourceNameRepetition".to_string(),
3267 description: format!("Resource \"{name}({discern_type})\" has already existed."),
3268 });
3269 };
3270 if name.is_empty() {
3271 return Err(RustConstructorError {
3272 error_id: "ResourceUntitled".to_string(),
3273 description: "All resources must have a valid name.".to_string(),
3274 });
3275 };
3276 match discern_type {
3277 "rust_constructor::PageData" => {}
3278 "rust_constructor::CustomRect" => {}
3279 "rust_constructor::Text" => {}
3280 "rust_constructor::Variable" => {}
3281 "rust_constructor::SplitTime" => {
3282 if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3283 split_time.time = [self.timer.now_time, self.timer.total_time];
3284 };
3285 }
3286 "rust_constructor::ImageTexture" => {
3287 if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3288 if let Ok(mut file) = File::open(&image_texture.cite_path) {
3289 let mut buffer = Vec::new();
3290 file.read_to_end(&mut buffer).unwrap();
3291 let img_bytes = buffer;
3292 let img = image::load_from_memory(&img_bytes).unwrap();
3293 let color_data = match image_texture.flip {
3294 [true, true] => img.fliph().flipv().into_rgba8(),
3295 [true, false] => img.fliph().into_rgba8(),
3296 [false, true] => img.flipv().into_rgba8(),
3297 _ => img.into_rgba8(),
3298 };
3299 let (w, h) = (color_data.width(), color_data.height());
3300 let raw_data: Vec<u8> = color_data.into_raw();
3301
3302 let color_image =
3303 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3304 let loaded_image_texture = image_texture.context.load_texture(
3305 name,
3306 color_image,
3307 TextureOptions::LINEAR,
3308 );
3309 image_texture.texture =
3310 Some(DebugTextureHandle::new(&loaded_image_texture));
3311 image_texture.cite_path = image_texture.cite_path.to_string();
3312 } else {
3313 return Err(RustConstructorError {
3314 error_id: "ImageLoadFailed".to_string(),
3315 description: format!(
3316 "Failed to load an image from the path \"{}\".",
3317 image_texture.cite_path
3318 ),
3319 });
3320 };
3321 };
3322 }
3323 "rust_constructor::Image" => {
3324 if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3325 let image_texture = self.get_resource::<ImageTexture>(
3326 &image.cite_texture,
3327 "rust_constructor::ImageTexture",
3328 )?;
3329 image.texture = image_texture.texture.clone();
3330 image.last_frame_cite_texture = image.cite_texture.clone();
3331 };
3332 }
3333 "rust_constructor::Font" => {
3334 if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3335 let mut fonts = FontDefinitions::default();
3336 if let Ok(font_read_data) = read(&font.path) {
3337 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3338 fonts.font_data.insert(
3339 name.to_owned(),
3340 Arc::new(FontData::from_owned(
3341 Arc::try_unwrap(font_data).ok().unwrap(),
3342 )),
3343 );
3344
3345 fonts
3347 .families
3348 .entry(FontFamily::Proportional)
3349 .or_default()
3350 .insert(0, name.to_owned());
3351
3352 fonts
3353 .families
3354 .entry(FontFamily::Monospace)
3355 .or_default()
3356 .insert(0, name.to_owned());
3357
3358 font.font_definitions = fonts;
3359 } else {
3360 return Err(RustConstructorError {
3361 error_id: "FontLoadFailed".to_string(),
3362 description: format!(
3363 "Failed to load a font from the path \"{}\".",
3364 font.path
3365 ),
3366 });
3367 }
3368 };
3369 }
3370 _ => {
3371 let mut tag = HashMap::new();
3372 tag.insert("name", name);
3373 tag.insert("type", discern_type);
3374 self.add_event("rust_constructor::001", tag, false);
3375 }
3376 };
3377 self.rust_constructor_resource
3378 .push(RustConstructorResourceBox::new(
3379 name,
3380 discern_type,
3381 Box::new(resource),
3382 ));
3383 Ok(())
3384 }
3385
3386 pub fn drop_resource(
3388 &mut self,
3389 name: &str,
3390 discern_type: &str,
3391 ) -> Result<(), RustConstructorError> {
3392 if let Some(index) = self.check_resource_exists(name, discern_type) {
3393 self.rust_constructor_resource.remove(index);
3394 if let Some(index) = self
3395 .active_list
3396 .iter()
3397 .position(|x| x.name == name && x.discern_type == discern_type)
3398 {
3399 self.active_list.remove(index);
3400 };
3401 if let Some(index) = self
3402 .render_layer
3403 .iter()
3404 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
3405 {
3406 self.render_layer.remove(index);
3407 };
3408 let mut tag = HashMap::new();
3409 tag.insert("name", name);
3410 tag.insert("type", discern_type);
3411 self.add_event("rust_constructor::002", tag, false);
3412 Ok(())
3413 } else {
3414 Err(RustConstructorError {
3415 error_id: "ResourceNotFound".to_string(),
3416 description: format!("Resource \"{name}({discern_type})\" not found."),
3417 })
3418 }
3419 }
3420
3421 pub fn replace_resource<T>(
3423 &mut self,
3424 name: &str,
3425 resource: T,
3426 ) -> Result<(), RustConstructorError>
3427 where
3428 T: RustConstructorResource + 'static,
3429 {
3430 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3431 list.0
3432 } else {
3433 type_name_of_val(&resource)
3434 };
3435 if let Some(index) = self.check_resource_exists(name, discern_type) {
3436 self.rust_constructor_resource[index] =
3437 RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
3438 Ok(())
3439 } else {
3440 Err(RustConstructorError {
3441 error_id: "ResourceNotFound".to_string(),
3442 description: format!("Resource \"{name}({discern_type})\" not found."),
3443 })
3444 }
3445 }
3446
3447 pub fn get_box_resource(
3449 &self,
3450 name: &str,
3451 discern_type: &str,
3452 ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
3453 if let Some(index) = self.check_resource_exists(name, discern_type) {
3454 Ok(&*self.rust_constructor_resource[index].content)
3455 } else {
3456 Err(RustConstructorError {
3457 error_id: "ResourceNotFound".to_string(),
3458 description: format!("Resource \"{name}({discern_type})\" not found."),
3459 })
3460 }
3461 }
3462
3463 pub fn get_box_resource_mut(
3465 &mut self,
3466 name: &str,
3467 discern_type: &str,
3468 ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
3469 if let Some(index) = self.check_resource_exists(name, discern_type) {
3470 Ok(&mut *self.rust_constructor_resource[index].content)
3471 } else {
3472 Err(RustConstructorError {
3473 error_id: "ResourceNotFound".to_string(),
3474 description: format!("Resource \"{name}({discern_type})\" not found."),
3475 })
3476 }
3477 }
3478
3479 pub fn get_resource<T>(
3481 &self,
3482 name: &str,
3483 discern_type: &str,
3484 ) -> Result<&T, RustConstructorError>
3485 where
3486 T: RustConstructorResource + 'static,
3487 {
3488 if let Some(resource) = self
3489 .get_box_resource(name, discern_type)?
3490 .as_any()
3491 .downcast_ref::<T>()
3492 {
3493 Ok(resource)
3494 } else {
3495 Err(RustConstructorError {
3496 error_id: "ResourceGenericMismatch".to_string(),
3497 description: format!(
3498 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3499 ),
3500 })
3501 }
3502 }
3503
3504 pub fn get_resource_mut<T>(
3506 &mut self,
3507 name: &str,
3508 discern_type: &str,
3509 ) -> Result<&mut T, RustConstructorError>
3510 where
3511 T: RustConstructorResource + 'static,
3512 {
3513 if let Some(resource) = self
3514 .get_box_resource_mut(name, discern_type)?
3515 .as_any_mut()
3516 .downcast_mut::<T>()
3517 {
3518 Ok(resource)
3519 } else {
3520 Err(RustConstructorError {
3521 error_id: "ResourceGenericMismatch".to_string(),
3522 description: format!(
3523 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3524 ),
3525 })
3526 }
3527 }
3528
3529 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
3531 self.rust_constructor_resource
3532 .iter()
3533 .position(|x| x.id.name == name && x.id.discern_type == discern_type)
3534 }
3535
3536 pub fn quick_place<T: RustConstructorResource + 'static>(
3538 &mut self,
3539 name: &str,
3540 resource: T,
3541 ui: &mut Ui,
3542 ctx: &Context,
3543 need_place_holder: NeedPlaceholder,
3544 ) -> Result<(), RustConstructorError> {
3545 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3546 list.0
3547 } else {
3548 type_name_of_val(&resource)
3549 };
3550 if self.check_resource_exists(name, discern_type).is_none() {
3551 self.add_resource(name, resource)
3552 } else {
3553 self.use_resource(name, discern_type, ui, ctx, need_place_holder)
3554 }
3555 }
3556
3557 pub fn use_resource(
3559 &mut self,
3560 name: &str,
3561 discern_type: &str,
3562 ui: &mut Ui,
3563 ctx: &Context,
3564 need_place_holder: NeedPlaceholder,
3565 ) -> Result<(), RustConstructorError> {
3566 if self.check_resource_exists(name, discern_type).is_some() {
3567 match discern_type {
3568 "rust_constructor::CustomRect"
3569 | "rust_constructor::Text"
3570 | "rust_constructor::Image" => {
3571 self.add_active_resource(name, discern_type)?;
3572 }
3573 "rust_constructor::PageData" => {
3574 self.update_frame_stats();
3576 self.update_render_list();
3578 for i in 0..self.render_list.len() {
3580 self.draw_resource_by_index(ui, ctx, i)?;
3581 }
3582 self.update_render_layer();
3584 self.update_event_list();
3586 self.active_list.clear();
3588 for rcr in &mut self.rust_constructor_resource {
3590 if let Some(display_info) = &mut rcr.content.display_display_info() {
3591 rcr.content.modify_display_info(DisplayInfo {
3592 enable: true,
3593 hidden: display_info.hidden,
3594 ignore_render_layer: display_info.ignore_render_layer,
3595 });
3596 };
3597 }
3598 self.update_timer();
3600 let current_page = &self.current_page.clone();
3601 let page_data =
3602 self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
3603 if page_data.forced_update {
3604 ctx.request_repaint();
3605 };
3606 }
3607 _ => {
3608 let mut tag = HashMap::new();
3609 tag.insert("name", name);
3610 tag.insert("type", discern_type);
3611 self.add_event("rust_constructor::003", tag, true);
3612 }
3613 }
3614 if let NeedPlaceholder::Yes(amount) = need_place_holder {
3615 for _ in 0..amount {
3616 self.add_active_resource(Self::PLACEHOLDER[0], Self::PLACEHOLDER[1])?;
3617 }
3618 };
3619 Ok(())
3620 } else {
3621 Err(RustConstructorError {
3622 error_id: "ResourceNotFound".to_string(),
3623 description: format!("Resource \"{name}({discern_type})\" not found."),
3624 })
3625 }
3626 }
3627
3628 pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
3630 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3631 page_data.enter_page_updated = false;
3632 self.timer.start_time = self.timer.total_time;
3633 self.current_page = name.to_string();
3634 self.update_timer();
3635 Ok(())
3636 }
3637
3638 pub fn get_font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
3640 let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
3641 Ok(font.font_definitions.clone())
3642 }
3643
3644 pub fn register_all_fonts(&mut self, ctx: &Context) {
3646 let mut font_definitions_amount = FontDefinitions::default();
3647 let mut fonts = Vec::new();
3648 for i in 0..self.rust_constructor_resource.len() {
3649 if let Some(font) = self.rust_constructor_resource[i]
3650 .content
3651 .as_any()
3652 .downcast_ref::<Font>()
3653 {
3654 fonts.push((
3655 self.rust_constructor_resource[i].id.name.clone(),
3656 font.font_definitions.clone(),
3657 ));
3658 };
3659 }
3660 for i in &fonts {
3661 if let Some(font_data) = i.1.font_data.get(&i.0) {
3663 font_definitions_amount
3664 .font_data
3665 .insert(i.0.clone(), Arc::clone(font_data));
3666 font_definitions_amount
3667 .families
3668 .entry(FontFamily::Name(i.0.clone().into()))
3669 .or_default()
3670 .push(i.0.clone());
3671 };
3672
3673 font_definitions_amount
3675 .families
3676 .entry(FontFamily::Proportional)
3677 .or_default()
3678 .insert(0, i.0.to_owned());
3679
3680 font_definitions_amount
3681 .families
3682 .entry(FontFamily::Monospace)
3683 .or_default()
3684 .insert(0, i.0.to_owned());
3685 }
3686 ctx.set_fonts(font_definitions_amount);
3687 }
3688
3689 pub fn position_size_processor(
3691 &self,
3692 position_size_config: PositionSizeConfig,
3693 ctx: &Context,
3694 ) -> [[f32; 2]; 2] {
3695 let mut position = [0_f32, 0_f32];
3696 let mut size = [0_f32, 0_f32];
3697 size[0] = match position_size_config.x_size_grid[0] {
3698 0_f32 => position_size_config.origin_size[0],
3699 _ => {
3700 (ctx.available_rect().width() / position_size_config.x_size_grid[1]
3701 * position_size_config.x_size_grid[0])
3702 + position_size_config.origin_size[0]
3703 }
3704 };
3705 size[1] = match position_size_config.y_size_grid[0] {
3706 0_f32 => position_size_config.origin_size[1],
3707 _ => {
3708 (ctx.available_rect().height() / position_size_config.y_size_grid[1]
3709 * position_size_config.y_size_grid[0])
3710 + position_size_config.origin_size[1]
3711 }
3712 };
3713 position[0] = match position_size_config.x_location_grid[1] {
3714 0_f32 => position_size_config.origin_position[0],
3715 _ => {
3716 (ctx.available_rect().width() / position_size_config.x_location_grid[1]
3717 * position_size_config.x_location_grid[0])
3718 + position_size_config.origin_position[0]
3719 }
3720 };
3721 position[1] = match position_size_config.y_location_grid[1] {
3722 0_f32 => position_size_config.origin_position[1],
3723 _ => {
3724 (ctx.available_rect().height() / position_size_config.y_location_grid[1]
3725 * position_size_config.y_location_grid[0])
3726 + position_size_config.origin_position[1]
3727 }
3728 };
3729 match position_size_config.display_method.0 {
3730 HorizontalAlign::Left => {}
3731 HorizontalAlign::Center => position[0] -= size[0] / 2.0,
3732 HorizontalAlign::Right => position[0] -= size[0],
3733 };
3734 match position_size_config.display_method.1 {
3735 VerticalAlign::Top => {}
3736 VerticalAlign::Center => position[1] -= size[1] / 2.0,
3737 VerticalAlign::Bottom => position[1] -= size[1],
3738 };
3739 position[0] += position_size_config.offset[0];
3740 position[1] += position_size_config.offset[1];
3741 [position, size]
3742 }
3743
3744 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3746 let page_data = self
3747 .get_resource::<PageData>(name, "rust_constructor::PageData")?
3748 .clone();
3749 if !page_data.change_page_updated {
3750 self.new_page_update(name)?;
3751 };
3752 Ok(page_data.change_page_updated)
3753 }
3754
3755 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3757 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3758 page_data.enter_page_updated = true;
3759 Ok(page_data.enter_page_updated)
3760 }
3761
3762 pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
3764 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3765 page_data.change_page_updated = true;
3766 self.timer.start_time = self.timer.total_time;
3767 self.update_timer();
3768 Ok(())
3769 }
3770
3771 pub fn update_frame_stats(&mut self) {
3773 let current_time = self.timer.total_time;
3774 if let Some(last) = self.last_frame_time {
3775 let delta = current_time - last;
3776 self.frame_times.push(delta);
3777 const MAX_SAMPLES: usize = 120;
3778 if self.frame_times.len() > MAX_SAMPLES {
3779 let remove_count = self.frame_times.len() - MAX_SAMPLES;
3780 self.frame_times.drain(0..remove_count);
3781 }
3782 }
3783 self.last_frame_time = Some(current_time);
3784 }
3785
3786 pub fn current_fps(&self) -> f32 {
3788 if self.frame_times.is_empty() {
3789 0.0
3790 } else {
3791 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
3792 }
3793 }
3794
3795 pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
3797 let new_time = [self.timer.now_time, self.timer.total_time];
3798 let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
3799 split_time.time = new_time;
3800 Ok(())
3801 }
3802
3803 pub fn get_split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
3805 let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
3806 Ok(split_time.time)
3807 }
3808
3809 pub fn update_timer(&mut self) {
3811 let elapsed = self.timer.timer.elapsed();
3812 let seconds = elapsed.as_secs();
3813 let milliseconds = elapsed.subsec_millis();
3814 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
3815 self.timer.now_time = self.timer.total_time - self.timer.start_time
3816 }
3817
3818 pub fn modify_variable<T: Debug + 'static>(
3820 &mut self,
3821 name: &str,
3822 value: Option<T>,
3823 ) -> Result<(), RustConstructorError> {
3824 let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
3825 variable.value = value;
3826 Ok(())
3827 }
3828
3829 pub fn get_variable<T: Debug + Clone + 'static>(
3831 &mut self,
3832 name: &str,
3833 ) -> Result<Option<T>, RustConstructorError> {
3834 if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
3835 Ok(variable.value.clone())
3836 } else if self
3837 .check_resource_exists(name, "rust_constructor::Variable")
3838 .is_none()
3839 {
3840 Err(RustConstructorError {
3841 error_id: "ResourceNotFound".to_string(),
3842 description: format!(
3843 "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
3844 ),
3845 })
3846 } else {
3847 Err(RustConstructorError {
3848 error_id: "ResourceGenericMismatch".to_string(),
3849 description: format!(
3850 "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
3851 ),
3852 })
3853 }
3854 }
3855
3856 pub fn get_image_texture(
3858 &mut self,
3859 name: &str,
3860 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3861 let image_texture =
3862 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3863 Ok(image_texture.texture.clone())
3864 }
3865
3866 pub fn reset_image_texture(
3868 &mut self,
3869 name: &str,
3870 path: &str,
3871 flip: [bool; 2],
3872 ctx: &Context,
3873 ) -> Result<(), RustConstructorError> {
3874 let image_texture =
3875 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3876 if let Ok(mut file) = File::open(path) {
3877 let mut buffer = Vec::new();
3878 file.read_to_end(&mut buffer).unwrap();
3879 let img_bytes = buffer;
3880 let img = image::load_from_memory(&img_bytes).unwrap();
3881 let color_data = match flip {
3882 [true, true] => img.fliph().flipv().into_rgba8(),
3883 [true, false] => img.fliph().into_rgba8(),
3884 [false, true] => img.flipv().into_rgba8(),
3885 _ => img.into_rgba8(),
3886 };
3887 let (w, h) = (color_data.width(), color_data.height());
3888 let raw_data: Vec<u8> = color_data.into_raw();
3889
3890 let color_image =
3891 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3892 let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
3893 image_texture.texture = Some(DebugTextureHandle::new(&texture));
3894 image_texture.cite_path = path.to_string();
3895 } else {
3896 return Err(RustConstructorError {
3897 error_id: "ImageLoadFailed".to_string(),
3898 description: format!(
3899 "Failed to load an image from the path \"{}\".",
3900 image_texture.cite_path
3901 ),
3902 });
3903 }
3904 Ok(())
3905 }
3906}