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)]
1682pub struct App {
1683 pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
1685 pub tick_interval: f32,
1687 pub current_page: String,
1689 pub timer: Timer,
1691 pub frame_times: Vec<f32>,
1693 pub last_frame_time: Option<f32>,
1695 pub basic_front_resource_list: Vec<String>,
1697 pub render_layer: Vec<([String; 2], [[f32; 2]; 2], bool)>,
1699 pub active_list: Vec<[String; 2]>,
1701 pub render_list: Vec<[String; 2]>,
1703 pub event_list: Vec<Event>,
1705 pub event_map: Vec<[String; 2]>,
1707}
1708
1709impl Default for App {
1710 fn default() -> Self {
1711 App {
1712 rust_constructor_resource: Vec::new(),
1713 tick_interval: 0.05,
1714 current_page: String::new(),
1715 timer: Timer::default(),
1716 frame_times: Vec::new(),
1717 last_frame_time: None,
1718 basic_front_resource_list: vec![
1719 String::from("rust_constructor::Image"),
1720 String::from("rust_constructor::Text"),
1721 String::from("rust_constructor::CustomRect"),
1722 ],
1723 render_layer: Vec::new(),
1724 active_list: Vec::new(),
1725 render_list: Vec::new(),
1726 event_list: Vec::new(),
1727 event_map: vec![
1728 [
1729 "rust_constructor::001".to_string(),
1730 "Attempting to create an external resource.".to_string(),
1731 ],
1732 [
1733 "rust_constructor::002".to_string(),
1734 "Attempting to remove an external resource.".to_string(),
1735 ],
1736 [
1737 "rust_constructor::003".to_string(),
1738 "Attempting to use an external resource.".to_string(),
1739 ],
1740 ],
1741 }
1742 }
1743}
1744
1745impl App {
1746 const PLACEHOLDER: [&str; 2] = ["PLACEHOLDER", "rust_constructor::Placeholder"];
1747 #[inline]
1748 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
1749 self.tick_interval = tick_interval;
1750 self
1751 }
1752
1753 #[inline]
1754 pub fn current_page(mut self, current_page: &str) -> Self {
1755 self.current_page = current_page.to_string();
1756 self
1757 }
1758
1759 pub fn add_event(&mut self, id: &str, tag: HashMap<&str, &str>, auto_delete: bool) {
1761 self.event_list.push(Event {
1762 id: id.to_string(),
1763 tag: tag
1764 .into_iter()
1765 .map(|s| (s.0.to_string(), s.1.to_string()))
1766 .collect(),
1767 description: if let Some(index) = self.event_map.iter().position(|x| x[0] == id) {
1768 self.event_map[index][1].clone()
1769 } else {
1770 "This event has no description.".to_string()
1771 },
1772 event_state: EventState {
1773 current_page: self.current_page.clone(),
1774 current_total_runtime: self.timer.total_time,
1775 current_page_runtime: self.timer.now_time,
1776 },
1777 auto_delete,
1778 handled: false,
1779 });
1780 }
1781
1782 pub fn update_event_list(&mut self) {
1784 let mut count = 0;
1785 for event in &mut self.event_list.clone() {
1786 if event.handled && event.auto_delete {
1787 self.event_list.remove(count);
1788 continue;
1789 };
1790 count += 1;
1791 }
1792 }
1793
1794 pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
1796 for i in 0..self.render_list.len() {
1797 #[allow(warnings)]
1798 self.draw_resource_by_index(ui, ctx, i);
1799 }
1800 }
1801
1802 pub fn draw_resource_by_index(
1804 &mut self,
1805 ui: &mut Ui,
1806 ctx: &Context,
1807 index: usize,
1808 ) -> Result<(), RustConstructorError> {
1809 if index < self.render_list.len() {
1810 let render_resource = &self.render_list.clone()[index];
1811 match &*render_resource[1] {
1812 "rust_constructor::Image" => {
1813 let image =
1814 self.get_resource::<Image>(&render_resource[0], "rust_constructor::Image")?;
1815 if image.display_info.enable {
1816 let mut image = image.clone();
1817 if image.cite_texture != image.last_frame_cite_texture {
1818 let image_texture = self.get_resource::<ImageTexture>(
1819 &image.cite_texture,
1820 "rust_constructor::ImageTexture",
1821 )?;
1822 image.texture = image_texture.texture.clone();
1823 };
1824 [
1825 image
1826 .basic_front_resource_config
1827 .position_size_config
1828 .position,
1829 image.basic_front_resource_config.position_size_config.size,
1830 ] = self.position_size_processor(
1831 image.basic_front_resource_config.position_size_config,
1832 ctx,
1833 );
1834 if !image.display_info.hidden {
1835 if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
1836 let [min, size] = self.position_size_processor(clip_rect, ctx);
1837 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
1838 };
1839 if let Some(texture) = &image.texture {
1840 let rect = Rect::from_min_size(
1841 Pos2::new(
1842 image
1843 .basic_front_resource_config
1844 .position_size_config
1845 .position[0],
1846 image
1847 .basic_front_resource_config
1848 .position_size_config
1849 .position[1],
1850 ),
1851 Vec2::new(
1852 image.basic_front_resource_config.position_size_config.size
1853 [0],
1854 image.basic_front_resource_config.position_size_config.size
1855 [1],
1856 ),
1857 );
1858
1859 egui::Image::new(ImageSource::Texture((&texture.0).into()))
1861 .tint(Color32::from_rgba_unmultiplied(
1862 image.overlay_color[0],
1863 image.overlay_color[1],
1864 image.overlay_color[2],
1865 (image.alpha as f32 * image.overlay_color[3] as f32 / 255.0)
1867 as u8,
1868 ))
1869 .bg_fill(Color32::from_rgba_unmultiplied(
1870 image.background_color[0],
1871 image.background_color[1],
1872 image.background_color[2],
1873 image.background_color[3],
1874 ))
1875 .rotate(
1876 image.rotate_angle,
1877 [
1878 image.rotate_center[0]
1879 / image
1880 .basic_front_resource_config
1881 .position_size_config
1882 .size[0],
1883 image.rotate_center[1]
1884 / image
1885 .basic_front_resource_config
1886 .position_size_config
1887 .size[1],
1888 ]
1889 .into(),
1890 )
1891 .paint_at(ui, rect)
1892 };
1893 if image.basic_front_resource_config.clip_rect.is_some() {
1894 ui.set_clip_rect(Rect::from_min_size(
1895 [0_f32, 0_f32].into(),
1896 [ctx.available_rect().width(), ctx.available_rect().height()]
1897 .into(),
1898 ));
1899 };
1900 };
1901 image.last_frame_cite_texture = image.cite_texture.clone();
1902 self.replace_resource(&render_resource[0], image)?;
1903 };
1904 }
1905 "rust_constructor::Text" => {
1906 let text =
1907 self.get_resource::<Text>(&render_resource[0], "rust_constructor::Text")?;
1908 if text.display_info.enable {
1909 let mut text = text.clone();
1910 [
1911 text.basic_front_resource_config
1912 .position_size_config
1913 .position,
1914 text.basic_front_resource_config.position_size_config.size,
1915 ] = self.position_size_processor(
1916 text.basic_front_resource_config.position_size_config,
1917 ctx,
1918 );
1919 let display_content = if text.truncate {
1920 let original_galley = ui.fonts_mut(|f| {
1921 f.layout(
1922 text.content.to_string(),
1923 FontId::proportional(text.font_size),
1924 Color32::default(),
1925 text.basic_front_resource_config.position_size_config.size[0],
1926 )
1927 });
1928
1929 let mut truncated = text.content.to_string();
1930 let mut ellipsis = "";
1931 if original_galley.size().y
1932 > text.basic_front_resource_config.position_size_config.size[1]
1933 {
1934 ellipsis = "...";
1936
1937 while !truncated.is_empty() {
1938 let test_text = format!("{}{}", truncated, ellipsis);
1939 let test_galley = ui.fonts_mut(|f| {
1940 f.layout(
1941 test_text,
1942 FontId::proportional(text.font_size),
1943 Color32::default(),
1944 text.basic_front_resource_config
1945 .position_size_config
1946 .size[0],
1947 )
1948 });
1949
1950 if test_galley.size().y
1951 <= text
1952 .basic_front_resource_config
1953 .position_size_config
1954 .size[1]
1955 {
1956 break;
1957 }
1958
1959 truncated.pop();
1961 }
1962 };
1963 format!("{}{}", truncated, ellipsis)
1964 } else {
1965 text.content.to_string()
1966 };
1967 let galley: Arc<Galley> = ui.fonts_mut(|f| {
1969 f.layout(
1970 display_content.to_string(),
1971 if !text.font.is_empty() {
1972 if self
1973 .check_resource_exists(&text.font, "rust_constructor::Font")
1974 .is_none()
1975 {
1976 FontId::new(
1977 text.font_size,
1978 FontFamily::Name(text.font.clone().into()),
1979 )
1980 } else {
1981 FontId::proportional(text.font_size)
1982 }
1983 } else {
1984 FontId::proportional(text.font_size)
1985 },
1986 Color32::from_rgba_unmultiplied(
1987 text.color[0],
1988 text.color[1],
1989 text.color[2],
1990 text.color[3],
1991 ),
1992 text.basic_front_resource_config.position_size_config.size[0],
1993 )
1994 });
1995 text.actual_size = [galley.size().x, galley.size().y];
1996 if text.last_frame_content != display_content {
1998 text.hyperlink_index.clear();
1999
2000 let byte_to_char_map: std::collections::HashMap<usize, usize> =
2002 display_content
2003 .char_indices()
2004 .enumerate()
2005 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2006 .collect();
2007
2008 for (hyperlink_text, method) in &text.hyperlink_text {
2009 let matches: Vec<(usize, &str)> =
2010 display_content.match_indices(hyperlink_text).collect();
2011 let text_char_count = hyperlink_text.chars().count();
2012
2013 if let HyperlinkSelectMethod::All(url) = method {
2014 for (byte_index, _) in matches {
2015 if let Some(&start_char_index) =
2016 byte_to_char_map.get(&byte_index)
2017 {
2018 text.hyperlink_index.push((
2019 start_char_index,
2020 start_char_index + text_char_count,
2021 url.clone(),
2022 ));
2023 };
2024 }
2025 } else if let HyperlinkSelectMethod::Segment(list) = method {
2026 for (index, url) in list {
2027 if *index >= matches.len() {
2028 continue;
2029 };
2030 let (byte_index, _) = matches[*index];
2031 if let Some(&start_char_index) =
2032 byte_to_char_map.get(&byte_index)
2033 {
2034 text.hyperlink_index.push((
2035 start_char_index,
2036 start_char_index + text_char_count,
2037 url.clone(),
2038 ));
2039 };
2040 }
2041 };
2042 }
2043 };
2044 if !text.display_info.hidden {
2045 let rect = Rect::from_min_size(
2047 text.basic_front_resource_config
2048 .position_size_config
2049 .position
2050 .into(),
2051 text.actual_size.into(),
2052 );
2053 ui.painter().rect_filled(
2055 rect,
2056 text.background_rounding,
2057 Color32::from_rgba_unmultiplied(
2058 text.background_color[0],
2059 text.background_color[1],
2060 text.background_color[2],
2061 text.background_color[3],
2062 ),
2063 );
2064
2065 if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2066 let [min, size] = self.position_size_processor(clip_rect, ctx);
2067 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2068 };
2069
2070 ui.painter().galley(
2072 text.basic_front_resource_config
2073 .position_size_config
2074 .position
2075 .into(),
2076 galley.clone(),
2077 Color32::from_rgba_unmultiplied(
2078 text.color[0],
2079 text.color[1],
2080 text.color[2],
2081 text.color[3],
2082 ),
2083 );
2084
2085 for (start, end, _) in &text.hyperlink_index {
2087 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2089 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2090
2091 let start_pos = start_cursor.left_top();
2092 let end_pos = end_cursor.right_top();
2093 if start_cursor.min.y == end_cursor.min.y {
2096 let underline_y = text
2098 .basic_front_resource_config
2099 .position_size_config
2100 .position[1]
2101 + start_pos.y
2102 + galley.rows.first().map_or(14.0, |row| row.height())
2103 - 2.0;
2104
2105 let color = Color32::from_rgba_unmultiplied(
2107 text.color[0],
2108 text.color[1],
2109 text.color[2],
2110 text.color[3],
2111 );
2112
2113 ui.painter().line_segment(
2114 [
2115 Pos2::new(
2116 text.basic_front_resource_config
2117 .position_size_config
2118 .position[0]
2119 + start_pos.x,
2120 underline_y,
2121 ),
2122 Pos2::new(
2123 text.basic_front_resource_config
2124 .position_size_config
2125 .position[0]
2126 + end_pos.x,
2127 underline_y,
2128 ),
2129 ],
2130 Stroke::new(text.font_size / 10_f32, color),
2131 );
2132 } else {
2133 let row_height =
2135 galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2139 let end_row = (end_pos.y / row_height).round() as usize;
2140
2141 for row in start_row..=end_row {
2142 let row_y = text
2143 .basic_front_resource_config
2144 .position_size_config
2145 .position[1]
2146 + row as f32 * row_height
2147 + row_height
2148 - 2.0; if let Some(current_row) = galley.rows.get(row) {
2152 let row_rect = current_row.rect();
2153
2154 let color = Color32::from_rgba_unmultiplied(
2155 text.color[0],
2156 text.color[1],
2157 text.color[2],
2158 text.color[3],
2159 );
2160
2161 if row == start_row {
2162 ui.painter().line_segment(
2164 [
2165 Pos2::new(
2166 text.basic_front_resource_config
2167 .position_size_config
2168 .position[0]
2169 + start_pos.x,
2170 row_y,
2171 ),
2172 Pos2::new(
2173 text.basic_front_resource_config
2174 .position_size_config
2175 .position[0]
2176 + row_rect.max.x,
2177 row_y,
2178 ),
2179 ],
2180 Stroke::new(text.font_size / 10_f32, color),
2181 );
2182 } else if row == end_row {
2183 ui.painter().line_segment(
2185 [
2186 Pos2::new(
2187 text.basic_front_resource_config
2188 .position_size_config
2189 .position[0]
2190 + row_rect.min.x,
2191 row_y,
2192 ),
2193 Pos2::new(
2194 text.basic_front_resource_config
2195 .position_size_config
2196 .position[0]
2197 + end_pos.x,
2198 row_y,
2199 ),
2200 ],
2201 Stroke::new(text.font_size / 10_f32, color),
2202 );
2203 } else {
2204 ui.painter().line_segment(
2206 [
2207 Pos2::new(
2208 text.basic_front_resource_config
2209 .position_size_config
2210 .position[0]
2211 + row_rect.min.x,
2212 row_y,
2213 ),
2214 Pos2::new(
2215 text.basic_front_resource_config
2216 .position_size_config
2217 .position[0]
2218 + row_rect.max.x,
2219 row_y,
2220 ),
2221 ],
2222 Stroke::new(text.font_size / 10_f32, color),
2223 );
2224 };
2225 };
2226 }
2227 };
2228 }
2229
2230 if text.selectable {
2231 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2233 let relative_pos = pointer_pos
2234 - text
2235 .basic_front_resource_config
2236 .position_size_config
2237 .position
2238 .into();
2239 let cursor = galley.cursor_from_pos(relative_pos);
2240 cursor.index
2241 };
2242
2243 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
2244 let rect = Rect::from_min_size(
2245 text.basic_front_resource_config
2246 .position_size_config
2247 .position
2248 .into(),
2249 text.actual_size.into(),
2250 );
2251 let detect_result = ui.interact(
2252 rect,
2253 Id::new(&render_resource[0]),
2254 Sense::click_and_drag(),
2255 );
2256
2257 if !detect_result.clicked()
2258 && (fullscreen_detect_result.any_click()
2259 || fullscreen_detect_result.any_pressed())
2260 {
2261 text.selection = None;
2262 };
2263
2264 if let Some(index) = self.get_render_layer_resource(
2265 &render_resource[0],
2266 "rust_constructor::Text",
2267 ) && let Some(mouse_pos) =
2268 fullscreen_detect_result.interact_pos()
2269 && self.resource_get_focus(index, mouse_pos.into())
2270 && (detect_result.clicked() || detect_result.drag_started())
2271 {
2272 let cursor = cursor_at_pointer(mouse_pos.to_vec2());
2273 text.selection = Some((cursor, cursor));
2274 };
2275
2276 if detect_result.dragged()
2277 && text.selection.is_some()
2278 && let Some(pointer_pos) =
2279 ui.input(|i| i.pointer.interact_pos())
2280 {
2281 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
2282 if let Some((start, _)) = text.selection {
2283 text.selection = Some((start, cursor));
2284 };
2285 };
2286
2287 if text.selection.is_some()
2288 && ui.input(|input| {
2289 input.key_released(Key::A) && input.modifiers.command
2290 })
2291 {
2292 text.selection = Some((0, display_content.chars().count()));
2293 };
2294
2295 let copy_triggered = ui.input(|input| {
2297 let c_released = input.key_released(Key::C);
2298 let cmd_pressed = input.modifiers.command;
2299 c_released && cmd_pressed
2300 });
2301 if copy_triggered && let Some((start, end)) = text.selection {
2302 let (start, end) = (start.min(end), start.max(end));
2303 let chars: Vec<char> = display_content.chars().collect();
2304 if start <= chars.len() && end <= chars.len() && start < end {
2305 let selected_text: String =
2306 chars[start..end].iter().collect();
2307 ui.ctx().copy_text(selected_text);
2308 };
2309 };
2310
2311 if let Some((start, end)) = text.selection {
2313 let (start, end) = (start.min(end), start.max(end));
2314 if start != end {
2315 let start_cursor =
2317 galley.pos_from_cursor(CCursor::new(start));
2318 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
2319
2320 let start_pos = start_cursor.left_top();
2321 let end_pos = end_cursor.right_top();
2322 if start_pos.y == end_pos.y {
2324 let rows = &galley.rows;
2326 let row_height = if !rows.is_empty() {
2327 if let Some(row) = rows.first() {
2329 row.height()
2330 } else {
2331 text.actual_size[1]
2332 / display_content.lines().count() as f32
2333 }
2334 } else {
2335 text.actual_size[1]
2336 / display_content.lines().count() as f32
2337 };
2338
2339 let selection_rect = Rect::from_min_max(
2340 Pos2::new(
2341 text.basic_front_resource_config
2342 .position_size_config
2343 .position[0]
2344 + start_pos.x,
2345 text.basic_front_resource_config
2346 .position_size_config
2347 .position[1]
2348 + start_pos.y,
2349 ),
2350 Pos2::new(
2351 text.basic_front_resource_config
2352 .position_size_config
2353 .position[0]
2354 + end_pos.x,
2355 text.basic_front_resource_config
2356 .position_size_config
2357 .position[1]
2358 + start_pos.y
2359 + row_height,
2360 ),
2361 );
2362 ui.painter().rect_filled(
2363 selection_rect,
2364 0.0,
2365 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2366 );
2367 } else {
2368 let rows = &galley.rows;
2370 let row_height = if !rows.is_empty() {
2371 rows[0].height()
2372 } else {
2373 text.actual_size[1]
2374 / display_content.lines().count() as f32
2375 };
2376
2377 let selection_top = text
2379 .basic_front_resource_config
2380 .position_size_config
2381 .position[1]
2382 + start_pos.y.min(end_pos.y);
2383 let selection_bottom = text
2384 .basic_front_resource_config
2385 .position_size_config
2386 .position[1]
2387 + start_pos.y.max(end_pos.y);
2388
2389 let start_row_index =
2391 (start_pos.y / row_height).floor() as usize;
2392 let end_row_index =
2393 (end_pos.y / row_height).floor() as usize;
2394 let (first_row_index, last_row_index) =
2395 if start_row_index <= end_row_index {
2396 (start_row_index, end_row_index)
2397 } else {
2398 (end_row_index, start_row_index)
2399 };
2400
2401 for (i, row) in rows.iter().enumerate() {
2402 let row_y = text
2403 .basic_front_resource_config
2404 .position_size_config
2405 .position[1]
2406 + row_height * i as f32;
2407 let row_bottom = row_y + row_height;
2408 if row_bottom > selection_top
2410 && row_y <= selection_bottom
2411 {
2412 let left = if i == first_row_index {
2413 text.basic_front_resource_config
2415 .position_size_config
2416 .position[0]
2417 + start_pos.x
2418 } else {
2419 text.basic_front_resource_config
2421 .position_size_config
2422 .position[0]
2423 + row.rect().min.x
2424 };
2425
2426 let right = if i == last_row_index {
2427 text.basic_front_resource_config
2429 .position_size_config
2430 .position[0]
2431 + end_pos.x
2432 } else {
2433 text.basic_front_resource_config
2435 .position_size_config
2436 .position[0]
2437 + row.rect().max.x
2438 };
2439
2440 let selection_rect = Rect::from_min_max(
2441 Pos2::new(left, row_y),
2442 Pos2::new(right, row_bottom),
2443 );
2444
2445 if selection_rect.width() > 0.0
2447 && selection_rect.height() > 0.0
2448 {
2449 ui.painter().rect_filled(
2450 selection_rect,
2451 0.0,
2452 Color32::from_rgba_unmultiplied(
2453 0, 120, 255, 100,
2454 ),
2455 );
2456 };
2457 };
2458 }
2459 };
2460 };
2461 };
2462 };
2463
2464 for (start, end, url) in &text.hyperlink_index {
2466 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2468 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2469
2470 let start_pos = start_cursor.left_top();
2471 let end_pos = end_cursor.right_top();
2472
2473 let row_height =
2474 galley.rows.first().map_or(14.0, |row| row.height());
2475
2476 let link_responses = if start_cursor.min.y == end_cursor.min.y {
2478 let link_rect = Rect::from_min_max(
2480 Pos2::new(
2481 text.basic_front_resource_config
2482 .position_size_config
2483 .position[0]
2484 + start_pos.x,
2485 text.basic_front_resource_config
2486 .position_size_config
2487 .position[1]
2488 + start_pos.y,
2489 ),
2490 Pos2::new(
2491 text.basic_front_resource_config
2492 .position_size_config
2493 .position[0]
2494 + end_pos.x,
2495 text.basic_front_resource_config
2496 .position_size_config
2497 .position[1]
2498 + start_pos.y
2499 + row_height,
2500 ),
2501 );
2502 vec![ui.interact(
2503 link_rect,
2504 egui::Id::new(format!(
2505 "link_{}_{}_{}",
2506 render_resource[0], start, end
2507 )),
2508 egui::Sense::click(),
2509 )]
2510 } else {
2511 let start_row = (start_pos.y / row_height).round() as usize;
2513 let end_row = (end_pos.y / row_height).round() as usize;
2514 let mut responses = Vec::new();
2515
2516 for row in start_row..=end_row {
2517 if let Some(current_row) = galley.rows.get(row) {
2518 let row_rect = current_row.rect();
2519 let row_y = text
2520 .basic_front_resource_config
2521 .position_size_config
2522 .position[1]
2523 + row as f32 * row_height;
2524
2525 let link_rect = if row == start_row {
2526 Rect::from_min_max(
2528 Pos2::new(
2529 text.basic_front_resource_config
2530 .position_size_config
2531 .position[0]
2532 + start_pos.x,
2533 row_y,
2534 ),
2535 Pos2::new(
2536 text.basic_front_resource_config
2537 .position_size_config
2538 .position[0]
2539 + row_rect.max.x,
2540 row_y + row_height,
2541 ),
2542 )
2543 } else if row == end_row {
2544 Rect::from_min_max(
2546 Pos2::new(
2547 text.basic_front_resource_config
2548 .position_size_config
2549 .position[0]
2550 + row_rect.min.x,
2551 row_y,
2552 ),
2553 Pos2::new(
2554 text.basic_front_resource_config
2555 .position_size_config
2556 .position[0]
2557 + end_pos.x,
2558 row_y + row_height,
2559 ),
2560 )
2561 } else {
2562 Rect::from_min_max(
2564 Pos2::new(
2565 text.basic_front_resource_config
2566 .position_size_config
2567 .position[0]
2568 + row_rect.min.x,
2569 row_y,
2570 ),
2571 Pos2::new(
2572 text.basic_front_resource_config
2573 .position_size_config
2574 .position[0]
2575 + row_rect.max.x,
2576 row_y + row_height,
2577 ),
2578 )
2579 };
2580
2581 responses.push(ui.interact(
2582 link_rect,
2583 Id::new(format!(
2584 "link_{}_{}_{}_row_{}",
2585 render_resource[0], start, end, row
2586 )),
2587 Sense::click(),
2588 ));
2589 };
2590 }
2591 responses
2592 };
2593
2594 let mut is_pressing_link = false;
2596 for link_response in &link_responses {
2597 if let Some(index) = self.get_render_layer_resource(
2598 &render_resource[0],
2599 "rust_constructor::Text",
2600 ) && let Some(mouse_pos) =
2601 ui.input(|i| i.pointer.interact_pos())
2602 && self.resource_get_focus(index, mouse_pos.into())
2603 {
2604 if link_response.is_pointer_button_down_on()
2605 && !link_response.drag_started()
2606 {
2607 text.selection = None;
2608 if let Some(pointer_pos) =
2609 ui.input(|i| i.pointer.interact_pos())
2610 {
2611 let relative_pos = pointer_pos
2612 - <[f32; 2] as Into<Pos2>>::into(
2613 text.basic_front_resource_config
2614 .position_size_config
2615 .position,
2616 );
2617 let cursor = galley.cursor_from_pos(relative_pos);
2618 if cursor.index >= *start && cursor.index <= *end {
2619 is_pressing_link = true;
2620 break;
2621 };
2622 };
2623 };
2624 let mut clicked_on_link = false;
2626 for link_response in &link_responses {
2627 if link_response.clicked()
2628 && let Some(pointer_pos) =
2629 ui.input(|i| i.pointer.interact_pos())
2630 {
2631 let relative_pos = pointer_pos
2632 - <[f32; 2] as Into<Pos2>>::into(
2633 text.basic_front_resource_config
2634 .position_size_config
2635 .position,
2636 );
2637 let cursor = galley.cursor_from_pos(relative_pos);
2638 if cursor.index >= *start && cursor.index <= *end {
2639 clicked_on_link = true;
2640 break;
2641 };
2642 };
2643 }
2644
2645 if clicked_on_link {
2646 if !url.is_empty() {
2648 ui.ctx().open_url(OpenUrl::new_tab(url));
2649 };
2650 };
2651 };
2652 }
2653
2654 if is_pressing_link {
2656 if start_cursor.min.y == end_cursor.min.y {
2657 let selection_rect = Rect::from_min_max(
2659 Pos2::new(
2660 text.basic_front_resource_config
2661 .position_size_config
2662 .position[0]
2663 + start_pos.x,
2664 text.basic_front_resource_config
2665 .position_size_config
2666 .position[1]
2667 + start_pos.y,
2668 ),
2669 Pos2::new(
2670 text.basic_front_resource_config
2671 .position_size_config
2672 .position[0]
2673 + end_pos.x,
2674 text.basic_front_resource_config
2675 .position_size_config
2676 .position[1]
2677 + start_pos.y
2678 + galley
2679 .rows
2680 .first()
2681 .map_or(14.0, |row| row.height()),
2682 ),
2683 );
2684 ui.painter().rect_filled(
2685 selection_rect,
2686 0.0,
2687 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2688 );
2689 } else {
2690 let row_height =
2692 galley.rows.first().map_or(14.0, |row| row.height());
2693 let start_row = (start_pos.y / row_height).round() as usize;
2694 let end_row = (end_pos.y / row_height).round() as usize;
2695
2696 for row in start_row..=end_row {
2697 if let Some(current_row) = galley.rows.get(row) {
2698 let row_rect = current_row.rect();
2699
2700 if row == start_row {
2701 let selection_rect = Rect::from_min_max(
2703 Pos2::new(
2704 text.basic_front_resource_config
2705 .position_size_config
2706 .position[0]
2707 + start_pos.x,
2708 text.basic_front_resource_config
2709 .position_size_config
2710 .position[1]
2711 + row as f32 * row_height,
2712 ),
2713 Pos2::new(
2714 text.basic_front_resource_config
2715 .position_size_config
2716 .position[0]
2717 + row_rect.max.x,
2718 text.basic_front_resource_config
2719 .position_size_config
2720 .position[1]
2721 + row as f32 * row_height
2722 + row_height,
2723 ),
2724 );
2725 ui.painter().rect_filled(
2726 selection_rect,
2727 0.0,
2728 Color32::from_rgba_unmultiplied(
2729 0, 120, 255, 100,
2730 ),
2731 );
2732 } else if row == end_row {
2733 let selection_rect = Rect::from_min_max(
2735 Pos2::new(
2736 text.basic_front_resource_config
2737 .position_size_config
2738 .position[0]
2739 + row_rect.min.x,
2740 text.basic_front_resource_config
2741 .position_size_config
2742 .position[1]
2743 + row as f32 * row_height,
2744 ),
2745 Pos2::new(
2746 text.basic_front_resource_config
2747 .position_size_config
2748 .position[0]
2749 + end_pos.x,
2750 text.basic_front_resource_config
2751 .position_size_config
2752 .position[1]
2753 + row as f32 * row_height
2754 + row_height,
2755 ),
2756 );
2757 ui.painter().rect_filled(
2758 selection_rect,
2759 0.0,
2760 Color32::from_rgba_unmultiplied(
2761 0, 120, 255, 100,
2762 ),
2763 );
2764 } else {
2765 let selection_rect = Rect::from_min_max(
2767 Pos2::new(
2768 text.basic_front_resource_config
2769 .position_size_config
2770 .position[0]
2771 + row_rect.min.x,
2772 text.basic_front_resource_config
2773 .position_size_config
2774 .position[1]
2775 + row as f32 * row_height,
2776 ),
2777 Pos2::new(
2778 text.basic_front_resource_config
2779 .position_size_config
2780 .position[0]
2781 + row_rect.max.x,
2782 text.basic_front_resource_config
2783 .position_size_config
2784 .position[1]
2785 + row as f32 * row_height
2786 + row_height,
2787 ),
2788 );
2789 ui.painter().rect_filled(
2790 selection_rect,
2791 0.0,
2792 Color32::from_rgba_unmultiplied(
2793 0, 120, 255, 100,
2794 ),
2795 );
2796 };
2797 };
2798 }
2799 };
2800 };
2801 }
2802 if text.basic_front_resource_config.clip_rect.is_some() {
2803 ui.set_clip_rect(Rect::from_min_size(
2804 [0_f32, 0_f32].into(),
2805 [ctx.available_rect().width(), ctx.available_rect().height()]
2806 .into(),
2807 ));
2808 };
2809 } else {
2810 text.selection = None;
2811 };
2812 text.last_frame_content = display_content;
2813 self.replace_resource(&render_resource[0], text)?;
2814 };
2815 }
2816 "rust_constructor::CustomRect" => {
2817 let custom_rect = self.get_resource::<CustomRect>(
2818 &render_resource[0],
2819 "rust_constructor::CustomRect",
2820 )?;
2821 if custom_rect.display_info.enable {
2822 let mut custom_rect = custom_rect.clone();
2823 [
2824 custom_rect
2825 .basic_front_resource_config
2826 .position_size_config
2827 .position,
2828 custom_rect
2829 .basic_front_resource_config
2830 .position_size_config
2831 .size,
2832 ] = self.position_size_processor(
2833 custom_rect.basic_front_resource_config.position_size_config,
2834 ctx,
2835 );
2836 if !custom_rect.display_info.hidden {
2837 if let Some(clip_rect) =
2838 custom_rect.basic_front_resource_config.clip_rect
2839 {
2840 let [min, size] = self.position_size_processor(clip_rect, ctx);
2841 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2842 };
2843 ui.painter().rect(
2844 Rect::from_min_max(
2845 Pos2::new(
2846 custom_rect
2847 .basic_front_resource_config
2848 .position_size_config
2849 .position[0],
2850 custom_rect
2851 .basic_front_resource_config
2852 .position_size_config
2853 .position[1],
2854 ),
2855 Pos2::new(
2856 custom_rect
2857 .basic_front_resource_config
2858 .position_size_config
2859 .position[0]
2860 + custom_rect
2861 .basic_front_resource_config
2862 .position_size_config
2863 .size[0],
2864 custom_rect
2865 .basic_front_resource_config
2866 .position_size_config
2867 .position[1]
2868 + custom_rect
2869 .basic_front_resource_config
2870 .position_size_config
2871 .size[1],
2872 ),
2873 ),
2874 custom_rect.rounding,
2875 Color32::from_rgba_unmultiplied(
2876 custom_rect.color[0],
2877 custom_rect.color[1],
2878 custom_rect.color[2],
2879 custom_rect.color[3],
2880 ),
2881 Stroke {
2882 width: custom_rect.border_width,
2883 color: Color32::from_rgba_unmultiplied(
2884 custom_rect.border_color[0],
2885 custom_rect.border_color[1],
2886 custom_rect.border_color[2],
2887 custom_rect.border_color[3],
2888 ),
2889 },
2890 match custom_rect.border_kind {
2891 BorderKind::Inside => StrokeKind::Inside,
2892 BorderKind::Middle => StrokeKind::Middle,
2893 BorderKind::Outside => StrokeKind::Outside,
2894 },
2895 );
2896 if custom_rect.basic_front_resource_config.clip_rect.is_some() {
2897 ui.set_clip_rect(Rect::from_min_size(
2898 [0_f32, 0_f32].into(),
2899 [ctx.available_rect().width(), ctx.available_rect().height()]
2900 .into(),
2901 ));
2902 };
2903 };
2904 self.replace_resource(&render_resource[0], custom_rect)?;
2905 };
2906 }
2907 _ => {
2908 unreachable!()
2909 }
2910 }
2911 Ok(())
2912 } else {
2913 Err(RustConstructorError {
2914 error_id: "IndexOutOfRange".to_string(),
2915 description: format!(
2916 "The maximum index of the target list is {}, but the index is {index}.",
2917 self.render_list.len() - 1
2918 ),
2919 })
2920 }
2921 }
2922
2923 pub fn active_list_info(&self, display_complex_info: bool, format: bool) -> String {
2925 let mut text = String::from("Resource Active Info:\n");
2926 for info in &self.active_list {
2927 if display_complex_info {
2928 if let Some(index) = self
2929 .rust_constructor_resource
2930 .iter()
2931 .position(|x| x.id.name == info[0] && x.id.discern_type == info[1])
2932 {
2933 text += &if format {
2934 format!(
2935 "\nName: {}\nType: {}\nDetail: {:#?}\n",
2936 info[0], info[1], self.rust_constructor_resource[index],
2937 )
2938 } else {
2939 format!(
2940 "\nName: {}\nType: {}\nDetail: {:?}\n",
2941 info[0], info[1], self.rust_constructor_resource[index],
2942 )
2943 };
2944 };
2945 } else {
2946 text += &format!("\nName: {}\nType: {}\n", info[0], info[1]);
2947 };
2948 }
2949 text
2950 }
2951
2952 pub fn render_layer_info(&self) -> String {
2954 let mut text = String::from("Render Layer Info:\n");
2955 for ([name, expose_type], [min_position, max_position], ignore_render_layer) in
2956 &self.render_layer
2957 {
2958 text += &format!(
2959 "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
2960 name, expose_type, min_position, max_position, ignore_render_layer
2961 );
2962 }
2963 text
2964 }
2965
2966 pub fn render_list_info(&self) -> String {
2968 let mut text = String::from("Render List Info:\n");
2969 for [name, expose_type] in &self.render_list {
2970 text += &format!("\nName: {:?}\nType: {:?}\n", name, expose_type);
2971 }
2972 text
2973 }
2974
2975 pub fn update_render_list(&mut self) {
2977 if self.render_list.is_empty() {
2978 for info in &self.active_list {
2979 if self.basic_front_resource_list.contains(&info[1]) {
2980 self.render_list.push([info[0].clone(), info[1].clone()]);
2981 };
2982 }
2983 } else {
2984 let mut count = 0;
2985 for render_resource in &self.render_list.clone() {
2986 if !self.active_list.contains(render_resource) {
2987 self.render_list.remove(count);
2988 } else {
2989 count += 1;
2990 };
2991 }
2992 let mut insert_index = 0;
2993 for info in &self.active_list {
2994 if self.basic_front_resource_list.contains(&info[1]) {
2995 if !self.render_list.contains(info) {
2996 self.render_list
2997 .insert(insert_index, [info[0].clone(), info[1].clone()]);
2998 } else {
2999 insert_index += 1;
3000 }
3001 };
3002 }
3003 };
3004 }
3005
3006 pub fn request_jump_render_list(
3008 &mut self,
3009 requester: [&str; 2],
3010 ) -> Result<(), RustConstructorError> {
3011 if let Some(index) = self
3012 .render_list
3013 .iter()
3014 .position(|x| x[0] == requester[0] && x[1] == requester[1])
3015 {
3016 self.render_list.remove(index);
3017 self.render_list
3018 .push([requester[0].to_string(), requester[1].to_string()]);
3019 Ok(())
3020 } else {
3021 Err(RustConstructorError {
3022 error_id: "RenderResourceNotFound".to_string(),
3023 description: format!(
3024 "Render resource \"{}({})\" not found.",
3025 requester[0], requester[1]
3026 ),
3027 })
3028 }
3029 }
3030
3031 pub fn update_render_layer(&mut self) {
3033 self.render_layer.clear();
3034 for info in &self.render_list {
3035 if let Some(index) = self
3036 .rust_constructor_resource
3037 .iter()
3038 .position(|x| x.id.name == info[0] && x.id.discern_type == info[1])
3039 {
3040 let basic_front_resource: Box<dyn BasicFrontResource> = match &*info[1] {
3041 "rust_constructor::Image" => Box::new(
3042 self.rust_constructor_resource[index]
3043 .content
3044 .as_any()
3045 .downcast_ref::<Image>()
3046 .unwrap()
3047 .clone(),
3048 ),
3049 "rust_constructor::Text" => Box::new(
3050 self.rust_constructor_resource[index]
3051 .content
3052 .as_any()
3053 .downcast_ref::<Text>()
3054 .unwrap()
3055 .clone(),
3056 ),
3057 "rust_constructor::CustomRect" => Box::new(
3058 self.rust_constructor_resource[index]
3059 .content
3060 .as_any()
3061 .downcast_ref::<CustomRect>()
3062 .unwrap()
3063 .clone(),
3064 ),
3065 _ => {
3066 unreachable!()
3067 }
3068 };
3069 if let Some(display_info) = basic_front_resource.display_display_info() {
3070 self.render_layer.push((
3071 info.clone(),
3072 [
3073 basic_front_resource.display_position_size_config().position,
3074 [
3075 basic_front_resource.display_position_size_config().position[0]
3076 + basic_front_resource.display_position_size_config().size[0],
3077 basic_front_resource.display_position_size_config().position[1]
3078 + basic_front_resource.display_position_size_config().size[1],
3079 ],
3080 ],
3081 display_info.ignore_render_layer,
3082 ));
3083 };
3084 };
3085 }
3086 }
3087
3088 pub fn display_render_layer(
3090 &self,
3091 ui: &mut Ui,
3092 render_config: &RenderConfig,
3093 ignore_render_config: &RenderConfig,
3094 ) {
3095 for (_, point, ignore_render_layer) in &self.render_layer {
3096 match if *ignore_render_layer {
3097 ignore_render_config
3098 } else {
3099 render_config
3100 } {
3101 RenderConfig::Rect(
3102 corner_radius,
3103 fill_color,
3104 border_color,
3105 border_width,
3106 border_kind,
3107 ) => {
3108 let rect = Rect::from_min_max(point[0].into(), point[1].into());
3109 ui.painter().rect(
3110 rect,
3111 CornerRadius {
3112 nw: corner_radius[0],
3113 ne: corner_radius[1],
3114 sw: corner_radius[2],
3115 se: corner_radius[3],
3116 },
3117 Color32::from_rgba_unmultiplied(
3118 fill_color[0],
3119 fill_color[1],
3120 fill_color[2],
3121 fill_color[3],
3122 ),
3123 Stroke::new(
3124 *border_width,
3125 Color32::from_rgba_unmultiplied(
3126 border_color[0],
3127 border_color[1],
3128 border_color[2],
3129 border_color[3],
3130 ),
3131 ),
3132 match *border_kind {
3133 BorderKind::Inside => StrokeKind::Inside,
3134 BorderKind::Middle => StrokeKind::Middle,
3135 BorderKind::Outside => StrokeKind::Outside,
3136 },
3137 );
3138 }
3139 RenderConfig::Line(width, color) => {
3140 ui.painter().line_segment(
3141 [point[0].into(), point[1].into()],
3142 Stroke::new(
3143 *width,
3144 Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3145 ),
3146 );
3147 }
3148 };
3149 }
3150 }
3151
3152 pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3154 self.render_layer
3155 .iter()
3156 .position(|x| x.0[0] == name && x.0[1] == discern_type)
3157 }
3158
3159 pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3161 for i in index + 1..self.render_layer.len() {
3162 let point = self.render_layer[i].1;
3163 if mouse_pos[0] > point[0][0]
3164 && mouse_pos[1] > point[0][1]
3165 && mouse_pos[0] < point[1][0]
3166 && mouse_pos[1] < point[1][1]
3167 && !self.render_layer[i].2
3168 {
3169 return false;
3170 };
3171 }
3172 true
3173 }
3174
3175 pub fn add_active_resource(
3177 &mut self,
3178 name: &str,
3179 discern_type: &str,
3180 ) -> Result<(), RustConstructorError> {
3181 let is_placeholder = name == Self::PLACEHOLDER[0] && discern_type == Self::PLACEHOLDER[1];
3182 if self.check_resource_exists(name, discern_type).is_some() || is_placeholder {
3183 if let Some(index) = self
3184 .active_list
3185 .iter()
3186 .position(|x| x[0] == Self::PLACEHOLDER[0] && x[1] == Self::PLACEHOLDER[1])
3187 && !is_placeholder
3188 {
3189 self.active_list.remove(index);
3190 self.active_list
3191 .insert(index, [name.to_string(), discern_type.to_string()]);
3192 } else {
3193 self.active_list
3194 .push([name.to_string(), discern_type.to_string()]);
3195 };
3196 Ok(())
3197 } else {
3198 Err(RustConstructorError {
3199 error_id: "ResourceNotFound".to_string(),
3200 description: format!("Resource \"{name}({discern_type})\" not found."),
3201 })
3202 }
3203 }
3204
3205 pub fn add_resource<T: RustConstructorResource + 'static>(
3207 &mut self,
3208 name: &str,
3209 mut resource: T,
3210 ) -> Result<(), RustConstructorError> {
3211 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3212 list.0
3213 } else {
3214 type_name_of_val(&resource)
3215 };
3216 if self.check_resource_exists(name, discern_type).is_some() {
3217 return Err(RustConstructorError {
3218 error_id: "ResourceNameRepetition".to_string(),
3219 description: format!("Resource \"{name}({discern_type})\" has already existed."),
3220 });
3221 };
3222 if name.is_empty() {
3223 return Err(RustConstructorError {
3224 error_id: "ResourceUntitled".to_string(),
3225 description: "All resources must have a valid name.".to_string(),
3226 });
3227 };
3228 match discern_type {
3229 "rust_constructor::PageData" => {}
3230 "rust_constructor::CustomRect" => {}
3231 "rust_constructor::Text" => {}
3232 "rust_constructor::Variable" => {}
3233 "rust_constructor::SplitTime" => {
3234 if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3235 split_time.time = [self.timer.now_time, self.timer.total_time];
3236 };
3237 }
3238 "rust_constructor::ImageTexture" => {
3239 if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3240 if let Ok(mut file) = File::open(&image_texture.cite_path) {
3241 let mut buffer = Vec::new();
3242 file.read_to_end(&mut buffer).unwrap();
3243 let img_bytes = buffer;
3244 let img = image::load_from_memory(&img_bytes).unwrap();
3245 let color_data = match image_texture.flip {
3246 [true, true] => img.fliph().flipv().into_rgba8(),
3247 [true, false] => img.fliph().into_rgba8(),
3248 [false, true] => img.flipv().into_rgba8(),
3249 _ => img.into_rgba8(),
3250 };
3251 let (w, h) = (color_data.width(), color_data.height());
3252 let raw_data: Vec<u8> = color_data.into_raw();
3253
3254 let color_image =
3255 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3256 let loaded_image_texture = image_texture.context.load_texture(
3257 name,
3258 color_image,
3259 TextureOptions::LINEAR,
3260 );
3261 image_texture.texture =
3262 Some(DebugTextureHandle::new(&loaded_image_texture));
3263 image_texture.cite_path = image_texture.cite_path.to_string();
3264 } else {
3265 return Err(RustConstructorError {
3266 error_id: "ImageLoadFailed".to_string(),
3267 description: format!(
3268 "Failed to load an image from the path \"{}\".",
3269 image_texture.cite_path
3270 ),
3271 });
3272 };
3273 };
3274 }
3275 "rust_constructor::Image" => {
3276 if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3277 let image_texture = self.get_resource::<ImageTexture>(
3278 &image.cite_texture,
3279 "rust_constructor::ImageTexture",
3280 )?;
3281 image.texture = image_texture.texture.clone();
3282 image.last_frame_cite_texture = image.cite_texture.clone();
3283 };
3284 }
3285 "rust_constructor::Font" => {
3286 if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3287 let mut fonts = FontDefinitions::default();
3288 if let Ok(font_read_data) = read(&font.path) {
3289 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3290 fonts.font_data.insert(
3291 name.to_owned(),
3292 Arc::new(FontData::from_owned(
3293 Arc::try_unwrap(font_data).ok().unwrap(),
3294 )),
3295 );
3296
3297 fonts
3299 .families
3300 .entry(FontFamily::Proportional)
3301 .or_default()
3302 .insert(0, name.to_owned());
3303
3304 fonts
3305 .families
3306 .entry(FontFamily::Monospace)
3307 .or_default()
3308 .insert(0, name.to_owned());
3309
3310 font.font_definitions = fonts;
3311 } else {
3312 return Err(RustConstructorError {
3313 error_id: "FontLoadFailed".to_string(),
3314 description: format!(
3315 "Failed to load a font from the path \"{}\".",
3316 font.path
3317 ),
3318 });
3319 }
3320 };
3321 }
3322 _ => {
3323 let mut tag = HashMap::new();
3324 tag.insert("name", name);
3325 tag.insert("discern_type", discern_type);
3326 self.add_event("rust_constructor::001", tag, false);
3327 }
3328 };
3329 self.rust_constructor_resource
3330 .push(RustConstructorResourceBox::new(
3331 name,
3332 discern_type,
3333 Box::new(resource),
3334 ));
3335 Ok(())
3336 }
3337
3338 pub fn drop_resource(
3340 &mut self,
3341 name: &str,
3342 discern_type: &str,
3343 ) -> Result<(), RustConstructorError> {
3344 if let Some(index) = self.check_resource_exists(name, discern_type) {
3345 self.rust_constructor_resource.remove(index);
3346 if let Some(index) = self
3347 .active_list
3348 .iter()
3349 .position(|x| x[0] == name && x[1] == discern_type)
3350 {
3351 self.active_list.remove(index);
3352 };
3353 if let Some(index) = self
3354 .render_layer
3355 .iter()
3356 .position(|x| x.0[0] == name && x.0[1] == discern_type)
3357 {
3358 self.render_layer.remove(index);
3359 };
3360 let mut tag = HashMap::new();
3361 tag.insert("name", name);
3362 tag.insert("discern_type", discern_type);
3363 self.add_event("rust_constructor::002", tag, false);
3364 Ok(())
3365 } else {
3366 Err(RustConstructorError {
3367 error_id: "ResourceNotFound".to_string(),
3368 description: format!("Resource \"{name}({discern_type})\" not found."),
3369 })
3370 }
3371 }
3372
3373 pub fn replace_resource<T>(
3375 &mut self,
3376 name: &str,
3377 resource: T,
3378 ) -> Result<(), RustConstructorError>
3379 where
3380 T: RustConstructorResource + 'static,
3381 {
3382 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3383 list.0
3384 } else {
3385 type_name_of_val(&resource)
3386 };
3387 if let Some(index) = self.check_resource_exists(name, discern_type) {
3388 self.rust_constructor_resource[index] =
3389 RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
3390 Ok(())
3391 } else {
3392 Err(RustConstructorError {
3393 error_id: "ResourceNotFound".to_string(),
3394 description: format!("Resource \"{name}({discern_type})\" not found."),
3395 })
3396 }
3397 }
3398
3399 pub fn get_resource<T>(
3401 &self,
3402 name: &str,
3403 discern_type: &str,
3404 ) -> Result<&T, RustConstructorError>
3405 where
3406 T: RustConstructorResource + 'static,
3407 {
3408 if let Some(index) = self.check_resource_exists(name, discern_type) {
3409 if let Some(resource) = self.rust_constructor_resource[index]
3410 .content
3411 .as_any()
3412 .downcast_ref::<T>()
3413 {
3414 Ok(resource)
3415 } else {
3416 Err(RustConstructorError {
3417 error_id: "ResourceGenericMismatch".to_string(),
3418 description: format!(
3419 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3420 ),
3421 })
3422 }
3423 } else {
3424 Err(RustConstructorError {
3425 error_id: "ResourceNotFound".to_string(),
3426 description: format!("Resource \"{name}({discern_type})\" not found."),
3427 })
3428 }
3429 }
3430
3431 pub fn get_resource_mut<T>(
3433 &mut self,
3434 name: &str,
3435 discern_type: &str,
3436 ) -> Result<&mut T, RustConstructorError>
3437 where
3438 T: RustConstructorResource + 'static,
3439 {
3440 if let Some(index) = self.check_resource_exists(name, discern_type) {
3441 if let Some(resource) = self.rust_constructor_resource[index]
3442 .content
3443 .as_any_mut()
3444 .downcast_mut::<T>()
3445 {
3446 Ok(resource)
3447 } else {
3448 Err(RustConstructorError {
3449 error_id: "ResourceGenericMismatch".to_string(),
3450 description: format!(
3451 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3452 ),
3453 })
3454 }
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 check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
3465 self.rust_constructor_resource
3466 .iter()
3467 .position(|x| x.id.name == name && x.id.discern_type == discern_type)
3468 }
3469
3470 pub fn quick_place<T: RustConstructorResource + 'static>(
3472 &mut self,
3473 name: &str,
3474 resource: T,
3475 ui: &mut Ui,
3476 ctx: &Context,
3477 need_place_holder: NeedPlaceholder,
3478 ) -> Result<(), RustConstructorError> {
3479 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3480 list.0
3481 } else {
3482 type_name_of_val(&resource)
3483 };
3484 if self.check_resource_exists(name, discern_type).is_none() {
3485 self.add_resource(name, resource)
3486 } else {
3487 self.use_resource(name, discern_type, ui, ctx, need_place_holder)
3488 }
3489 }
3490
3491 pub fn use_resource(
3493 &mut self,
3494 name: &str,
3495 discern_type: &str,
3496 ui: &mut Ui,
3497 ctx: &Context,
3498 need_place_holder: NeedPlaceholder,
3499 ) -> Result<(), RustConstructorError> {
3500 if self.check_resource_exists(name, discern_type).is_some() {
3501 match discern_type {
3502 "rust_constructor::CustomRect"
3503 | "rust_constructor::Text"
3504 | "rust_constructor::Image" => {
3505 self.add_active_resource(name, discern_type)?;
3506 }
3507 "rust_constructor::PageData" => {
3508 self.update_frame_stats();
3510 self.update_render_list();
3512 for i in 0..self.render_list.len() {
3514 self.draw_resource_by_index(ui, ctx, i)?;
3515 }
3516 self.update_render_layer();
3518 self.update_event_list();
3520 self.active_list.clear();
3522 for rcr in &mut self.rust_constructor_resource {
3524 if let Some(display_info) = &mut rcr.content.display_display_info() {
3525 rcr.content.modify_display_info(DisplayInfo {
3526 enable: true,
3527 hidden: display_info.hidden,
3528 ignore_render_layer: display_info.ignore_render_layer,
3529 });
3530 };
3531 }
3532 self.update_timer();
3534 let current_page = &self.current_page.clone();
3535 let page_data =
3536 self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
3537 if page_data.forced_update {
3538 ctx.request_repaint();
3539 };
3540 }
3541 _ => {
3542 let mut tag = HashMap::new();
3543 tag.insert("name", name);
3544 tag.insert("discern_type", discern_type);
3545 self.add_event("rust_constructor::003", tag, true);
3546 }
3547 }
3548 if let NeedPlaceholder::Yes(amount) = need_place_holder {
3549 for _ in 0..amount {
3550 self.add_active_resource(Self::PLACEHOLDER[0], Self::PLACEHOLDER[1])?;
3551 }
3552 };
3553 Ok(())
3554 } else {
3555 Err(RustConstructorError {
3556 error_id: "ResourceNotFound".to_string(),
3557 description: format!("Resource \"{name}({discern_type})\" not found."),
3558 })
3559 }
3560 }
3561
3562 pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
3564 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3565 page_data.enter_page_updated = false;
3566 self.timer.start_time = self.timer.total_time;
3567 self.current_page = name.to_string();
3568 self.update_timer();
3569 Ok(())
3570 }
3571
3572 pub fn get_font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
3574 let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
3575 Ok(font.font_definitions.clone())
3576 }
3577
3578 pub fn register_all_fonts(&mut self, ctx: &Context) {
3580 let mut font_definitions_amount = FontDefinitions::default();
3581 let mut fonts = Vec::new();
3582 for i in 0..self.rust_constructor_resource.len() {
3583 if let Some(font) = self.rust_constructor_resource[i]
3584 .content
3585 .as_any()
3586 .downcast_ref::<Font>()
3587 {
3588 fonts.push((
3589 self.rust_constructor_resource[i].id.name.clone(),
3590 font.font_definitions.clone(),
3591 ));
3592 };
3593 }
3594 for i in &fonts {
3595 if let Some(font_data) = i.1.font_data.get(&i.0) {
3597 font_definitions_amount
3598 .font_data
3599 .insert(i.0.clone(), Arc::clone(font_data));
3600 font_definitions_amount
3601 .families
3602 .entry(FontFamily::Name(i.0.clone().into()))
3603 .or_default()
3604 .push(i.0.clone());
3605 };
3606
3607 font_definitions_amount
3609 .families
3610 .entry(FontFamily::Proportional)
3611 .or_default()
3612 .insert(0, i.0.to_owned());
3613
3614 font_definitions_amount
3615 .families
3616 .entry(FontFamily::Monospace)
3617 .or_default()
3618 .insert(0, i.0.to_owned());
3619 }
3620 ctx.set_fonts(font_definitions_amount);
3621 }
3622
3623 pub fn position_size_processor(
3625 &self,
3626 position_size_config: PositionSizeConfig,
3627 ctx: &Context,
3628 ) -> [[f32; 2]; 2] {
3629 let mut position = [0_f32, 0_f32];
3630 let mut size = [0_f32, 0_f32];
3631 size[0] = match position_size_config.x_size_grid[0] {
3632 0_f32 => position_size_config.origin_size[0],
3633 _ => {
3634 (ctx.available_rect().width() / position_size_config.x_size_grid[1]
3635 * position_size_config.x_size_grid[0])
3636 + position_size_config.origin_size[0]
3637 }
3638 };
3639 size[1] = match position_size_config.y_size_grid[0] {
3640 0_f32 => position_size_config.origin_size[1],
3641 _ => {
3642 (ctx.available_rect().height() / position_size_config.y_size_grid[1]
3643 * position_size_config.y_size_grid[0])
3644 + position_size_config.origin_size[1]
3645 }
3646 };
3647 position[0] = match position_size_config.x_location_grid[1] {
3648 0_f32 => position_size_config.origin_position[0],
3649 _ => {
3650 (ctx.available_rect().width() / position_size_config.x_location_grid[1]
3651 * position_size_config.x_location_grid[0])
3652 + position_size_config.origin_position[0]
3653 }
3654 };
3655 position[1] = match position_size_config.y_location_grid[1] {
3656 0_f32 => position_size_config.origin_position[1],
3657 _ => {
3658 (ctx.available_rect().height() / position_size_config.y_location_grid[1]
3659 * position_size_config.y_location_grid[0])
3660 + position_size_config.origin_position[1]
3661 }
3662 };
3663 match position_size_config.display_method.0 {
3664 HorizontalAlign::Left => {}
3665 HorizontalAlign::Center => position[0] -= size[0] / 2.0,
3666 HorizontalAlign::Right => position[0] -= size[0],
3667 };
3668 match position_size_config.display_method.1 {
3669 VerticalAlign::Top => {}
3670 VerticalAlign::Center => position[1] -= size[1] / 2.0,
3671 VerticalAlign::Bottom => position[1] -= size[1],
3672 };
3673 position[0] += position_size_config.offset[0];
3674 position[1] += position_size_config.offset[1];
3675 [position, size]
3676 }
3677
3678 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3680 let page_data = self
3681 .get_resource::<PageData>(name, "rust_constructor::PageData")?
3682 .clone();
3683 if !page_data.change_page_updated {
3684 self.new_page_update(name)?;
3685 };
3686 Ok(page_data.change_page_updated)
3687 }
3688
3689 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3691 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3692 page_data.enter_page_updated = true;
3693 Ok(page_data.enter_page_updated)
3694 }
3695
3696 pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
3698 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3699 page_data.change_page_updated = true;
3700 self.timer.start_time = self.timer.total_time;
3701 self.update_timer();
3702 Ok(())
3703 }
3704
3705 pub fn update_frame_stats(&mut self) {
3707 let current_time = self.timer.total_time;
3708 if let Some(last) = self.last_frame_time {
3709 let delta = current_time - last;
3710 self.frame_times.push(delta);
3711 const MAX_SAMPLES: usize = 120;
3712 if self.frame_times.len() > MAX_SAMPLES {
3713 let remove_count = self.frame_times.len() - MAX_SAMPLES;
3714 self.frame_times.drain(0..remove_count);
3715 }
3716 }
3717 self.last_frame_time = Some(current_time);
3718 }
3719
3720 pub fn current_fps(&self) -> f32 {
3722 if self.frame_times.is_empty() {
3723 0.0
3724 } else {
3725 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
3726 }
3727 }
3728
3729 pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
3731 let new_time = [self.timer.now_time, self.timer.total_time];
3732 let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
3733 split_time.time = new_time;
3734 Ok(())
3735 }
3736
3737 pub fn get_split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
3739 let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
3740 Ok(split_time.time)
3741 }
3742
3743 pub fn update_timer(&mut self) {
3745 let elapsed = self.timer.timer.elapsed();
3746 let seconds = elapsed.as_secs();
3747 let milliseconds = elapsed.subsec_millis();
3748 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
3749 self.timer.now_time = self.timer.total_time - self.timer.start_time
3750 }
3751
3752 pub fn modify_variable<T: Debug + 'static>(
3754 &mut self,
3755 name: &str,
3756 value: Option<T>,
3757 ) -> Result<(), RustConstructorError> {
3758 let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
3759 variable.value = value;
3760 Ok(())
3761 }
3762
3763 pub fn get_variable<T: Debug + Clone + 'static>(
3765 &mut self,
3766 name: &str,
3767 ) -> Result<Option<T>, RustConstructorError> {
3768 if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
3769 Ok(variable.value.clone())
3770 } else if self
3771 .check_resource_exists(name, "rust_constructor::Variable")
3772 .is_none()
3773 {
3774 Err(RustConstructorError {
3775 error_id: "ResourceNotFound".to_string(),
3776 description: format!(
3777 "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
3778 ),
3779 })
3780 } else {
3781 Err(RustConstructorError {
3782 error_id: "ResourceGenericMismatch".to_string(),
3783 description: format!(
3784 "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
3785 ),
3786 })
3787 }
3788 }
3789
3790 pub fn get_image_texture(
3792 &mut self,
3793 name: &str,
3794 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3795 let image_texture =
3796 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3797 Ok(image_texture.texture.clone())
3798 }
3799
3800 pub fn reset_image_texture(
3802 &mut self,
3803 name: &str,
3804 path: &str,
3805 flip: [bool; 2],
3806 ctx: &Context,
3807 ) -> Result<(), RustConstructorError> {
3808 let image_texture =
3809 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3810 if let Ok(mut file) = File::open(path) {
3811 let mut buffer = Vec::new();
3812 file.read_to_end(&mut buffer).unwrap();
3813 let img_bytes = buffer;
3814 let img = image::load_from_memory(&img_bytes).unwrap();
3815 let color_data = match flip {
3816 [true, true] => img.fliph().flipv().into_rgba8(),
3817 [true, false] => img.fliph().into_rgba8(),
3818 [false, true] => img.flipv().into_rgba8(),
3819 _ => img.into_rgba8(),
3820 };
3821 let (w, h) = (color_data.width(), color_data.height());
3822 let raw_data: Vec<u8> = color_data.into_raw();
3823
3824 let color_image =
3825 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3826 let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
3827 image_texture.texture = Some(DebugTextureHandle::new(&texture));
3828 image_texture.cite_path = path.to_string();
3829 } else {
3830 return Err(RustConstructorError {
3831 error_id: "ImageLoadFailed".to_string(),
3832 description: format!(
3833 "Failed to load an image from the path \"{}\".",
3834 image_texture.cite_path
3835 ),
3836 });
3837 }
3838 Ok(())
3839 }
3840}