1use eframe::{
23 Result,
24 emath::Rect,
25 epaint::{Stroke, textures::TextureOptions},
26};
27use egui::{
28 Color32, ColorImage, Context, CornerRadius, CursorIcon, FontData, FontDefinitions, FontFamily,
29 FontId, Galley, Id, ImageSource, Key, OpenUrl, PointerButton, Pos2, Sense, StrokeKind,
30 TextureHandle, Ui, Vec2, text::CCursor,
31};
32use std::{
33 any::{Any, type_name_of_val},
34 char,
35 cmp::Ordering,
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]], replace: bool);
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 display_position(&self) -> [f32; 2];
79
80 fn display_size(&self) -> [f32; 2];
82
83 fn modify_basic_front_resource_config(
85 &mut self,
86 basic_front_resource_config: BasicFrontResourceConfig,
87 );
88
89 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig);
91
92 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>);
94}
95
96#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
98pub struct RustConstructorId {
99 pub name: String,
101 pub discern_type: String,
103}
104
105#[derive(Debug)]
107pub struct RustConstructorResourceBox {
108 pub id: RustConstructorId,
110 pub content: Box<dyn RustConstructorResource>,
112}
113
114impl RustConstructorResourceBox {
115 pub fn new(name: &str, discern_type: &str, content: Box<dyn RustConstructorResource>) -> Self {
116 Self {
117 id: RustConstructorId {
118 name: name.to_string(),
119 discern_type: discern_type.to_string(),
120 },
121 content,
122 }
123 }
124}
125
126#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
128pub struct BasicFrontResourceConfig {
129 pub position_size_config: PositionSizeConfig,
131 pub clip_rect: Option<PositionSizeConfig>,
133}
134
135impl BasicFrontResourceConfig {
136 #[inline]
137 pub fn position_size_config(mut self, position_size_config: PositionSizeConfig) -> Self {
138 self.position_size_config = position_size_config;
139 self
140 }
141
142 #[inline]
143 pub fn clip_rect(mut self, clip_rect: Option<PositionSizeConfig>) -> Self {
144 self.clip_rect = clip_rect;
145 self
146 }
147}
148
149#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
151pub struct PositionSizeConfig {
152 pub origin_position: [f32; 2],
154 pub origin_size: [f32; 2],
156 pub x_location_grid: [f32; 2],
158 pub y_location_grid: [f32; 2],
160 pub x_size_grid: [f32; 2],
162 pub y_size_grid: [f32; 2],
164 pub display_method: (HorizontalAlign, VerticalAlign),
166 pub offset: [f32; 2],
168}
169
170impl Default for PositionSizeConfig {
171 fn default() -> Self {
172 PositionSizeConfig {
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, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
252pub struct PageData {
253 pub forced_update: bool,
255 pub change_page_updated: bool,
257 pub enter_page_updated: bool,
259 pub tags: Vec<[String; 2]>,
261}
262
263impl RustConstructorResource for PageData {
264 fn as_any(&self) -> &dyn Any {
265 self
266 }
267
268 fn as_any_mut(&mut self) -> &mut dyn Any {
269 self
270 }
271
272 fn display_display_info(&self) -> Option<DisplayInfo> {
273 None
274 }
275
276 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
277
278 fn display_tags(&self) -> Vec<[String; 2]> {
279 self.tags.clone()
280 }
281
282 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
283 if replace {
284 self.tags = tags.to_owned();
285 } else {
286 for tag in tags {
287 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
288 self.tags.remove(index);
289 };
290 }
291 self.tags.extend(tags.iter().cloned());
292 };
293 }
294}
295
296impl Default for PageData {
297 fn default() -> Self {
298 PageData {
299 forced_update: true,
300 change_page_updated: false,
301 enter_page_updated: false,
302 tags: Vec::new(),
303 }
304 }
305}
306
307impl PageData {
308 #[inline]
309 pub fn forced_update(mut self, forced_update: bool) -> Self {
310 self.forced_update = forced_update;
311 self
312 }
313
314 #[inline]
315 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
316 if replace {
317 self.tags = tags.to_owned();
318 } else {
319 for tag in tags {
320 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
321 self.tags.remove(index);
322 };
323 }
324 self.tags.extend(tags.iter().cloned());
325 };
326 self
327 }
328}
329
330#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
332pub struct Timer {
333 pub start_time: f32,
335 pub total_time: f32,
337 pub timer: Instant,
339 pub now_time: f32,
341}
342
343impl Default for Timer {
344 fn default() -> Self {
345 Timer {
346 start_time: 0_f32,
347 total_time: 0_f32,
348 timer: Instant::now(),
349 now_time: 0_f32,
350 }
351 }
352}
353
354#[derive(Clone, PartialEq, Eq, Hash)]
356pub struct DebugTextureHandle(TextureHandle);
357
358impl Debug for DebugTextureHandle {
359 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
360 f.debug_struct("DebugTextureHandle").finish()
362 }
363}
364
365impl DebugTextureHandle {
366 pub fn new(texture_handle: &TextureHandle) -> Self {
367 Self(texture_handle.clone())
368 }
369}
370
371#[derive(Clone, Debug, Default, PartialEq)]
373pub struct ImageTexture {
374 pub texture: Option<DebugTextureHandle>,
376 pub cite_path: String,
378 pub flip: [bool; 2],
380 pub context: Context,
382 pub tags: Vec<[String; 2]>,
384}
385
386impl RustConstructorResource for ImageTexture {
387 fn as_any(&self) -> &dyn Any {
388 self
389 }
390
391 fn as_any_mut(&mut self) -> &mut dyn Any {
392 self
393 }
394
395 fn display_display_info(&self) -> Option<DisplayInfo> {
396 None
397 }
398
399 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
400
401 fn display_tags(&self) -> Vec<[String; 2]> {
402 self.tags.clone()
403 }
404
405 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
406 if replace {
407 self.tags = tags.to_owned();
408 } else {
409 for tag in tags {
410 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
411 self.tags.remove(index);
412 };
413 }
414 self.tags.extend(tags.iter().cloned());
415 };
416 }
417}
418
419impl ImageTexture {
420 #[inline]
421 pub fn cite_path(mut self, cite_path: &str) -> Self {
422 self.cite_path = cite_path.to_string();
423 self
424 }
425
426 #[inline]
427 pub fn flip(mut self, horizontal_flip: bool, vertical_flip: bool) -> Self {
428 self.flip = [horizontal_flip, vertical_flip];
429 self
430 }
431
432 #[inline]
433 pub fn ctx(mut self, context: &Context) -> Self {
434 self.context = context.clone();
435 self
436 }
437
438 #[inline]
439 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
440 if replace {
441 self.tags = tags.to_owned();
442 } else {
443 for tag in tags {
444 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
445 self.tags.remove(index);
446 };
447 }
448 self.tags.extend(tags.iter().cloned());
449 };
450 self
451 }
452}
453
454#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
456pub enum BorderKind {
457 #[default]
459 Inside,
460 Middle,
462 Outside,
464}
465
466#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
468pub struct CustomRectConfig {
469 pub position_size_config: Option<PositionSizeConfig>,
471 pub clip_rect: Option<Option<PositionSizeConfig>>,
473 pub hidden: Option<bool>,
475 pub ignore_render_layer: Option<bool>,
477 pub rounding: Option<f32>,
479 pub color: Option<[u8; 3]>,
481 pub alpha: Option<u8>,
483 pub border_width: Option<f32>,
485 pub border_color: Option<[u8; 3]>,
487 pub border_alpha: Option<u8>,
489 pub border_kind: Option<BorderKind>,
491 pub tags: Option<Vec<[String; 2]>>,
493}
494
495impl CustomRectConfig {
496 pub fn from_custom_rect(custom_rect: &CustomRect) -> Self {
497 Self {
498 position_size_config: Some(
499 custom_rect.basic_front_resource_config.position_size_config,
500 ),
501 clip_rect: Some(custom_rect.basic_front_resource_config.clip_rect),
502 hidden: Some(custom_rect.display_info.hidden),
503 ignore_render_layer: Some(custom_rect.display_info.ignore_render_layer),
504 rounding: Some(custom_rect.rounding),
505 color: Some(custom_rect.color),
506 alpha: Some(custom_rect.alpha),
507 border_width: Some(custom_rect.border_width),
508 border_color: Some(custom_rect.border_color),
509 border_alpha: Some(custom_rect.border_alpha),
510 border_kind: Some(custom_rect.border_kind),
511 tags: Some(custom_rect.tags.clone()),
512 }
513 }
514
515 #[inline]
516 pub fn position_size_config(
517 mut self,
518 position_size_config: Option<PositionSizeConfig>,
519 ) -> Self {
520 self.position_size_config = position_size_config;
521 self
522 }
523
524 #[inline]
525 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
526 self.clip_rect = clip_rect;
527 self
528 }
529
530 #[inline]
531 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
532 self.hidden = hidden;
533 self
534 }
535
536 #[inline]
537 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
538 self.ignore_render_layer = ignore_render_layer;
539 self
540 }
541
542 #[inline]
543 pub fn rounding(mut self, rounding: Option<f32>) -> Self {
544 self.rounding = rounding;
545 self
546 }
547
548 #[inline]
549 pub fn color(mut self, color: Option<[u8; 3]>) -> Self {
550 self.color = color;
551 self
552 }
553
554 #[inline]
555 pub fn alpha(mut self, alpha: Option<u8>) -> Self {
556 self.alpha = alpha;
557 self
558 }
559
560 #[inline]
561 pub fn border_width(mut self, border_width: Option<f32>) -> Self {
562 self.border_width = border_width;
563 self
564 }
565
566 #[inline]
567 pub fn border_color(mut self, border_color: Option<[u8; 3]>) -> Self {
568 self.border_color = border_color;
569 self
570 }
571
572 #[inline]
573 pub fn border_alpha(mut self, border_alpha: Option<u8>) -> Self {
574 self.border_alpha = border_alpha;
575 self
576 }
577
578 #[inline]
579 pub fn border_kind(mut self, border_kind: Option<BorderKind>) -> Self {
580 self.border_kind = border_kind;
581 self
582 }
583
584 #[inline]
585 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
586 self.tags = tags;
587 self
588 }
589}
590
591#[derive(Debug, Clone, PartialEq, PartialOrd)]
593pub struct CustomRect {
594 pub basic_front_resource_config: BasicFrontResourceConfig,
596 pub position: [f32; 2],
598 pub size: [f32; 2],
600 pub display_info: DisplayInfo,
602 pub rounding: f32,
604 pub color: [u8; 3],
606 pub alpha: u8,
608 pub border_width: f32,
610 pub border_color: [u8; 3],
612 pub border_alpha: u8,
614 pub border_kind: BorderKind,
616 pub tags: Vec<[String; 2]>,
618}
619
620impl RustConstructorResource for CustomRect {
621 fn as_any(&self) -> &dyn Any {
622 self
623 }
624
625 fn as_any_mut(&mut self) -> &mut dyn Any {
626 self
627 }
628
629 fn display_display_info(&self) -> Option<DisplayInfo> {
630 Some(self.display_info)
631 }
632
633 fn modify_display_info(&mut self, display_info: DisplayInfo) {
634 self.display_info = display_info;
635 }
636
637 fn display_tags(&self) -> Vec<[String; 2]> {
638 self.tags.clone()
639 }
640
641 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
642 if replace {
643 self.tags = tags.to_owned();
644 } else {
645 for tag in tags {
646 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
647 self.tags.remove(index);
648 };
649 }
650 self.tags.extend(tags.iter().cloned());
651 };
652 }
653}
654
655impl BasicFrontResource for CustomRect {
656 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
657 self.basic_front_resource_config.clone()
658 }
659
660 fn display_position_size_config(&self) -> PositionSizeConfig {
661 self.basic_front_resource_config.position_size_config
662 }
663
664 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
665 self.basic_front_resource_config.clip_rect
666 }
667
668 fn display_position(&self) -> [f32; 2] {
669 self.position
670 }
671
672 fn display_size(&self) -> [f32; 2] {
673 self.size
674 }
675
676 fn modify_basic_front_resource_config(
677 &mut self,
678 basic_front_resource_config: BasicFrontResourceConfig,
679 ) {
680 self.basic_front_resource_config = basic_front_resource_config;
681 }
682
683 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
684 self.basic_front_resource_config.position_size_config = position_size_config;
685 }
686
687 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
688 self.basic_front_resource_config.clip_rect = clip_rect;
689 }
690}
691
692impl Default for CustomRect {
693 fn default() -> Self {
694 Self {
695 basic_front_resource_config: BasicFrontResourceConfig::default(),
696 position: [0_f32, 0_f32],
697 size: [0_f32, 0_f32],
698 display_info: DisplayInfo::default(),
699 rounding: 2_f32,
700 color: [255, 255, 255],
701 alpha: 255,
702 border_width: 2_f32,
703 border_color: [0, 0, 0],
704 border_alpha: 255,
705 border_kind: BorderKind::default(),
706 tags: Vec::new(),
707 }
708 }
709}
710
711impl CustomRect {
712 pub fn from_config(mut self, config: &CustomRectConfig) -> Self {
713 if let Some(position_size_config) = config.position_size_config {
714 self.basic_front_resource_config.position_size_config = position_size_config;
715 };
716 if let Some(clip_rect) = config.clip_rect {
717 self.basic_front_resource_config.clip_rect = clip_rect;
718 };
719 if let Some(hidden) = config.hidden {
720 self.display_info.hidden = hidden;
721 };
722 if let Some(ignore_render_layer) = config.ignore_render_layer {
723 self.display_info.ignore_render_layer = ignore_render_layer;
724 };
725 if let Some(rounding) = config.rounding {
726 self.rounding = rounding;
727 };
728 if let Some(color) = config.color {
729 self.color = color;
730 };
731 if let Some(alpha) = config.alpha {
732 self.alpha = alpha;
733 };
734 if let Some(border_width) = config.border_width {
735 self.border_width = border_width;
736 };
737 if let Some(border_color) = config.border_color {
738 self.border_color = border_color;
739 };
740 if let Some(border_alpha) = config.border_alpha {
741 self.border_alpha = border_alpha;
742 };
743 if let Some(border_kind) = config.border_kind {
744 self.border_kind = border_kind;
745 };
746 if let Some(tags) = config.tags.clone() {
747 self.tags = tags;
748 };
749 self
750 }
751
752 #[inline]
753 pub fn basic_front_resource_config(
754 mut self,
755 basic_front_resource_config: &BasicFrontResourceConfig,
756 ) -> Self {
757 self.basic_front_resource_config = basic_front_resource_config.clone();
758 self
759 }
760
761 #[inline]
762 pub fn hidden(mut self, hidden: bool) -> Self {
763 self.display_info.hidden = hidden;
764 self
765 }
766
767 #[inline]
768 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
769 self.display_info.ignore_render_layer = ignore_render_layer;
770 self
771 }
772
773 #[inline]
774 pub fn rounding(mut self, rounding: f32) -> Self {
775 self.rounding = rounding;
776 self
777 }
778
779 #[inline]
780 pub fn color(mut self, r: u8, g: u8, b: u8) -> Self {
781 self.color = [r, g, b];
782 self
783 }
784
785 #[inline]
786 pub fn alpha(mut self, alpha: u8) -> Self {
787 self.alpha = alpha;
788 self
789 }
790
791 #[inline]
792 pub fn border_width(mut self, border_width: f32) -> Self {
793 self.border_width = border_width;
794 self
795 }
796
797 #[inline]
798 pub fn border_color(mut self, r: u8, g: u8, b: u8) -> Self {
799 self.border_color = [r, g, b];
800 self
801 }
802
803 #[inline]
804 pub fn border_alpha(mut self, border_alpha: u8) -> Self {
805 self.border_alpha = border_alpha;
806 self
807 }
808
809 #[inline]
810 pub fn border_kind(mut self, border_kind: BorderKind) -> Self {
811 self.border_kind = border_kind;
812 self
813 }
814
815 #[inline]
816 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
817 if replace {
818 self.tags = tags.to_owned();
819 } else {
820 for tag in tags {
821 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
822 self.tags.remove(index);
823 };
824 }
825 self.tags.extend(tags.iter().cloned());
826 };
827 self
828 }
829}
830
831#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
833pub struct ImageConfig {
834 pub position_size_config: Option<PositionSizeConfig>,
836 pub clip_rect: Option<Option<PositionSizeConfig>>,
838 pub hidden: Option<bool>,
840 pub ignore_render_layer: Option<bool>,
842 pub alpha: Option<u8>,
844 pub overlay_color: Option<[u8; 3]>,
846 pub overlay_alpha: Option<u8>,
848 pub background_color: Option<[u8; 3]>,
850 pub background_alpha: Option<u8>,
852 pub rotate_angle: Option<f32>,
854 pub rotate_center: Option<[f32; 2]>,
856 pub cite_texture: Option<String>,
858 pub tags: Option<Vec<[String; 2]>>,
860}
861
862impl ImageConfig {
863 pub fn from_image(image: &Image) -> Self {
864 Self {
865 position_size_config: Some(image.basic_front_resource_config.position_size_config),
866 clip_rect: Some(image.basic_front_resource_config.clip_rect),
867 hidden: Some(image.display_info.hidden),
868 ignore_render_layer: Some(image.display_info.ignore_render_layer),
869 alpha: Some(image.alpha),
870 overlay_color: Some(image.overlay_color),
871 overlay_alpha: Some(image.overlay_alpha),
872 background_color: Some(image.background_color),
873 background_alpha: Some(image.background_alpha),
874 rotate_angle: Some(image.rotate_angle),
875 rotate_center: Some(image.rotate_center),
876 cite_texture: Some(image.cite_texture.clone()),
877 tags: Some(image.tags.clone()),
878 }
879 }
880
881 #[inline]
882 pub fn position_size_config(
883 mut self,
884 position_size_config: Option<PositionSizeConfig>,
885 ) -> Self {
886 self.position_size_config = position_size_config;
887 self
888 }
889
890 #[inline]
891 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
892 self.clip_rect = clip_rect;
893 self
894 }
895
896 #[inline]
897 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
898 self.hidden = hidden;
899 self
900 }
901
902 #[inline]
903 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
904 self.ignore_render_layer = ignore_render_layer;
905 self
906 }
907
908 #[inline]
909 pub fn alpha(mut self, alpha: Option<u8>) -> Self {
910 self.alpha = alpha;
911 self
912 }
913
914 #[inline]
915 pub fn overlay_color(mut self, overlay_color: Option<[u8; 3]>) -> Self {
916 self.overlay_color = overlay_color;
917 self
918 }
919
920 #[inline]
921 pub fn overlay_alpha(mut self, overlay_alpha: Option<u8>) -> Self {
922 self.overlay_alpha = overlay_alpha;
923 self
924 }
925
926 #[inline]
927 pub fn background_color(mut self, background_color: Option<[u8; 3]>) -> Self {
928 self.background_color = background_color;
929 self
930 }
931
932 #[inline]
933 pub fn background_alpha(mut self, background_alpha: Option<u8>) -> Self {
934 self.background_alpha = background_alpha;
935 self
936 }
937
938 #[inline]
939 pub fn rotate_angle(mut self, rotate_angle: Option<f32>) -> Self {
940 self.rotate_angle = rotate_angle;
941 self
942 }
943
944 #[inline]
945 pub fn rotate_center(mut self, rotate_center: Option<[f32; 2]>) -> Self {
946 self.rotate_center = rotate_center;
947 self
948 }
949
950 #[inline]
951 pub fn cite_texture(mut self, cite_texture: Option<String>) -> Self {
952 self.cite_texture = cite_texture;
953 self
954 }
955
956 #[inline]
957 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
958 self.tags = tags;
959 self
960 }
961}
962
963#[derive(Debug, Clone, PartialEq)]
965pub struct Image {
966 pub basic_front_resource_config: BasicFrontResourceConfig,
968 pub position: [f32; 2],
970 pub size: [f32; 2],
972 pub display_info: DisplayInfo,
974 pub texture: Option<DebugTextureHandle>,
976 pub alpha: u8,
978 pub overlay_color: [u8; 3],
980 pub overlay_alpha: u8,
982 pub background_color: [u8; 3],
984 pub background_alpha: u8,
986 pub rotate_angle: f32,
988 pub rotate_center: [f32; 2],
990 pub cite_texture: String,
992 pub last_frame_cite_texture: String,
994 pub tags: Vec<[String; 2]>,
996}
997
998impl RustConstructorResource for Image {
999 fn as_any(&self) -> &dyn Any {
1000 self
1001 }
1002
1003 fn as_any_mut(&mut self) -> &mut dyn Any {
1004 self
1005 }
1006
1007 fn display_display_info(&self) -> Option<DisplayInfo> {
1008 Some(self.display_info)
1009 }
1010
1011 fn modify_display_info(&mut self, display_info: DisplayInfo) {
1012 self.display_info = display_info;
1013 }
1014
1015 fn display_tags(&self) -> Vec<[String; 2]> {
1016 self.tags.clone()
1017 }
1018
1019 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1020 if replace {
1021 self.tags = tags.to_owned();
1022 } else {
1023 for tag in tags {
1024 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1025 self.tags.remove(index);
1026 };
1027 }
1028 self.tags.extend(tags.iter().cloned());
1029 };
1030 }
1031}
1032
1033impl BasicFrontResource for Image {
1034 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
1035 self.basic_front_resource_config.clone()
1036 }
1037
1038 fn display_position_size_config(&self) -> PositionSizeConfig {
1039 self.basic_front_resource_config.position_size_config
1040 }
1041
1042 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
1043 self.basic_front_resource_config.clip_rect
1044 }
1045
1046 fn display_position(&self) -> [f32; 2] {
1047 self.position
1048 }
1049
1050 fn display_size(&self) -> [f32; 2] {
1051 self.size
1052 }
1053
1054 fn modify_basic_front_resource_config(
1055 &mut self,
1056 basic_front_resource_config: BasicFrontResourceConfig,
1057 ) {
1058 self.basic_front_resource_config = basic_front_resource_config;
1059 }
1060
1061 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
1062 self.basic_front_resource_config.position_size_config = position_size_config;
1063 }
1064
1065 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
1066 self.basic_front_resource_config.clip_rect = clip_rect;
1067 }
1068}
1069
1070impl Default for Image {
1071 fn default() -> Self {
1072 Self {
1073 basic_front_resource_config: BasicFrontResourceConfig::default(),
1074 position: [0_f32, 0_f32],
1075 size: [0_f32, 0_f32],
1076 display_info: DisplayInfo::default(),
1077 texture: None,
1078 alpha: 255,
1079 overlay_color: [255, 255, 255],
1080 overlay_alpha: 255,
1081 background_color: [0, 0, 0],
1082 background_alpha: 0,
1083 rotate_angle: 0_f32,
1084 rotate_center: [0_f32, 0_f32],
1085 cite_texture: String::from("rust_constructor::ImageTexture"),
1086 last_frame_cite_texture: String::from("rust_constructor::ImageTexture"),
1087 tags: Vec::new(),
1088 }
1089 }
1090}
1091
1092impl Image {
1093 pub fn from_config(mut self, config: &ImageConfig) -> Self {
1094 if let Some(position_size_config) = config.position_size_config {
1095 self.basic_front_resource_config.position_size_config = position_size_config;
1096 };
1097 if let Some(clip_rect) = config.clip_rect {
1098 self.basic_front_resource_config.clip_rect = clip_rect;
1099 };
1100 if let Some(hidden) = config.hidden {
1101 self.display_info.hidden = hidden;
1102 };
1103 if let Some(ignore_render_layer) = config.ignore_render_layer {
1104 self.display_info.ignore_render_layer = ignore_render_layer;
1105 };
1106 if let Some(alpha) = config.alpha {
1107 self.alpha = alpha;
1108 };
1109 if let Some(overlay_color) = config.overlay_color {
1110 self.overlay_color = overlay_color;
1111 };
1112 if let Some(overlay_alpha) = config.overlay_alpha {
1113 self.overlay_alpha = overlay_alpha;
1114 };
1115 if let Some(background_color) = config.background_color {
1116 self.background_color = background_color;
1117 };
1118 if let Some(background_alpha) = config.background_alpha {
1119 self.background_alpha = background_alpha;
1120 };
1121 if let Some(rotate_angle) = config.rotate_angle {
1122 self.rotate_angle = rotate_angle;
1123 };
1124 if let Some(rotate_center) = config.rotate_center {
1125 self.rotate_center = rotate_center;
1126 };
1127 if let Some(cite_texture) = config.cite_texture.clone() {
1128 self.cite_texture = cite_texture;
1129 };
1130 if let Some(tags) = config.tags.clone() {
1131 self.tags = tags;
1132 };
1133 self
1134 }
1135
1136 #[inline]
1137 pub fn basic_front_resource_config(
1138 mut self,
1139 basic_front_resource_config: &BasicFrontResourceConfig,
1140 ) -> Self {
1141 self.basic_front_resource_config = basic_front_resource_config.clone();
1142 self
1143 }
1144
1145 #[inline]
1146 pub fn hidden(mut self, hidden: bool) -> Self {
1147 self.display_info.hidden = hidden;
1148 self
1149 }
1150
1151 #[inline]
1152 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
1153 self.display_info.ignore_render_layer = ignore_render_layer;
1154 self
1155 }
1156
1157 #[inline]
1158 pub fn alpha(mut self, alpha: u8) -> Self {
1159 self.alpha = alpha;
1160 self
1161 }
1162
1163 #[inline]
1164 pub fn overlay_color(mut self, r: u8, g: u8, b: u8) -> Self {
1165 self.overlay_color = [r, g, b];
1166 self
1167 }
1168
1169 #[inline]
1170 pub fn overlay_alpha(mut self, overlay_alpha: u8) -> Self {
1171 self.overlay_alpha = overlay_alpha;
1172 self
1173 }
1174
1175 #[inline]
1176 pub fn background_color(mut self, r: u8, g: u8, b: u8) -> Self {
1177 self.background_color = [r, g, b];
1178 self
1179 }
1180
1181 #[inline]
1182 pub fn background_alpha(mut self, background_alpha: u8) -> Self {
1183 self.background_alpha = background_alpha;
1184 self
1185 }
1186
1187 #[inline]
1188 pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1189 self.rotate_angle = rotate_angle;
1190 self
1191 }
1192
1193 #[inline]
1194 pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1195 self.rotate_center = [x, y];
1196 self
1197 }
1198
1199 #[inline]
1200 pub fn cite_texture(mut self, cite_texture: &str) -> Self {
1201 self.cite_texture = cite_texture.to_string();
1202 self
1203 }
1204
1205 #[inline]
1206 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1207 if replace {
1208 self.tags = tags.to_owned();
1209 } else {
1210 for tag in tags {
1211 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1212 self.tags.remove(index);
1213 };
1214 }
1215 self.tags.extend(tags.iter().cloned());
1216 };
1217 self
1218 }
1219}
1220
1221#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1223pub enum HyperlinkSelectMethod {
1224 All(String),
1226 Segment(Vec<(usize, String)>),
1228}
1229
1230#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1232pub struct TextConfig {
1233 pub position_size_config: Option<PositionSizeConfig>,
1235 pub clip_rect: Option<Option<PositionSizeConfig>>,
1237 pub hidden: Option<bool>,
1239 pub ignore_render_layer: Option<bool>,
1241 pub content: Option<String>,
1243 pub font_size: Option<f32>,
1245 pub color: Option<[u8; 3]>,
1247 pub alpha: Option<u8>,
1249 pub background_color: Option<[u8; 3]>,
1251 pub background_alpha: Option<u8>,
1253 pub background_rounding: Option<f32>,
1255 pub font: Option<String>,
1257 pub selectable: Option<bool>,
1259 pub hyperlink_text: Option<Vec<(String, HyperlinkSelectMethod)>>,
1261 pub auto_fit: Option<[bool; 2]>,
1263 pub tags: Option<Vec<[String; 2]>>,
1265}
1266
1267impl TextConfig {
1268 pub fn from_text(text: &Text) -> Self {
1269 Self {
1270 position_size_config: Some(text.basic_front_resource_config.position_size_config),
1271 clip_rect: Some(text.basic_front_resource_config.clip_rect),
1272 hidden: Some(text.display_info.hidden),
1273 ignore_render_layer: Some(text.display_info.ignore_render_layer),
1274 content: Some(text.content.clone()),
1275 font_size: Some(text.font_size),
1276 color: Some(text.color),
1277 alpha: Some(text.alpha),
1278 background_color: Some(text.background_color),
1279 background_alpha: Some(text.background_alpha),
1280 background_rounding: Some(text.background_rounding),
1281 font: Some(text.font.clone()),
1282 selectable: Some(text.selectable),
1283 hyperlink_text: Some(text.hyperlink_text.clone()),
1284 auto_fit: Some(text.auto_fit),
1285 tags: Some(text.tags.clone()),
1286 }
1287 }
1288
1289 #[inline]
1290 pub fn position_size_config(
1291 mut self,
1292 position_size_config: Option<PositionSizeConfig>,
1293 ) -> Self {
1294 self.position_size_config = position_size_config;
1295 self
1296 }
1297
1298 #[inline]
1299 pub fn clip_rect(mut self, clip_rect: Option<Option<PositionSizeConfig>>) -> Self {
1300 self.clip_rect = clip_rect;
1301 self
1302 }
1303
1304 #[inline]
1305 pub fn hidden(mut self, hidden: Option<bool>) -> Self {
1306 self.hidden = hidden;
1307 self
1308 }
1309
1310 #[inline]
1311 pub fn ignore_render_layer(mut self, ignore_render_layer: Option<bool>) -> Self {
1312 self.ignore_render_layer = ignore_render_layer;
1313 self
1314 }
1315
1316 #[inline]
1317 pub fn content(mut self, content: Option<String>) -> Self {
1318 self.content = content;
1319 self
1320 }
1321
1322 #[inline]
1323 pub fn font_size(mut self, font_size: Option<f32>) -> Self {
1324 self.font_size = font_size;
1325 self
1326 }
1327
1328 #[inline]
1329 pub fn color(mut self, color: Option<[u8; 3]>) -> Self {
1330 self.color = color;
1331 self
1332 }
1333
1334 #[inline]
1335 pub fn alpha(mut self, alpha: Option<u8>) -> Self {
1336 self.alpha = alpha;
1337 self
1338 }
1339
1340 #[inline]
1341 pub fn background_color(mut self, background_color: Option<[u8; 3]>) -> Self {
1342 self.background_color = background_color;
1343 self
1344 }
1345
1346 #[inline]
1347 pub fn background_alpha(mut self, background_alpha: Option<u8>) -> Self {
1348 self.background_alpha = background_alpha;
1349 self
1350 }
1351
1352 #[inline]
1353 pub fn background_rounding(mut self, background_rounding: Option<f32>) -> Self {
1354 self.background_rounding = background_rounding;
1355 self
1356 }
1357
1358 #[inline]
1359 pub fn font(mut self, font: Option<String>) -> Self {
1360 self.font = font;
1361 self
1362 }
1363
1364 #[inline]
1365 pub fn selectable(mut self, selectable: Option<bool>) -> Self {
1366 self.selectable = selectable;
1367 self
1368 }
1369
1370 #[inline]
1371 pub fn hyperlink_text(
1372 mut self,
1373 hyperlink_text: Option<Vec<(String, HyperlinkSelectMethod)>>,
1374 ) -> Self {
1375 self.hyperlink_text = hyperlink_text;
1376 self
1377 }
1378
1379 #[inline]
1380 pub fn auto_fit(mut self, auto_fit: Option<[bool; 2]>) -> Self {
1381 self.auto_fit = auto_fit;
1382 self
1383 }
1384
1385 #[inline]
1386 pub fn tags(mut self, tags: Option<Vec<[String; 2]>>) -> Self {
1387 self.tags = tags;
1388 self
1389 }
1390}
1391
1392#[derive(Debug, Clone, PartialEq, PartialOrd)]
1394pub struct Text {
1395 pub basic_front_resource_config: BasicFrontResourceConfig,
1397 pub position: [f32; 2],
1399 pub size: [f32; 2],
1401 pub display_info: DisplayInfo,
1403 pub content: String,
1405 pub font_size: f32,
1407 pub color: [u8; 3],
1409 pub alpha: u8,
1411 pub background_color: [u8; 3],
1413 pub background_alpha: u8,
1415 pub background_rounding: f32,
1417 pub font: String,
1419 pub selectable: bool,
1421 pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1423 pub hyperlink_index: Vec<(usize, usize, String)>,
1425 pub auto_fit: [bool; 2],
1427 pub last_frame_content: String,
1429 pub selection: Option<(usize, usize)>,
1431 pub truncate_size: [f32; 2],
1433 pub actual_size: [f32; 2],
1435 pub tags: Vec<[String; 2]>,
1437}
1438
1439impl RustConstructorResource for Text {
1440 fn as_any(&self) -> &dyn Any {
1441 self
1442 }
1443
1444 fn as_any_mut(&mut self) -> &mut dyn Any {
1445 self
1446 }
1447
1448 fn display_display_info(&self) -> Option<DisplayInfo> {
1449 Some(self.display_info)
1450 }
1451
1452 fn modify_display_info(&mut self, display_info: DisplayInfo) {
1453 self.display_info = display_info;
1454 }
1455
1456 fn display_tags(&self) -> Vec<[String; 2]> {
1457 self.tags.clone()
1458 }
1459
1460 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1461 if replace {
1462 self.tags = tags.to_owned();
1463 } else {
1464 for tag in tags {
1465 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1466 self.tags.remove(index);
1467 };
1468 }
1469 self.tags.extend(tags.iter().cloned());
1470 };
1471 }
1472}
1473
1474impl BasicFrontResource for Text {
1475 fn display_basic_front_resource_config(&self) -> BasicFrontResourceConfig {
1476 self.basic_front_resource_config.clone()
1477 }
1478
1479 fn display_position_size_config(&self) -> PositionSizeConfig {
1480 self.basic_front_resource_config.position_size_config
1481 }
1482
1483 fn display_clip_rect(&self) -> Option<PositionSizeConfig> {
1484 self.basic_front_resource_config.clip_rect
1485 }
1486
1487 fn display_position(&self) -> [f32; 2] {
1488 self.position
1489 }
1490
1491 fn display_size(&self) -> [f32; 2] {
1492 self.size
1493 }
1494
1495 fn modify_basic_front_resource_config(
1496 &mut self,
1497 basic_front_resource_config: BasicFrontResourceConfig,
1498 ) {
1499 self.basic_front_resource_config = basic_front_resource_config;
1500 }
1501
1502 fn modify_position_size_config(&mut self, position_size_config: PositionSizeConfig) {
1503 self.basic_front_resource_config.position_size_config = position_size_config;
1504 }
1505
1506 fn modify_clip_rect(&mut self, clip_rect: Option<PositionSizeConfig>) {
1507 self.basic_front_resource_config.clip_rect = clip_rect;
1508 }
1509}
1510
1511impl Default for Text {
1512 fn default() -> Self {
1513 Self {
1514 basic_front_resource_config: BasicFrontResourceConfig::default(),
1515 position: [0_f32, 0_f32],
1516 size: [0_f32, 0_f32],
1517 display_info: DisplayInfo::default(),
1518 content: String::from("Hello world"),
1519 font_size: 16_f32,
1520 color: [255, 255, 255],
1521 alpha: 255,
1522 background_color: [0, 0, 0],
1523 background_alpha: 0,
1524 background_rounding: 2_f32,
1525 font: String::new(),
1526 selectable: true,
1527 auto_fit: [true, true],
1528 hyperlink_text: Vec::new(),
1529 hyperlink_index: Vec::new(),
1530 last_frame_content: String::from(""),
1531 selection: None,
1532 truncate_size: [0_f32, 0_f32],
1533 actual_size: [0_f32, 0_f32],
1534 tags: Vec::new(),
1535 }
1536 }
1537}
1538
1539impl Text {
1540 pub fn from_config(mut self, config: &TextConfig) -> Self {
1541 if let Some(position_size_config) = config.position_size_config {
1542 self.basic_front_resource_config.position_size_config = position_size_config;
1543 };
1544 if let Some(clip_rect) = config.clip_rect {
1545 self.basic_front_resource_config.clip_rect = clip_rect;
1546 };
1547 if let Some(hidden) = config.hidden {
1548 self.display_info.hidden = hidden;
1549 };
1550 if let Some(ignore_render_layer) = config.ignore_render_layer {
1551 self.display_info.ignore_render_layer = ignore_render_layer;
1552 };
1553 if let Some(content) = config.content.clone() {
1554 self.content = content;
1555 };
1556 if let Some(font_size) = config.font_size {
1557 self.font_size = font_size;
1558 };
1559 if let Some(color) = config.color {
1560 self.color = color;
1561 };
1562 if let Some(alpha) = config.alpha {
1563 self.alpha = alpha;
1564 };
1565 if let Some(background_color) = config.background_color {
1566 self.background_color = background_color;
1567 };
1568 if let Some(background_alpha) = config.background_alpha {
1569 self.background_alpha = background_alpha;
1570 };
1571 if let Some(background_rounding) = config.background_rounding {
1572 self.background_rounding = background_rounding;
1573 };
1574 if let Some(font) = config.font.clone() {
1575 self.font = font;
1576 };
1577 if let Some(selectable) = config.selectable {
1578 self.selectable = selectable;
1579 };
1580 if let Some(hyperlink_text) = config.hyperlink_text.clone() {
1581 self.hyperlink_text = hyperlink_text;
1582 };
1583 if let Some(auto_fit) = config.auto_fit {
1584 self.auto_fit = auto_fit;
1585 };
1586 if let Some(tags) = config.tags.clone() {
1587 self.tags = tags;
1588 };
1589 self
1590 }
1591
1592 #[inline]
1593 pub fn basic_front_resource_config(
1594 mut self,
1595 basic_front_resource_config: &BasicFrontResourceConfig,
1596 ) -> Self {
1597 self.basic_front_resource_config = basic_front_resource_config.clone();
1598 self
1599 }
1600
1601 #[inline]
1602 pub fn hidden(mut self, hidden: bool) -> Self {
1603 self.display_info.hidden = hidden;
1604 self
1605 }
1606
1607 #[inline]
1608 pub fn ignore_render_layer(mut self, ignore_render_layer: bool) -> Self {
1609 self.display_info.ignore_render_layer = ignore_render_layer;
1610 self
1611 }
1612
1613 #[inline]
1614 pub fn content(mut self, content: &str) -> Self {
1615 self.content = content.to_string();
1616 self
1617 }
1618
1619 #[inline]
1620 pub fn font_size(mut self, font_size: f32) -> Self {
1621 self.font_size = font_size;
1622 self
1623 }
1624
1625 #[inline]
1626 pub fn color(mut self, r: u8, g: u8, b: u8) -> Self {
1627 self.color = [r, g, b];
1628 self
1629 }
1630
1631 #[inline]
1632 pub fn alpha(mut self, alpha: u8) -> Self {
1633 self.alpha = alpha;
1634 self
1635 }
1636
1637 #[inline]
1638 pub fn background_color(mut self, r: u8, g: u8, b: u8) -> Self {
1639 self.background_color = [r, g, b];
1640 self
1641 }
1642
1643 #[inline]
1644 pub fn background_alpha(mut self, alpha: u8) -> Self {
1645 self.background_alpha = alpha;
1646 self
1647 }
1648
1649 #[inline]
1650 pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1651 self.background_rounding = background_rounding;
1652 self
1653 }
1654
1655 #[inline]
1656 pub fn font(mut self, font: &str) -> Self {
1657 self.font = font.to_string();
1658 self
1659 }
1660
1661 #[inline]
1662 pub fn selectable(mut self, selectable: bool) -> Self {
1663 self.selectable = selectable;
1664 self
1665 }
1666
1667 #[inline]
1668 pub fn push_hyperlink_text(
1669 mut self,
1670 target_text: &str,
1671 select_method: HyperlinkSelectMethod,
1672 ) -> Self {
1673 self.hyperlink_text
1674 .push((target_text.to_string(), select_method));
1675 self
1676 }
1677
1678 #[inline]
1679 pub fn hyperlink_text(mut self, hyperlink_text: Vec<(String, HyperlinkSelectMethod)>) -> Self {
1680 self.hyperlink_text = hyperlink_text;
1681 self
1682 }
1683
1684 #[inline]
1685 pub fn auto_fit(mut self, x: bool, y: bool) -> Self {
1686 self.auto_fit = [x, y];
1687 self
1688 }
1689
1690 #[inline]
1691 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1692 if replace {
1693 self.tags = tags.to_owned();
1694 } else {
1695 for tag in tags {
1696 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1697 self.tags.remove(index);
1698 };
1699 }
1700 self.tags.extend(tags.iter().cloned());
1701 };
1702 self
1703 }
1704}
1705
1706#[derive(Debug, Clone, PartialEq, PartialOrd)]
1708pub struct Variable<T> {
1709 pub value: Option<T>,
1711 pub tags: Vec<[String; 2]>,
1713}
1714
1715impl<T: Debug + 'static> RustConstructorResource for Variable<T> {
1716 fn as_any(&self) -> &dyn Any {
1717 self
1718 }
1719
1720 fn as_any_mut(&mut self) -> &mut dyn Any {
1721 self
1722 }
1723
1724 fn display_display_info(&self) -> Option<DisplayInfo> {
1725 None
1726 }
1727
1728 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1729
1730 fn display_tags(&self) -> Vec<[String; 2]> {
1731 self.tags.clone()
1732 }
1733
1734 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1735 if replace {
1736 self.tags = tags.to_owned();
1737 } else {
1738 for tag in tags {
1739 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1740 self.tags.remove(index);
1741 };
1742 }
1743 self.tags.extend(tags.iter().cloned());
1744 };
1745 }
1746}
1747
1748impl<T> Default for Variable<T> {
1749 fn default() -> Self {
1750 Variable {
1751 value: None,
1752 tags: Vec::new(),
1753 }
1754 }
1755}
1756
1757impl<T> Variable<T> {
1758 #[inline]
1759 pub fn value(mut self, value: Option<T>) -> Self {
1760 self.value = value;
1761 self
1762 }
1763
1764 #[inline]
1765 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1766 if replace {
1767 self.tags = tags.to_owned();
1768 } else {
1769 for tag in tags {
1770 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1771 self.tags.remove(index);
1772 };
1773 }
1774 self.tags.extend(tags.iter().cloned());
1775 };
1776 self
1777 }
1778}
1779
1780#[derive(Clone, Debug, Default, PartialEq)]
1782pub struct Font {
1783 pub font_definitions: FontDefinitions,
1785 pub path: String,
1787 pub tags: Vec<[String; 2]>,
1789}
1790
1791impl RustConstructorResource for Font {
1792 fn as_any(&self) -> &dyn Any {
1793 self
1794 }
1795
1796 fn as_any_mut(&mut self) -> &mut dyn Any {
1797 self
1798 }
1799
1800 fn display_display_info(&self) -> Option<DisplayInfo> {
1801 None
1802 }
1803
1804 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1805
1806 fn display_tags(&self) -> Vec<[String; 2]> {
1807 self.tags.clone()
1808 }
1809
1810 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1811 if replace {
1812 self.tags = tags.to_owned();
1813 } else {
1814 for tag in tags {
1815 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1816 self.tags.remove(index);
1817 };
1818 }
1819 self.tags.extend(tags.iter().cloned());
1820 };
1821 }
1822}
1823
1824impl Font {
1825 #[inline]
1826 pub fn path(mut self, path: &str) -> Self {
1827 self.path = path.to_string();
1828 self
1829 }
1830
1831 #[inline]
1832 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1833 if replace {
1834 self.tags = tags.to_owned();
1835 } else {
1836 for tag in tags {
1837 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1838 self.tags.remove(index);
1839 };
1840 }
1841 self.tags.extend(tags.iter().cloned());
1842 };
1843 self
1844 }
1845}
1846
1847#[derive(Debug, Clone, PartialEq, PartialOrd)]
1849pub struct SplitTime {
1850 pub time: [f32; 2],
1852 pub tags: Vec<[String; 2]>,
1854}
1855
1856impl RustConstructorResource for SplitTime {
1857 fn as_any(&self) -> &dyn Any {
1858 self
1859 }
1860
1861 fn as_any_mut(&mut self) -> &mut dyn Any {
1862 self
1863 }
1864
1865 fn display_display_info(&self) -> Option<DisplayInfo> {
1866 None
1867 }
1868
1869 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1870
1871 fn display_tags(&self) -> Vec<[String; 2]> {
1872 self.tags.clone()
1873 }
1874
1875 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1876 if replace {
1877 self.tags = tags.to_owned();
1878 } else {
1879 for tag in tags {
1880 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1881 self.tags.remove(index);
1882 };
1883 }
1884 self.tags.extend(tags.iter().cloned());
1885 };
1886 }
1887}
1888
1889impl Default for SplitTime {
1890 fn default() -> Self {
1891 Self {
1892 time: [0_f32, 0_f32],
1893 tags: Vec::new(),
1894 }
1895 }
1896}
1897
1898impl SplitTime {
1899 #[inline]
1900 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1901 if replace {
1902 self.tags = tags.to_owned();
1903 } else {
1904 for tag in tags {
1905 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1906 self.tags.remove(index);
1907 };
1908 }
1909 self.tags.extend(tags.iter().cloned());
1910 };
1911 self
1912 }
1913}
1914
1915#[derive(Clone, Debug, PartialEq, PartialOrd)]
1917pub enum BackgroundType {
1918 Image(ImageConfig),
1920 CustomRect(CustomRectConfig),
1922}
1923
1924impl Default for BackgroundType {
1925 fn default() -> Self {
1926 BackgroundType::CustomRect(CustomRectConfig::default())
1927 }
1928}
1929
1930#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
1932pub struct Background {
1933 pub background_type: BackgroundType,
1935 pub auto_update: bool,
1937 pub use_background_tags: bool,
1939 pub tags: Vec<[String; 2]>,
1941}
1942
1943impl RustConstructorResource for Background {
1944 fn as_any(&self) -> &dyn Any {
1945 self
1946 }
1947
1948 fn as_any_mut(&mut self) -> &mut dyn Any {
1949 self
1950 }
1951
1952 fn display_display_info(&self) -> Option<DisplayInfo> {
1953 None
1954 }
1955
1956 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
1957
1958 fn display_tags(&self) -> Vec<[String; 2]> {
1959 self.tags.clone()
1960 }
1961
1962 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
1963 if replace {
1964 self.tags = tags.to_owned();
1965 } else {
1966 for tag in tags {
1967 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
1968 self.tags.remove(index);
1969 };
1970 }
1971 self.tags.extend(tags.iter().cloned());
1972 };
1973 }
1974}
1975
1976impl Background {
1977 #[inline]
1978 pub fn background_type(mut self, background_type: &BackgroundType) -> Self {
1979 self.background_type = background_type.clone();
1980 self
1981 }
1982
1983 #[inline]
1984 pub fn auto_update(mut self, auto_update: bool) -> Self {
1985 self.auto_update = auto_update;
1986 self
1987 }
1988
1989 #[inline]
1990 pub fn use_background_tags(mut self, use_background_tags: bool) -> Self {
1991 self.use_background_tags = use_background_tags;
1992 self
1993 }
1994
1995 #[inline]
1996 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
1997 if replace {
1998 self.tags = tags.to_owned();
1999 } else {
2000 for tag in tags {
2001 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2002 self.tags.remove(index);
2003 };
2004 }
2005 self.tags.extend(tags.iter().cloned());
2006 };
2007 self
2008 }
2009}
2010
2011#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2013pub enum ScrollLengthMethod {
2014 Fixed(f32),
2016 AutoFit,
2018}
2019
2020#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2022pub enum ClickAim {
2023 Move,
2025 TopResize,
2027 BottomResize,
2029 LeftResize,
2031 RightResize,
2033 LeftTopResize,
2035 RightTopResize,
2037 LeftBottomResize,
2039 RightBottomResize,
2041}
2042
2043#[derive(Debug, Clone, PartialEq, PartialOrd)]
2044pub enum ScrollBarDisplayMethod {
2046 Always(BackgroundType, [f32; 2], f32),
2048 OnlyScroll(BackgroundType, [f32; 2], f32),
2050 Hidden,
2052}
2053
2054#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2056pub enum PanelMargin {
2057 Vertical([f32; 4], bool),
2059 Horizontal([f32; 4], bool),
2061 None([f32; 4], bool),
2063}
2064
2065#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2067pub struct PanelLayout {
2068 pub panel_margin: PanelMargin,
2069 pub panel_location: PanelLocation,
2070}
2071
2072#[derive(Debug, Clone, PartialEq, PartialOrd)]
2074pub enum CustomPanelLayout {
2075 Type(String, PanelLayout),
2077 Id(RustConstructorId, PanelLayout),
2079}
2080
2081#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2083pub enum PanelLocation {
2084 Absolute([f32; 2]),
2086 Relative([[u32; 2]; 2]),
2088}
2089
2090#[derive(Debug, Clone, PartialEq, PartialOrd)]
2092pub struct ResourcePanel {
2093 pub resizable: [bool; 4],
2095 pub background: BackgroundType,
2097 pub min_size: [f32; 2],
2099 pub max_size: Option<[f32; 2]>,
2101 pub movable: [bool; 2],
2103 pub scroll_length_method: [Option<ScrollLengthMethod>; 2],
2105 pub scroll_sensitivity: f32,
2107 pub use_smooth_scroll_delta: bool,
2109 pub scroll_bar_display_method: ScrollBarDisplayMethod,
2111 pub overall_layout: PanelLayout,
2113 pub custom_layout: Vec<CustomPanelLayout>,
2115 pub scroll_length: [f32; 2],
2117 pub scroll_progress: [f32; 2],
2119 pub last_frame_mouse_status: Option<([f32; 2], ClickAim, [f32; 2])>,
2121 pub scrolled: [bool; 2],
2123 pub scroll_bar_alpha: [u8; 2],
2125 pub tags: Vec<[String; 2]>,
2127}
2128
2129impl RustConstructorResource for ResourcePanel {
2130 fn as_any(&self) -> &dyn Any {
2131 self
2132 }
2133
2134 fn as_any_mut(&mut self) -> &mut dyn Any {
2135 self
2136 }
2137
2138 fn display_display_info(&self) -> Option<DisplayInfo> {
2139 None
2140 }
2141
2142 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
2143
2144 fn display_tags(&self) -> Vec<[String; 2]> {
2145 self.tags.clone()
2146 }
2147
2148 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
2149 if replace {
2150 self.tags = tags.to_owned();
2151 } else {
2152 for tag in tags {
2153 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2154 self.tags.remove(index);
2155 };
2156 }
2157 self.tags.extend(tags.iter().cloned());
2158 };
2159 }
2160}
2161
2162impl Default for ResourcePanel {
2163 fn default() -> Self {
2164 Self {
2165 resizable: [true, true, true, true],
2166 background: BackgroundType::default(),
2167 min_size: [10_f32, 10_f32],
2168 max_size: None,
2169 movable: [true, true],
2170 scroll_length_method: [None, None],
2171 scroll_sensitivity: 0_f32,
2172 use_smooth_scroll_delta: true,
2173 scroll_bar_display_method: ScrollBarDisplayMethod::OnlyScroll(
2174 BackgroundType::default(),
2175 [4_f32, 2_f32],
2176 4_f32,
2177 ),
2178 overall_layout: (PanelLayout {
2179 panel_margin: PanelMargin::Vertical([0_f32, 0_f32, 0_f32, 0_f32], false),
2180 panel_location: PanelLocation::Absolute([0_f32, 0_f32]),
2181 }),
2182 custom_layout: Vec::new(),
2183 scroll_length: [0_f32, 0_f32],
2184 scroll_progress: [0_f32, 0_f32],
2185 last_frame_mouse_status: None,
2186 scrolled: [false, false],
2187 scroll_bar_alpha: [0, 0],
2188 tags: Vec::new(),
2189 }
2190 }
2191}
2192
2193impl ResourcePanel {
2194 #[inline]
2195 pub fn resizable(mut self, top: bool, bottom: bool, left: bool, right: bool) -> Self {
2196 self.resizable = [top, bottom, left, right];
2197 self
2198 }
2199
2200 #[inline]
2201 pub fn background(mut self, background: &BackgroundType) -> Self {
2202 self.background = background.clone();
2203 self
2204 }
2205
2206 #[inline]
2207 pub fn min_size(mut self, width: f32, height: f32) -> Self {
2208 self.min_size = [width, height];
2209 self
2210 }
2211
2212 #[inline]
2213 pub fn max_size(mut self, max_size: Option<[f32; 2]>) -> Self {
2214 self.max_size = max_size;
2215 self
2216 }
2217
2218 #[inline]
2219 pub fn movable(mut self, horizontal: bool, vertical: bool) -> Self {
2220 self.movable = [horizontal, vertical];
2221 self
2222 }
2223
2224 #[inline]
2225 pub fn scroll_length_method(
2226 mut self,
2227 horizontal: Option<ScrollLengthMethod>,
2228 vertical: Option<ScrollLengthMethod>,
2229 ) -> Self {
2230 self.scroll_length_method = [horizontal, vertical];
2231 self
2232 }
2233
2234 #[inline]
2235 pub fn scroll_sensitivity(mut self, scroll_sensitivity: f32) -> Self {
2236 self.scroll_sensitivity = scroll_sensitivity;
2237 self
2238 }
2239
2240 #[inline]
2241 pub fn use_smooth_scroll_delta(mut self, use_smooth_scroll_delta: bool) -> Self {
2242 self.use_smooth_scroll_delta = use_smooth_scroll_delta;
2243 self
2244 }
2245
2246 #[inline]
2247 pub fn scroll_bar_display_method(
2248 mut self,
2249 scroll_bar_display_method: ScrollBarDisplayMethod,
2250 ) -> Self {
2251 self.scroll_bar_display_method = scroll_bar_display_method;
2252 self
2253 }
2254
2255 #[inline]
2256 pub fn overall_layout(mut self, overall_layout: PanelLayout) -> Self {
2257 self.overall_layout = overall_layout;
2258 self
2259 }
2260
2261 #[inline]
2262 pub fn push_custom_layout(mut self, custom_layout: CustomPanelLayout) -> Self {
2263 self.custom_layout.push(custom_layout);
2264 self
2265 }
2266
2267 #[inline]
2268 pub fn custom_layout(mut self, custom_layout: &[CustomPanelLayout]) -> Self {
2269 self.custom_layout = custom_layout.to_owned();
2270 self
2271 }
2272
2273 #[inline]
2274 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
2275 if replace {
2276 self.tags = tags.to_owned();
2277 } else {
2278 for tag in tags {
2279 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2280 self.tags.remove(index);
2281 };
2282 }
2283 self.tags.extend(tags.iter().cloned());
2284 };
2285 self
2286 }
2287}
2288
2289#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
2291pub struct SwitchAppearanceConfig {
2292 pub background_config: BackgroundType,
2294 pub text_config: TextConfig,
2296 pub hint_text_config: TextConfig,
2298}
2299
2300#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2302pub struct SwitchClickConfig {
2303 pub click_method: PointerButton,
2305 pub action: bool,
2307}
2308
2309#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2311pub struct SwitchData {
2312 pub switched: bool,
2314 pub last_frame_clicked: Option<usize>,
2316 pub state: u32,
2318}
2319
2320#[derive(Debug, Clone, PartialEq)]
2322pub struct Switch {
2323 pub appearance: Vec<SwitchAppearanceConfig>,
2325 pub background_type: BackgroundType,
2327 pub text_config: TextConfig,
2329 pub hint_text_config: TextConfig,
2331 pub enable_animation: [bool; 2],
2333 pub state_amount: u32,
2335 pub click_method: Vec<SwitchClickConfig>,
2337 pub enable: bool,
2339 pub state: u32,
2341 pub last_frame_hovered: bool,
2343 pub last_frame_clicked: Option<usize>,
2345 pub switched: bool,
2347 pub tags: Vec<[String; 2]>,
2349}
2350
2351impl RustConstructorResource for Switch {
2352 fn as_any(&self) -> &dyn Any {
2353 self
2354 }
2355
2356 fn as_any_mut(&mut self) -> &mut dyn Any {
2357 self
2358 }
2359
2360 fn display_display_info(&self) -> Option<DisplayInfo> {
2361 None
2362 }
2363
2364 fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
2365
2366 fn display_tags(&self) -> Vec<[String; 2]> {
2367 self.tags.clone()
2368 }
2369
2370 fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
2371 if replace {
2372 self.tags = tags.to_owned();
2373 } else {
2374 for tag in tags {
2375 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2376 self.tags.remove(index);
2377 };
2378 }
2379 self.tags.extend(tags.iter().cloned());
2380 };
2381 }
2382}
2383
2384impl Default for Switch {
2385 fn default() -> Self {
2386 Self {
2387 appearance: vec![],
2388 background_type: BackgroundType::default(),
2389 text_config: TextConfig::default(),
2390 hint_text_config: TextConfig::default(),
2391 enable_animation: [false, false],
2392 state_amount: 0,
2393 click_method: vec![],
2394 enable: true,
2395 state: 0,
2396 last_frame_hovered: false,
2397 last_frame_clicked: None,
2398 switched: false,
2399 tags: Vec::new(),
2400 }
2401 }
2402}
2403
2404impl Switch {
2405 #[inline]
2406 pub fn appearance(mut self, appearance: &[SwitchAppearanceConfig]) -> Self {
2407 self.appearance = appearance.to_owned();
2408 self
2409 }
2410
2411 #[inline]
2412 pub fn background_type(mut self, background_type: &BackgroundType) -> Self {
2413 self.background_type = background_type.clone();
2414 self
2415 }
2416
2417 #[inline]
2418 pub fn text_config(mut self, text_config: &TextConfig) -> Self {
2419 self.text_config = text_config.clone();
2420 self
2421 }
2422
2423 #[inline]
2424 pub fn hint_text_config(mut self, hint_text_config: &TextConfig) -> Self {
2425 self.hint_text_config = hint_text_config.clone();
2426 self
2427 }
2428
2429 #[inline]
2430 pub fn enable_animation(mut self, enable_hover: bool, enable_click: bool) -> Self {
2431 self.enable_animation = [enable_hover, enable_click];
2432 self
2433 }
2434
2435 #[inline]
2436 pub fn state_amount(mut self, state_amount: u32) -> Self {
2437 self.state_amount = state_amount;
2438 self
2439 }
2440
2441 #[inline]
2442 pub fn click_method(mut self, click_method: Vec<SwitchClickConfig>) -> Self {
2443 self.click_method = click_method;
2444 self
2445 }
2446
2447 #[inline]
2448 pub fn enable(mut self, enable: bool) -> Self {
2449 self.enable = enable;
2450 self
2451 }
2452
2453 #[inline]
2454 pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
2455 if replace {
2456 self.tags = tags.to_owned();
2457 } else {
2458 for tag in tags {
2459 if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2460 self.tags.remove(index);
2461 };
2462 }
2463 self.tags.extend(tags.iter().cloned());
2464 };
2465 self
2466 }
2467}
2468
2469#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2471pub struct RustConstructorError {
2472 pub error_id: String,
2474 pub description: String,
2476}
2477
2478impl Display for RustConstructorError {
2479 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
2480 Debug::fmt(self, f)
2481 }
2482}
2483
2484impl Error for RustConstructorError {}
2485
2486#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2488pub enum HorizontalAlign {
2489 #[default]
2491 Left,
2492 Center,
2494 Right,
2496}
2497
2498#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2500pub enum VerticalAlign {
2501 #[default]
2503 Top,
2504 Center,
2506 Bottom,
2508}
2509
2510#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2512pub enum RenderConfig {
2513 Line(f32, [u8; 4]),
2514 Rect([u8; 4], [u8; 4], [u8; 4], f32, BorderKind),
2515}
2516
2517#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2519pub struct DisplayInfo {
2520 pub enable: bool,
2522 pub hidden: bool,
2524 pub ignore_render_layer: bool,
2526}
2527
2528#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2530pub enum RequestMethod {
2531 Id(RustConstructorId),
2533 Citer(RustConstructorId),
2535}
2536
2537#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2539pub enum RequestType {
2540 Top,
2542 Up(u32),
2544}
2545
2546#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2548pub enum ActiveListInfoMethod {
2549 Detailed(bool),
2551 #[default]
2553 Simple,
2554}
2555
2556#[derive(Debug)]
2558pub struct App {
2559 pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
2561 pub tick_interval: f32,
2563 pub current_page: String,
2565 pub timer: Timer,
2567 pub frame_times: Vec<f32>,
2569 pub last_frame_time: Option<f32>,
2571 pub basic_front_resource_list: Vec<String>,
2573 pub render_layer: Vec<(RustConstructorId, [[f32; 2]; 2], bool)>,
2575 pub active_list: Vec<RustConstructorId>,
2577 pub render_list: Vec<RustConstructorId>,
2579}
2580
2581impl Default for App {
2582 fn default() -> Self {
2583 App {
2584 rust_constructor_resource: Vec::new(),
2585 tick_interval: 0.05,
2586 current_page: String::new(),
2587 timer: Timer::default(),
2588 frame_times: Vec::new(),
2589 last_frame_time: None,
2590 basic_front_resource_list: vec![
2591 String::from("rust_constructor::Image"),
2592 String::from("rust_constructor::Text"),
2593 String::from("rust_constructor::CustomRect"),
2594 ],
2595 render_layer: Vec::new(),
2596 active_list: Vec::new(),
2597 render_list: Vec::new(),
2598 }
2599 }
2600}
2601
2602impl App {
2603 #[inline]
2604 pub fn tick_interval(mut self, tick_interval: f32) -> Self {
2605 self.tick_interval = tick_interval;
2606 self
2607 }
2608
2609 #[inline]
2610 pub fn current_page(mut self, current_page: &str) -> Self {
2611 self.current_page = current_page.to_string();
2612 self
2613 }
2614
2615 pub fn get_tag(&self, tag_name: &str, target: &[[String; 2]]) -> Option<(usize, String)> {
2617 target
2618 .iter()
2619 .position(|x| x[0] == tag_name)
2620 .map(|index| (index, target[index][1].clone()))
2621 }
2622
2623 pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
2625 for i in 0..self.render_list.len() {
2626 #[allow(warnings)]
2627 self.draw_resource_by_index(ui, ctx, i);
2628 }
2629 }
2630
2631 pub fn draw_resource_by_index(
2633 &mut self,
2634 ui: &mut Ui,
2635 ctx: &Context,
2636 index: usize,
2637 ) -> Result<(), RustConstructorError> {
2638 if let Some(render_resource) = self.render_list.clone().get(index) {
2639 match &*render_resource.discern_type {
2640 "rust_constructor::Image" => {
2641 let image = self
2642 .get_resource::<Image>(&render_resource.name, "rust_constructor::Image")?;
2643 if image.display_info.enable {
2644 let mut image = image.clone();
2645 if image.cite_texture != image.last_frame_cite_texture {
2646 let image_texture = self.get_resource::<ImageTexture>(
2647 &image.cite_texture,
2648 "rust_constructor::ImageTexture",
2649 )?;
2650 image.texture = image_texture.texture.clone();
2651 };
2652 [image.position, image.size] = self.position_size_processor(
2653 image.basic_front_resource_config.position_size_config,
2654 ctx,
2655 );
2656 if !image.display_info.hidden {
2657 if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
2658 let [min, size] = self.position_size_processor(clip_rect, ctx);
2659 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2660 };
2661 if let Some(texture) = &image.texture {
2662 let rect = Rect::from_min_size(
2663 Pos2::new(image.position[0], image.position[1]),
2664 Vec2::new(image.size[0], image.size[1]),
2665 );
2666
2667 egui::Image::new(ImageSource::Texture((&texture.0).into()))
2669 .tint(Color32::from_rgba_unmultiplied(
2670 image.overlay_color[0],
2671 image.overlay_color[1],
2672 image.overlay_color[2],
2673 (image.alpha as f32 * image.overlay_alpha as f32 / 255_f32)
2675 as u8,
2676 ))
2677 .bg_fill(Color32::from_rgba_unmultiplied(
2678 image.background_color[0],
2679 image.background_color[1],
2680 image.background_color[2],
2681 (image.alpha as f32 * image.background_alpha as f32
2682 / 255_f32)
2683 as u8,
2684 ))
2685 .rotate(
2686 image.rotate_angle,
2687 [
2688 image.rotate_center[0] / image.size[0],
2689 image.rotate_center[1] / image.size[1],
2690 ]
2691 .into(),
2692 )
2693 .paint_at(ui, rect)
2694 };
2695 if image.basic_front_resource_config.clip_rect.is_some() {
2696 ui.set_clip_rect(Rect::from_min_size(
2697 [0_f32, 0_f32].into(),
2698 [ctx.available_rect().width(), ctx.available_rect().height()]
2699 .into(),
2700 ));
2701 };
2702 };
2703 image.last_frame_cite_texture = image.cite_texture.clone();
2704 self.replace_resource(&render_resource.name, image)?;
2705 };
2706 }
2707 "rust_constructor::Text" => {
2708 let text =
2709 self.get_resource::<Text>(&render_resource.name, "rust_constructor::Text")?;
2710 if text.display_info.enable {
2711 let mut text = text.clone();
2712 [text.position, text.truncate_size] = self.position_size_processor(
2713 text.basic_front_resource_config.position_size_config,
2714 ctx,
2715 );
2716 let display_content = {
2717 let original_galley = ui.fonts_mut(|f| {
2718 f.layout(
2719 text.content.to_string(),
2720 FontId::proportional(text.font_size),
2721 Color32::default(),
2722 text.truncate_size[0],
2723 )
2724 });
2725
2726 let mut truncated = text.content.to_string();
2727 let mut ellipsis = "";
2728 if original_galley.size().y > text.truncate_size[1] {
2729 ellipsis = "...";
2731
2732 while !truncated.is_empty() {
2733 let test_text = format!("{}{}", truncated, ellipsis);
2734 let test_galley = ui.fonts_mut(|f| {
2735 f.layout(
2736 test_text,
2737 FontId::proportional(text.font_size),
2738 Color32::default(),
2739 text.truncate_size[0],
2740 )
2741 });
2742
2743 if test_galley.size().y <= text.truncate_size[1] {
2744 break;
2745 }
2746
2747 truncated.pop();
2749 }
2750 };
2751 format!("{}{}", truncated, ellipsis)
2752 };
2753 let galley: Arc<Galley> = ui.fonts_mut(|f| {
2755 f.layout(
2756 display_content.to_string(),
2757 if !text.font.is_empty() {
2758 if self
2759 .check_resource_exists(&text.font, "rust_constructor::Font")
2760 .is_none()
2761 {
2762 FontId::proportional(text.font_size)
2763 } else {
2764 FontId::new(
2765 text.font_size,
2766 FontFamily::Name(text.font.clone().into()),
2767 )
2768 }
2769 } else {
2770 FontId::proportional(text.font_size)
2771 },
2772 Color32::from_rgba_unmultiplied(
2773 text.color[0],
2774 text.color[1],
2775 text.color[2],
2776 text.alpha,
2777 ),
2778 text.truncate_size[0],
2779 )
2780 });
2781 text.size = [
2782 if text.auto_fit[0] {
2783 galley.size().x
2784 } else {
2785 text.truncate_size[0]
2786 },
2787 if text.auto_fit[1] {
2788 galley.size().y
2789 } else {
2790 text.truncate_size[1]
2791 },
2792 ];
2793 text.actual_size = [galley.size().x, galley.size().y];
2794 if text.last_frame_content != display_content {
2796 text.hyperlink_index.clear();
2797
2798 let byte_to_char_map: std::collections::HashMap<usize, usize> =
2800 display_content
2801 .char_indices()
2802 .enumerate()
2803 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2804 .collect();
2805
2806 for (hyperlink_text, method) in &text.hyperlink_text {
2807 let matches: Vec<(usize, &str)> =
2808 display_content.match_indices(hyperlink_text).collect();
2809 let text_char_count = hyperlink_text.chars().count();
2810
2811 if let HyperlinkSelectMethod::All(url) = method {
2812 for (byte_index, _) in matches {
2813 if let Some(&start_char_index) =
2814 byte_to_char_map.get(&byte_index)
2815 {
2816 text.hyperlink_index.push((
2817 start_char_index,
2818 start_char_index + text_char_count,
2819 url.clone(),
2820 ));
2821 };
2822 }
2823 } else if let HyperlinkSelectMethod::Segment(list) = method {
2824 for (index, url) in list {
2825 if *index >= matches.len() {
2826 continue;
2827 };
2828 let (byte_index, _) = matches[*index];
2829 if let Some(&start_char_index) =
2830 byte_to_char_map.get(&byte_index)
2831 {
2832 text.hyperlink_index.push((
2833 start_char_index,
2834 start_char_index + text_char_count,
2835 url.clone(),
2836 ));
2837 };
2838 }
2839 };
2840 }
2841 };
2842 if !text.display_info.hidden {
2843 let rect =
2845 Rect::from_min_size(text.position.into(), text.actual_size.into());
2846 ui.painter().rect_filled(
2848 rect,
2849 text.background_rounding,
2850 Color32::from_rgba_unmultiplied(
2851 text.background_color[0],
2852 text.background_color[1],
2853 text.background_color[2],
2854 text.background_alpha,
2855 ),
2856 );
2857
2858 if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2859 let [min, size] = self.position_size_processor(clip_rect, ctx);
2860 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2861 };
2862
2863 ui.painter().galley(
2865 text.position.into(),
2866 galley.clone(),
2867 Color32::from_rgba_unmultiplied(
2868 text.color[0],
2869 text.color[1],
2870 text.color[2],
2871 text.alpha,
2872 ),
2873 );
2874
2875 for (start, end, _) in &text.hyperlink_index {
2877 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2879 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2880
2881 let start_pos = start_cursor.left_top();
2882 let end_pos = end_cursor.right_top();
2883 if start_cursor.min.y == end_cursor.min.y {
2886 let underline_y = text.position[1]
2888 + start_pos.y
2889 + galley.rows.first().map_or(14.0, |row| row.height())
2890 - 2.0;
2891
2892 let color = Color32::from_rgba_unmultiplied(
2894 text.color[0],
2895 text.color[1],
2896 text.color[2],
2897 text.alpha,
2898 );
2899
2900 ui.painter().line_segment(
2901 [
2902 Pos2::new(text.position[0] + start_pos.x, underline_y),
2903 Pos2::new(text.position[0] + end_pos.x, underline_y),
2904 ],
2905 Stroke::new(text.font_size / 10_f32, color),
2906 );
2907 } else {
2908 let row_height =
2910 galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2914 let end_row = (end_pos.y / row_height).round() as usize;
2915
2916 for row in start_row..=end_row {
2917 let row_y =
2918 text.position[1] + row as f32 * row_height + row_height
2919 - 2.0; if let Some(current_row) = galley.rows.get(row) {
2923 let row_rect = current_row.rect();
2924
2925 let color = Color32::from_rgba_unmultiplied(
2926 text.color[0],
2927 text.color[1],
2928 text.color[2],
2929 text.alpha,
2930 );
2931
2932 if row == start_row {
2933 ui.painter().line_segment(
2935 [
2936 Pos2::new(
2937 text.position[0] + start_pos.x,
2938 row_y,
2939 ),
2940 Pos2::new(
2941 text.position[0] + row_rect.max.x,
2942 row_y,
2943 ),
2944 ],
2945 Stroke::new(text.font_size / 10_f32, color),
2946 );
2947 } else if row == end_row {
2948 ui.painter().line_segment(
2950 [
2951 Pos2::new(
2952 text.position[0] + row_rect.min.x,
2953 row_y,
2954 ),
2955 Pos2::new(
2956 text.position[0] + end_pos.x,
2957 row_y,
2958 ),
2959 ],
2960 Stroke::new(text.font_size / 10_f32, color),
2961 );
2962 } else {
2963 ui.painter().line_segment(
2965 [
2966 Pos2::new(
2967 text.position[0] + row_rect.min.x,
2968 row_y,
2969 ),
2970 Pos2::new(
2971 text.position[0] + row_rect.max.x,
2972 row_y,
2973 ),
2974 ],
2975 Stroke::new(text.font_size / 10_f32, color),
2976 );
2977 };
2978 };
2979 }
2980 };
2981 }
2982
2983 if text.selectable {
2984 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2986 let relative_pos = pointer_pos - text.position.into();
2987 let cursor = galley.cursor_from_pos(relative_pos);
2988 cursor.index
2989 };
2990
2991 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
2992 let rect = Rect::from_min_size(
2993 text.position.into(),
2994 text.actual_size.into(),
2995 );
2996 let detect_result = ui.interact(
2997 rect,
2998 Id::new(&render_resource.name),
2999 Sense::click_and_drag(),
3000 );
3001
3002 if !detect_result.clicked()
3003 && (fullscreen_detect_result.any_click()
3004 || fullscreen_detect_result.any_pressed())
3005 {
3006 text.selection = None;
3007 };
3008
3009 if let Some(index) = self.get_render_layer_resource(
3010 &render_resource.name,
3011 "rust_constructor::Text",
3012 ) && let Some(mouse_pos) =
3013 fullscreen_detect_result.interact_pos()
3014 && self.resource_get_focus(index, mouse_pos.into())
3015 && (detect_result.clicked() || detect_result.drag_started())
3016 {
3017 let cursor = cursor_at_pointer(mouse_pos.to_vec2());
3018 text.selection = Some((cursor, cursor));
3019 };
3020
3021 if detect_result.dragged()
3022 && text.selection.is_some()
3023 && let Some(pointer_pos) =
3024 ui.input(|i| i.pointer.interact_pos())
3025 {
3026 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3027 if let Some((start, _)) = text.selection {
3028 text.selection = Some((start, cursor));
3029 };
3030 };
3031
3032 if text.selection.is_some()
3033 && ui.input(|input| {
3034 input.key_released(Key::A) && input.modifiers.command
3035 })
3036 {
3037 text.selection = Some((0, display_content.chars().count()));
3038 };
3039
3040 let copy_triggered = ui.input(|input| {
3042 let c_released = input.key_released(Key::C);
3043 let cmd_pressed = input.modifiers.command;
3044 c_released && cmd_pressed
3045 });
3046 if copy_triggered && let Some((start, end)) = text.selection {
3047 let (start, end) = (start.min(end), start.max(end));
3048 let chars: Vec<char> = display_content.chars().collect();
3049 if start <= chars.len() && end <= chars.len() && start < end {
3050 let selected_text: String =
3051 chars[start..end].iter().collect();
3052 ui.ctx().copy_text(selected_text);
3053 };
3054 };
3055
3056 if let Some((start, end)) = text.selection {
3058 let (start, end) = (start.min(end), start.max(end));
3059 if start != end {
3060 let start_cursor =
3062 galley.pos_from_cursor(CCursor::new(start));
3063 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3064
3065 let start_pos = start_cursor.left_top();
3066 let end_pos = end_cursor.right_top();
3067 if start_pos.y == end_pos.y {
3069 let rows = &galley.rows;
3071 let row_height = if !rows.is_empty() {
3072 if let Some(row) = rows.first() {
3074 row.height()
3075 } else {
3076 text.actual_size[1]
3077 / display_content.lines().count() as f32
3078 }
3079 } else {
3080 text.actual_size[1]
3081 / display_content.lines().count() as f32
3082 };
3083
3084 let selection_rect = Rect::from_min_max(
3085 Pos2::new(
3086 text.position[0] + start_pos.x,
3087 text.position[1] + start_pos.y,
3088 ),
3089 Pos2::new(
3090 text.position[0] + end_pos.x,
3091 text.position[1] + start_pos.y + row_height,
3092 ),
3093 );
3094 ui.painter().rect_filled(
3095 selection_rect,
3096 0.0,
3097 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3098 );
3099 } else {
3100 let rows = &galley.rows;
3102 let row_height = if !rows.is_empty() {
3103 rows[0].height()
3104 } else {
3105 text.actual_size[1]
3106 / display_content.lines().count() as f32
3107 };
3108
3109 let selection_top =
3111 text.position[1] + start_pos.y.min(end_pos.y);
3112 let selection_bottom =
3113 text.position[1] + start_pos.y.max(end_pos.y);
3114
3115 let start_row_index =
3117 (start_pos.y / row_height).floor() as usize;
3118 let end_row_index =
3119 (end_pos.y / row_height).floor() as usize;
3120 let (first_row_index, last_row_index) =
3121 if start_row_index <= end_row_index {
3122 (start_row_index, end_row_index)
3123 } else {
3124 (end_row_index, start_row_index)
3125 };
3126
3127 for (i, row) in rows.iter().enumerate() {
3128 let row_y =
3129 text.position[1] + row_height * i as f32;
3130 let row_bottom = row_y + row_height;
3131 if row_bottom > selection_top
3133 && row_y <= selection_bottom
3134 {
3135 let left = if i == first_row_index {
3136 text.position[0] + start_pos.x
3138 } else {
3139 text.position[0] + row.rect().min.x
3141 };
3142
3143 let right = if i == last_row_index {
3144 text.position[0] + end_pos.x
3146 } else {
3147 text.position[0] + row.rect().max.x
3149 };
3150
3151 let selection_rect = Rect::from_min_max(
3152 Pos2::new(left, row_y),
3153 Pos2::new(right, row_bottom),
3154 );
3155
3156 if selection_rect.width() > 0.0
3158 && selection_rect.height() > 0.0
3159 {
3160 ui.painter().rect_filled(
3161 selection_rect,
3162 0.0,
3163 Color32::from_rgba_unmultiplied(
3164 0, 120, 255, 100,
3165 ),
3166 );
3167 };
3168 };
3169 }
3170 };
3171 };
3172 };
3173 };
3174
3175 for (start, end, url) in &text.hyperlink_index {
3177 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3179 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3180
3181 let start_pos = start_cursor.left_top();
3182 let end_pos = end_cursor.right_top();
3183
3184 let row_height =
3185 galley.rows.first().map_or(14.0, |row| row.height());
3186
3187 let link_responses = if start_cursor.min.y == end_cursor.min.y {
3189 let link_rect = Rect::from_min_max(
3191 Pos2::new(
3192 text.position[0] + start_pos.x,
3193 text.position[1] + start_pos.y,
3194 ),
3195 Pos2::new(
3196 text.position[0] + end_pos.x,
3197 text.position[1] + start_pos.y + row_height,
3198 ),
3199 );
3200 vec![ui.interact(
3201 link_rect,
3202 egui::Id::new(format!(
3203 "link_{}_{}_{}",
3204 render_resource.name, start, end
3205 )),
3206 egui::Sense::click(),
3207 )]
3208 } else {
3209 let start_row = (start_pos.y / row_height).round() as usize;
3211 let end_row = (end_pos.y / row_height).round() as usize;
3212 let mut responses = Vec::new();
3213
3214 for row in start_row..=end_row {
3215 if let Some(current_row) = galley.rows.get(row) {
3216 let row_rect = current_row.rect();
3217 let row_y = text.position[1] + row as f32 * row_height;
3218
3219 let link_rect = if row == start_row {
3220 Rect::from_min_max(
3222 Pos2::new(
3223 text.position[0] + start_pos.x,
3224 row_y,
3225 ),
3226 Pos2::new(
3227 text.position[0] + row_rect.max.x,
3228 row_y + row_height,
3229 ),
3230 )
3231 } else if row == end_row {
3232 Rect::from_min_max(
3234 Pos2::new(
3235 text.position[0] + row_rect.min.x,
3236 row_y,
3237 ),
3238 Pos2::new(
3239 text.position[0] + end_pos.x,
3240 row_y + row_height,
3241 ),
3242 )
3243 } else {
3244 Rect::from_min_max(
3246 Pos2::new(
3247 text.position[0] + row_rect.min.x,
3248 row_y,
3249 ),
3250 Pos2::new(
3251 text.position[0] + row_rect.max.x,
3252 row_y + row_height,
3253 ),
3254 )
3255 };
3256
3257 responses.push(ui.interact(
3258 link_rect,
3259 Id::new(format!(
3260 "link_{}_{}_{}_row_{}",
3261 render_resource.name, start, end, row
3262 )),
3263 Sense::click(),
3264 ));
3265 };
3266 }
3267 responses
3268 };
3269
3270 let mut is_pressing_link = false;
3272 for link_response in &link_responses {
3273 if let Some(index) = self.get_render_layer_resource(
3274 &render_resource.name,
3275 "rust_constructor::Text",
3276 ) && let Some(mouse_pos) =
3277 ui.input(|i| i.pointer.interact_pos())
3278 && self.resource_get_focus(index, mouse_pos.into())
3279 {
3280 if link_response.is_pointer_button_down_on()
3281 && !link_response.drag_started()
3282 {
3283 text.selection = None;
3284 if let Some(pointer_pos) =
3285 ui.input(|i| i.pointer.interact_pos())
3286 {
3287 let relative_pos = pointer_pos
3288 - <[f32; 2] as Into<Pos2>>::into(text.position);
3289 let cursor = galley.cursor_from_pos(relative_pos);
3290 if cursor.index >= *start && cursor.index <= *end {
3291 is_pressing_link = true;
3292 break;
3293 };
3294 };
3295 };
3296 let mut clicked_on_link = false;
3298 for link_response in &link_responses {
3299 if link_response.clicked()
3300 && let Some(pointer_pos) =
3301 ui.input(|i| i.pointer.interact_pos())
3302 {
3303 let relative_pos = pointer_pos
3304 - <[f32; 2] as Into<Pos2>>::into(text.position);
3305 let cursor = galley.cursor_from_pos(relative_pos);
3306 if cursor.index >= *start && cursor.index <= *end {
3307 clicked_on_link = true;
3308 break;
3309 };
3310 };
3311 }
3312
3313 if clicked_on_link {
3314 if !url.is_empty() {
3316 ui.ctx().open_url(OpenUrl::new_tab(url));
3317 };
3318 };
3319 };
3320 }
3321
3322 if is_pressing_link {
3324 if start_cursor.min.y == end_cursor.min.y {
3325 let selection_rect = Rect::from_min_max(
3327 Pos2::new(
3328 text.position[0] + start_pos.x,
3329 text.position[1] + start_pos.y,
3330 ),
3331 Pos2::new(
3332 text.position[0] + end_pos.x,
3333 text.position[1]
3334 + start_pos.y
3335 + galley
3336 .rows
3337 .first()
3338 .map_or(14.0, |row| row.height()),
3339 ),
3340 );
3341 ui.painter().rect_filled(
3342 selection_rect,
3343 0.0,
3344 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3345 );
3346 } else {
3347 let row_height =
3349 galley.rows.first().map_or(14.0, |row| row.height());
3350 let start_row = (start_pos.y / row_height).round() as usize;
3351 let end_row = (end_pos.y / row_height).round() as usize;
3352
3353 for row in start_row..=end_row {
3354 if let Some(current_row) = galley.rows.get(row) {
3355 let row_rect = current_row.rect();
3356
3357 if row == start_row {
3358 let selection_rect = Rect::from_min_max(
3360 Pos2::new(
3361 text.position[0] + start_pos.x,
3362 text.position[1]
3363 + row as f32 * row_height,
3364 ),
3365 Pos2::new(
3366 text.position[0] + row_rect.max.x,
3367 text.position[1]
3368 + row as f32 * row_height
3369 + row_height,
3370 ),
3371 );
3372 ui.painter().rect_filled(
3373 selection_rect,
3374 0.0,
3375 Color32::from_rgba_unmultiplied(
3376 0, 120, 255, 100,
3377 ),
3378 );
3379 } else if row == end_row {
3380 let selection_rect = Rect::from_min_max(
3382 Pos2::new(
3383 text.position[0] + row_rect.min.x,
3384 text.position[1]
3385 + row as f32 * row_height,
3386 ),
3387 Pos2::new(
3388 text.position[0] + end_pos.x,
3389 text.position[1]
3390 + row as f32 * row_height
3391 + row_height,
3392 ),
3393 );
3394 ui.painter().rect_filled(
3395 selection_rect,
3396 0.0,
3397 Color32::from_rgba_unmultiplied(
3398 0, 120, 255, 100,
3399 ),
3400 );
3401 } else {
3402 let selection_rect = Rect::from_min_max(
3404 Pos2::new(
3405 text.position[0] + row_rect.min.x,
3406 text.position[1]
3407 + row as f32 * row_height,
3408 ),
3409 Pos2::new(
3410 text.position[0] + row_rect.max.x,
3411 text.position[1]
3412 + row as f32 * row_height
3413 + row_height,
3414 ),
3415 );
3416 ui.painter().rect_filled(
3417 selection_rect,
3418 0.0,
3419 Color32::from_rgba_unmultiplied(
3420 0, 120, 255, 100,
3421 ),
3422 );
3423 };
3424 };
3425 }
3426 };
3427 };
3428 }
3429 if text.basic_front_resource_config.clip_rect.is_some() {
3430 ui.set_clip_rect(Rect::from_min_size(
3431 [0_f32, 0_f32].into(),
3432 [ctx.available_rect().width(), ctx.available_rect().height()]
3433 .into(),
3434 ));
3435 };
3436 } else {
3437 text.selection = None;
3438 };
3439 text.last_frame_content = display_content;
3440 self.replace_resource(&render_resource.name, text)?;
3441 };
3442 }
3443 "rust_constructor::CustomRect" => {
3444 let custom_rect = self.get_resource::<CustomRect>(
3445 &render_resource.name,
3446 "rust_constructor::CustomRect",
3447 )?;
3448 if custom_rect.display_info.enable {
3449 let mut custom_rect = custom_rect.clone();
3450 [custom_rect.position, custom_rect.size] = self.position_size_processor(
3451 custom_rect.basic_front_resource_config.position_size_config,
3452 ctx,
3453 );
3454 if !custom_rect.display_info.hidden {
3455 if let Some(clip_rect) =
3456 custom_rect.basic_front_resource_config.clip_rect
3457 {
3458 let [min, size] = self.position_size_processor(clip_rect, ctx);
3459 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
3460 };
3461 ui.painter().rect(
3462 Rect::from_min_max(
3463 Pos2::new(custom_rect.position[0], custom_rect.position[1]),
3464 Pos2::new(
3465 custom_rect.position[0] + custom_rect.size[0],
3466 custom_rect.position[1] + custom_rect.size[1],
3467 ),
3468 ),
3469 custom_rect.rounding,
3470 Color32::from_rgba_unmultiplied(
3471 custom_rect.color[0],
3472 custom_rect.color[1],
3473 custom_rect.color[2],
3474 custom_rect.alpha,
3475 ),
3476 Stroke {
3477 width: custom_rect.border_width,
3478 color: Color32::from_rgba_unmultiplied(
3479 custom_rect.border_color[0],
3480 custom_rect.border_color[1],
3481 custom_rect.border_color[2],
3482 custom_rect.alpha,
3483 ),
3484 },
3485 match custom_rect.border_kind {
3486 BorderKind::Inside => StrokeKind::Inside,
3487 BorderKind::Middle => StrokeKind::Middle,
3488 BorderKind::Outside => StrokeKind::Outside,
3489 },
3490 );
3491 if custom_rect.basic_front_resource_config.clip_rect.is_some() {
3492 ui.set_clip_rect(Rect::from_min_size(
3493 [0_f32, 0_f32].into(),
3494 [ctx.available_rect().width(), ctx.available_rect().height()]
3495 .into(),
3496 ));
3497 };
3498 };
3499 self.replace_resource(&render_resource.name, custom_rect)?;
3500 };
3501 }
3502 _ => {
3503 unreachable!()
3504 }
3505 }
3506 Ok(())
3507 } else {
3508 Err(RustConstructorError {
3509 error_id: "IndexOutOfRange".to_string(),
3510 description: format!(
3511 "The maximum index of the target list is {}, but the index is {index}.",
3512 self.render_list.len() - 1
3513 ),
3514 })
3515 }
3516 }
3517
3518 pub fn active_list_info(&self, method: ActiveListInfoMethod) -> String {
3520 let mut text = String::from("Resource Active Info:\n");
3521 for info in &self.active_list {
3522 if let ActiveListInfoMethod::Detailed(format) = method {
3523 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3524 text += &if format {
3525 format!(
3526 "\nName: {}\nType: {}\nDetail: {:#?}\n",
3527 info.name, info.discern_type, self.rust_constructor_resource[index],
3528 )
3529 } else {
3530 format!(
3531 "\nName: {}\nType: {}\nDetail: {:?}\n",
3532 info.name, info.discern_type, self.rust_constructor_resource[index],
3533 )
3534 };
3535 };
3536 } else {
3537 text += &format!("\nName: {}\nType: {}\n", info.name, info.discern_type);
3538 };
3539 }
3540 text
3541 }
3542
3543 pub fn render_layer_info(&self) -> String {
3545 let mut text = String::from("Render Layer Info:\n");
3546 for (
3547 RustConstructorId { name, discern_type },
3548 [min_position, max_position],
3549 ignore_render_layer,
3550 ) in &self.render_layer
3551 {
3552 text += &format!(
3553 "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
3554 name, discern_type, min_position, max_position, ignore_render_layer
3555 );
3556 }
3557 text
3558 }
3559
3560 pub fn render_list_info(&self) -> String {
3562 let mut text = String::from("Render List Info:\n");
3563 for RustConstructorId { name, discern_type } in &self.render_list {
3564 text += &format!("\nName: {:?}\nType: {:?}\n", name, discern_type);
3565 }
3566 text
3567 }
3568
3569 pub fn update_render_list(&mut self) {
3571 if self.render_list.is_empty() {
3572 for info in &self.active_list {
3573 if self.basic_front_resource_list.contains(&info.discern_type) {
3574 self.render_list.push(RustConstructorId {
3575 name: info.name.clone(),
3576 discern_type: info.discern_type.clone(),
3577 });
3578 };
3579 }
3580 } else {
3581 let mut count = 0;
3582 for render_resource in &self.render_list.clone() {
3583 if !self.active_list.contains(render_resource) {
3584 self.render_list.remove(count);
3585 } else {
3586 count += 1;
3587 };
3588 }
3589 let mut insert_index = 0;
3590 for info in &self.active_list {
3591 if self.basic_front_resource_list.contains(&info.discern_type) {
3592 if !self.render_list.contains(info) {
3593 self.render_list.insert(
3594 insert_index,
3595 RustConstructorId {
3596 name: info.name.clone(),
3597 discern_type: info.discern_type.clone(),
3598 },
3599 );
3600 insert_index += 1;
3601 } else if self.render_list[insert_index].cmp(info) == Ordering::Equal {
3602 insert_index += 1;
3603 };
3604 };
3605 }
3606 };
3607 }
3608
3609 pub fn unsafe_request_jump_render_list(
3611 &mut self,
3612 requester: RequestMethod,
3613 request_type: RequestType,
3614 ) {
3615 #[allow(warnings)]
3616 self.request_jump_render_list(requester, request_type);
3617 }
3618
3619 pub fn request_jump_render_list(
3621 &mut self,
3622 requester: RequestMethod,
3623 request_type: RequestType,
3624 ) -> Result<(), RustConstructorError> {
3625 match requester {
3626 RequestMethod::Id(RustConstructorId { name, discern_type }) => {
3627 if let Some(index) = self
3628 .render_list
3629 .iter()
3630 .position(|x| x.name == name && x.discern_type == discern_type)
3631 {
3632 self.jump_render_list_processor(index, request_type)?;
3633 Ok(())
3634 } else {
3635 Err(RustConstructorError {
3636 error_id: "RenderResourceNotFound".to_string(),
3637 description: format!(
3638 "Render resource \"{name}({discern_type})\" not found.",
3639 ),
3640 })
3641 }
3642 }
3643 RequestMethod::Citer(RustConstructorId { name, discern_type }) => {
3644 for (i, render_resource) in self.render_list.iter().enumerate() {
3645 let [resource_name, resource_type] = [
3646 render_resource.name.clone(),
3647 render_resource.discern_type.clone(),
3648 ];
3649 let tags = self
3650 .get_box_resource(&resource_name, &resource_type)?
3651 .display_tags();
3652 if let [Some(tag_name), Some(tag_type)] = [
3653 self.get_tag("citer_name", &tags),
3654 self.get_tag("citer_type", &tags),
3655 ] && tag_name.1 == name
3656 && tag_type.1 == discern_type
3657 {
3658 self.jump_render_list_processor(i, request_type)?;
3659 return Ok(());
3660 };
3661 }
3662 Err(RustConstructorError {
3663 error_id: "RenderResourceNotFound".to_string(),
3664 description: format!("Render resource \"{name}({discern_type})\" not found.",),
3665 })
3666 }
3667 }
3668 }
3669
3670 pub fn jump_render_list_processor(
3672 &mut self,
3673 requester_index: usize,
3674 request_type: RequestType,
3675 ) -> Result<(), RustConstructorError> {
3676 if requester_index < self.render_list.len() {
3677 let requester = self.render_list.remove(requester_index);
3678 let new_index = match request_type {
3679 RequestType::Top => self.render_list.len(),
3680 RequestType::Up(up) => {
3681 if requester_index + up as usize <= self.render_list.len() {
3682 requester_index + up as usize
3683 } else {
3684 self.render_list.len()
3685 }
3686 }
3687 };
3688 self.render_list.insert(new_index, requester);
3689 Ok(())
3690 } else {
3691 Err(RustConstructorError {
3692 error_id: "IndexOutOfRange".to_string(),
3693 description: format!(
3694 "The maximum index of the target list is {}, but the index is {requester_index}.",
3695 self.render_list.len() - 1
3696 ),
3697 })
3698 }
3699 }
3700
3701 pub fn update_render_layer(&mut self) {
3703 self.render_layer.clear();
3704 for info in &self.render_list {
3705 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3706 let basic_front_resource: Box<dyn BasicFrontResource> = match &*info.discern_type {
3707 "rust_constructor::Image" => Box::new(
3708 self.rust_constructor_resource[index]
3709 .content
3710 .as_any()
3711 .downcast_ref::<Image>()
3712 .unwrap()
3713 .clone(),
3714 ),
3715 "rust_constructor::Text" => Box::new(
3716 self.rust_constructor_resource[index]
3717 .content
3718 .as_any()
3719 .downcast_ref::<Text>()
3720 .unwrap()
3721 .clone(),
3722 ),
3723 "rust_constructor::CustomRect" => Box::new(
3724 self.rust_constructor_resource[index]
3725 .content
3726 .as_any()
3727 .downcast_ref::<CustomRect>()
3728 .unwrap()
3729 .clone(),
3730 ),
3731 _ => {
3732 unreachable!()
3733 }
3734 };
3735 if let Some(display_info) = basic_front_resource.display_display_info() {
3736 self.render_layer.push((
3737 info.clone(),
3738 [
3739 basic_front_resource.display_position(),
3740 [
3741 basic_front_resource.display_position()[0]
3742 + basic_front_resource.display_size()[0],
3743 basic_front_resource.display_position()[1]
3744 + basic_front_resource.display_size()[1],
3745 ],
3746 ],
3747 display_info.ignore_render_layer,
3748 ));
3749 };
3750 };
3751 }
3752 }
3753
3754 pub fn display_render_layer(
3756 &self,
3757 ui: &mut Ui,
3758 render_config: &RenderConfig,
3759 ignore_render_config: &RenderConfig,
3760 ) {
3761 for (_, point, ignore_render_layer) in &self.render_layer {
3762 match if *ignore_render_layer {
3763 ignore_render_config
3764 } else {
3765 render_config
3766 } {
3767 RenderConfig::Rect(
3768 corner_radius,
3769 fill_color,
3770 border_color,
3771 border_width,
3772 border_kind,
3773 ) => {
3774 let rect = Rect::from_min_max(point[0].into(), point[1].into());
3775 ui.painter().rect(
3776 rect,
3777 CornerRadius {
3778 nw: corner_radius[0],
3779 ne: corner_radius[1],
3780 sw: corner_radius[2],
3781 se: corner_radius[3],
3782 },
3783 Color32::from_rgba_unmultiplied(
3784 fill_color[0],
3785 fill_color[1],
3786 fill_color[2],
3787 fill_color[3],
3788 ),
3789 Stroke::new(
3790 *border_width,
3791 Color32::from_rgba_unmultiplied(
3792 border_color[0],
3793 border_color[1],
3794 border_color[2],
3795 border_color[3],
3796 ),
3797 ),
3798 match *border_kind {
3799 BorderKind::Inside => StrokeKind::Inside,
3800 BorderKind::Middle => StrokeKind::Middle,
3801 BorderKind::Outside => StrokeKind::Outside,
3802 },
3803 );
3804 }
3805 RenderConfig::Line(width, color) => {
3806 ui.painter().line_segment(
3807 [point[0].into(), point[1].into()],
3808 Stroke::new(
3809 *width,
3810 Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3811 ),
3812 );
3813 }
3814 };
3815 }
3816 }
3817
3818 pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3820 self.render_layer
3821 .iter()
3822 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
3823 }
3824
3825 pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3827 for i in index + 1..self.render_layer.len() {
3828 let point = self.render_layer[i].1;
3829 if mouse_pos[0] > point[0][0]
3830 && mouse_pos[1] > point[0][1]
3831 && mouse_pos[0] < point[1][0]
3832 && mouse_pos[1] < point[1][1]
3833 && !self.render_layer[i].2
3834 {
3835 return false;
3836 };
3837 }
3838 true
3839 }
3840
3841 pub fn add_active_resource(
3843 &mut self,
3844 name: &str,
3845 discern_type: &str,
3846 ) -> Result<(), RustConstructorError> {
3847 if self.check_resource_exists(name, discern_type).is_some() {
3848 self.active_list.push(RustConstructorId {
3849 name: name.to_string(),
3850 discern_type: discern_type.to_string(),
3851 });
3852 Ok(())
3853 } else {
3854 Err(RustConstructorError {
3855 error_id: "ResourceNotFound".to_string(),
3856 description: format!("Resource \"{name}({discern_type})\" not found."),
3857 })
3858 }
3859 }
3860
3861 pub fn add_resource<T: RustConstructorResource + 'static>(
3863 &mut self,
3864 name: &str,
3865 mut resource: T,
3866 ) -> Result<(), RustConstructorError> {
3867 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3868 list.0
3869 } else {
3870 type_name_of_val(&resource)
3871 };
3872 if self.check_resource_exists(name, discern_type).is_some() {
3873 return Err(RustConstructorError {
3874 error_id: "ResourceNameRepetition".to_string(),
3875 description: format!("Resource \"{name}({discern_type})\" has already existed."),
3876 });
3877 };
3878 if name.is_empty() {
3879 return Err(RustConstructorError {
3880 error_id: "ResourceUntitled".to_string(),
3881 description: "All resources must have a valid name.".to_string(),
3882 });
3883 };
3884 match discern_type {
3885 "rust_constructor::SplitTime" => {
3886 if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3887 split_time.time = [self.timer.now_time, self.timer.total_time];
3888 };
3889 }
3890 "rust_constructor::ImageTexture" => {
3891 if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3892 if let Ok(mut file) = File::open(&image_texture.cite_path) {
3893 let mut buffer = Vec::new();
3894 file.read_to_end(&mut buffer).unwrap();
3895 let img_bytes = buffer;
3896 let img = image::load_from_memory(&img_bytes).unwrap();
3897 let color_data = match image_texture.flip {
3898 [true, true] => img.fliph().flipv().into_rgba8(),
3899 [true, false] => img.fliph().into_rgba8(),
3900 [false, true] => img.flipv().into_rgba8(),
3901 _ => img.into_rgba8(),
3902 };
3903 let (w, h) = (color_data.width(), color_data.height());
3904 let raw_data: Vec<u8> = color_data.into_raw();
3905
3906 let color_image =
3907 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3908 let loaded_image_texture = image_texture.context.load_texture(
3909 name,
3910 color_image,
3911 TextureOptions::LINEAR,
3912 );
3913 image_texture.texture =
3914 Some(DebugTextureHandle::new(&loaded_image_texture));
3915 image_texture.cite_path = image_texture.cite_path.to_string();
3916 } else {
3917 return Err(RustConstructorError {
3918 error_id: "ImageLoadFailed".to_string(),
3919 description: format!(
3920 "Failed to load an image from the path \"{}\".",
3921 image_texture.cite_path
3922 ),
3923 });
3924 };
3925 };
3926 }
3927 "rust_constructor::Image" => {
3928 if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3929 let image_texture = self.get_resource::<ImageTexture>(
3930 &image.cite_texture,
3931 "rust_constructor::ImageTexture",
3932 )?;
3933 image.texture = image_texture.texture.clone();
3934 image.last_frame_cite_texture = image.cite_texture.clone();
3935 };
3936 }
3937 "rust_constructor::Font" => {
3938 if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3939 let mut fonts = FontDefinitions::default();
3940 if let Ok(font_read_data) = read(&font.path) {
3941 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3942 fonts.font_data.insert(
3943 name.to_owned(),
3944 Arc::new(FontData::from_owned(
3945 Arc::try_unwrap(font_data).ok().unwrap(),
3946 )),
3947 );
3948
3949 fonts
3951 .families
3952 .entry(FontFamily::Proportional)
3953 .or_default()
3954 .insert(0, name.to_owned());
3955
3956 fonts
3957 .families
3958 .entry(FontFamily::Monospace)
3959 .or_default()
3960 .insert(0, name.to_owned());
3961
3962 font.font_definitions = fonts;
3963 } else {
3964 return Err(RustConstructorError {
3965 error_id: "FontLoadFailed".to_string(),
3966 description: format!(
3967 "Failed to load a font from the path \"{}\".",
3968 font.path
3969 ),
3970 });
3971 }
3972 };
3973 }
3974 "rust_constructor::Background" => {
3975 if let Some(background) = resource.as_any_mut().downcast_mut::<Background>() {
3976 match &background.background_type {
3977 BackgroundType::CustomRect(config) => {
3978 let mut custom_rect = CustomRect::default().from_config(config);
3979 if background.use_background_tags {
3980 custom_rect.modify_tags(&background.tags, false);
3981 };
3982 self.add_resource(name, custom_rect)
3983 }
3984 BackgroundType::Image(config) => {
3985 let mut image = Image::default().from_config(config);
3986 if background.use_background_tags {
3987 image.modify_tags(&background.tags, false);
3988 };
3989 self.add_resource(name, image)
3990 }
3991 }?;
3992 };
3993 }
3994 "rust_constructor::Switch" => {
3995 if let Some(switch) = resource.as_any_mut().downcast_mut::<Switch>() {
3996 let count = 1 + switch.enable_animation.iter().filter(|x| **x).count();
3997 if switch.appearance.len() != count * switch.state_amount as usize {
3998 return Err(RustConstructorError {
3999 error_id: "SwitchAppearanceConfigMismatch".to_string(),
4000 description: format!(
4001 "Expected {} elements, found {}.",
4002 count * switch.state_amount as usize,
4003 switch.appearance.len()
4004 ),
4005 });
4006 };
4007 self.add_resource(
4008 &format!("{name}Background"),
4009 Background::default()
4010 .background_type(&switch.background_type)
4011 .auto_update(true)
4012 .use_background_tags(true)
4013 .tags(
4014 &[
4015 ["citer_name".to_string(), name.to_string()],
4016 ["citer_type".to_string(), discern_type.to_string()],
4017 ],
4018 false,
4019 ),
4020 )?;
4021 self.add_resource(
4022 &format!("{name}Text"),
4023 Text::default().from_config(&switch.text_config).tags(
4024 &[
4025 ["citer_name".to_string(), name.to_string()],
4026 ["citer_type".to_string(), discern_type.to_string()],
4027 ],
4028 false,
4029 ),
4030 )?;
4031 self.add_resource(
4032 &format!("{name}HintText"),
4033 Text::default()
4034 .from_config(&switch.hint_text_config)
4035 .ignore_render_layer(true)
4036 .hidden(true)
4037 .tags(
4038 &[
4039 ["citer_name".to_string(), name.to_string()],
4040 ["citer_type".to_string(), discern_type.to_string()],
4041 ["disable_x_scrolling".to_string(), "".to_string()],
4042 ["disable_y_scrolling".to_string(), "".to_string()],
4043 ],
4044 false,
4045 ),
4046 )?;
4047 self.add_resource(
4048 &format!("{name}StartHoverTime"),
4049 SplitTime::default().tags(
4050 &[
4051 ["citer_name".to_string(), name.to_string()],
4052 ["citer_type".to_string(), discern_type.to_string()],
4053 ],
4054 false,
4055 ),
4056 )?;
4057 self.add_resource(
4058 &format!("{name}HintFadeAnimation"),
4059 SplitTime::default().tags(
4060 &[
4061 ["citer_name".to_string(), name.to_string()],
4062 ["citer_type".to_string(), discern_type.to_string()],
4063 ],
4064 false,
4065 ),
4066 )?;
4067 };
4068 }
4069 "rust_constructor::ResourcePanel" => {
4070 if let Some(resource_panel) = resource.as_any_mut().downcast_mut::<ResourcePanel>()
4071 {
4072 self.add_resource(
4073 &format!("{name}Background"),
4074 Background::default()
4075 .background_type(&resource_panel.background)
4076 .auto_update(true)
4077 .use_background_tags(true)
4078 .tags(
4079 &[
4080 ["citer_name".to_string(), name.to_string()],
4081 ["citer_type".to_string(), discern_type.to_string()],
4082 ],
4083 false,
4084 ),
4085 )?;
4086 if let ScrollBarDisplayMethod::Always(_, _, _) =
4087 &resource_panel.scroll_bar_display_method
4088 {
4089 self.add_resource(
4090 &format!("{name}XScroll"),
4091 Background::default()
4092 .auto_update(true)
4093 .use_background_tags(true)
4094 .tags(
4095 &[
4096 ["citer_name".to_string(), name.to_string()],
4097 ["citer_type".to_string(), discern_type.to_string()],
4098 ],
4099 false,
4100 ),
4101 )?;
4102 self.add_resource(
4103 &format!("{name}YScroll"),
4104 Background::default()
4105 .auto_update(true)
4106 .use_background_tags(true)
4107 .tags(
4108 &[
4109 ["citer_name".to_string(), name.to_string()],
4110 ["citer_type".to_string(), discern_type.to_string()],
4111 ],
4112 false,
4113 ),
4114 )?;
4115 };
4116 if let ScrollBarDisplayMethod::OnlyScroll(_, _, _) =
4117 &resource_panel.scroll_bar_display_method
4118 {
4119 self.add_resource(
4120 &format!("{name}XScroll"),
4121 Background::default()
4122 .auto_update(true)
4123 .use_background_tags(true)
4124 .tags(
4125 &[
4126 ["citer_name".to_string(), name.to_string()],
4127 ["citer_type".to_string(), discern_type.to_string()],
4128 ],
4129 false,
4130 ),
4131 )?;
4132 self.add_resource(
4133 &format!("{name}YScroll"),
4134 Background::default()
4135 .auto_update(true)
4136 .use_background_tags(true)
4137 .tags(
4138 &[
4139 ["citer_name".to_string(), name.to_string()],
4140 ["citer_type".to_string(), discern_type.to_string()],
4141 ],
4142 false,
4143 ),
4144 )?;
4145 self.add_resource(
4146 &format!("{name}ScrollBarXAlpha"),
4147 SplitTime::default().tags(
4148 &[
4149 ["citer_name".to_string(), name.to_string()],
4150 ["citer_type".to_string(), discern_type.to_string()],
4151 ],
4152 false,
4153 ),
4154 )?;
4155 self.add_resource(
4156 &format!("{name}ScrollBarXAlphaStart"),
4157 SplitTime::default().tags(
4158 &[
4159 ["citer_name".to_string(), name.to_string()],
4160 ["citer_type".to_string(), discern_type.to_string()],
4161 ],
4162 false,
4163 ),
4164 )?;
4165 self.add_resource(
4166 &format!("{name}ScrollBarYAlpha"),
4167 SplitTime::default().tags(
4168 &[
4169 ["citer_name".to_string(), name.to_string()],
4170 ["citer_type".to_string(), discern_type.to_string()],
4171 ],
4172 false,
4173 ),
4174 )?;
4175 self.add_resource(
4176 &format!("{name}ScrollBarYAlphaStart"),
4177 SplitTime::default().tags(
4178 &[
4179 ["citer_name".to_string(), name.to_string()],
4180 ["citer_type".to_string(), discern_type.to_string()],
4181 ],
4182 false,
4183 ),
4184 )?;
4185 };
4186 };
4187 }
4188 _ => {}
4189 };
4190 self.rust_constructor_resource
4191 .push(RustConstructorResourceBox::new(
4192 name,
4193 discern_type,
4194 Box::new(resource),
4195 ));
4196 Ok(())
4197 }
4198
4199 pub fn drop_resource(
4201 &mut self,
4202 name: &str,
4203 discern_type: &str,
4204 ) -> Result<(), RustConstructorError> {
4205 if let Some(index) = self.check_resource_exists(name, discern_type) {
4206 self.rust_constructor_resource.remove(index);
4207 if let Some(index) = self
4208 .active_list
4209 .iter()
4210 .position(|x| x.name == name && x.discern_type == discern_type)
4211 {
4212 self.active_list.remove(index);
4213 };
4214 if let Some(index) = self
4215 .render_layer
4216 .iter()
4217 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
4218 {
4219 self.render_layer.remove(index);
4220 };
4221 Ok(())
4222 } else {
4223 Err(RustConstructorError {
4224 error_id: "ResourceNotFound".to_string(),
4225 description: format!("Resource \"{name}({discern_type})\" not found."),
4226 })
4227 }
4228 }
4229
4230 pub fn replace_resource<T>(
4232 &mut self,
4233 name: &str,
4234 resource: T,
4235 ) -> Result<(), RustConstructorError>
4236 where
4237 T: RustConstructorResource + 'static,
4238 {
4239 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4240 list.0
4241 } else {
4242 type_name_of_val(&resource)
4243 };
4244 if let Some(index) = self.check_resource_exists(name, discern_type) {
4245 self.rust_constructor_resource[index] =
4246 RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
4247 Ok(())
4248 } else {
4249 Err(RustConstructorError {
4250 error_id: "ResourceNotFound".to_string(),
4251 description: format!("Resource \"{name}({discern_type})\" not found."),
4252 })
4253 }
4254 }
4255
4256 pub fn get_box_resource(
4258 &self,
4259 name: &str,
4260 discern_type: &str,
4261 ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
4262 if let Some(index) = self.check_resource_exists(name, discern_type) {
4263 Ok(&*self.rust_constructor_resource[index].content)
4264 } else {
4265 Err(RustConstructorError {
4266 error_id: "ResourceNotFound".to_string(),
4267 description: format!("Resource \"{name}({discern_type})\" not found."),
4268 })
4269 }
4270 }
4271
4272 pub fn get_box_resource_mut(
4274 &mut self,
4275 name: &str,
4276 discern_type: &str,
4277 ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
4278 if let Some(index) = self.check_resource_exists(name, discern_type) {
4279 Ok(&mut *self.rust_constructor_resource[index].content)
4280 } else {
4281 Err(RustConstructorError {
4282 error_id: "ResourceNotFound".to_string(),
4283 description: format!("Resource \"{name}({discern_type})\" not found."),
4284 })
4285 }
4286 }
4287
4288 pub fn get_resource<T>(
4290 &self,
4291 name: &str,
4292 discern_type: &str,
4293 ) -> Result<&T, RustConstructorError>
4294 where
4295 T: RustConstructorResource + 'static,
4296 {
4297 if let Some(resource) = self
4298 .get_box_resource(name, discern_type)?
4299 .as_any()
4300 .downcast_ref::<T>()
4301 {
4302 Ok(resource)
4303 } else {
4304 Err(RustConstructorError {
4305 error_id: "ResourceGenericMismatch".to_string(),
4306 description: format!(
4307 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4308 ),
4309 })
4310 }
4311 }
4312
4313 pub fn get_resource_mut<T>(
4315 &mut self,
4316 name: &str,
4317 discern_type: &str,
4318 ) -> Result<&mut T, RustConstructorError>
4319 where
4320 T: RustConstructorResource + 'static,
4321 {
4322 if let Some(resource) = self
4323 .get_box_resource_mut(name, discern_type)?
4324 .as_any_mut()
4325 .downcast_mut::<T>()
4326 {
4327 Ok(resource)
4328 } else {
4329 Err(RustConstructorError {
4330 error_id: "ResourceGenericMismatch".to_string(),
4331 description: format!(
4332 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4333 ),
4334 })
4335 }
4336 }
4337
4338 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
4340 self.rust_constructor_resource
4341 .iter()
4342 .position(|x| x.id.name == name && x.id.discern_type == discern_type)
4343 }
4344
4345 pub fn quick_place<T: RustConstructorResource + 'static>(
4347 &mut self,
4348 name: &str,
4349 resource: T,
4350 ui: &mut Ui,
4351 ctx: &Context,
4352 ) -> Result<(), RustConstructorError> {
4353 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4354 list.0
4355 } else {
4356 type_name_of_val(&resource)
4357 };
4358 if self.check_resource_exists(name, discern_type).is_none() {
4359 self.add_resource(name, resource)
4360 } else {
4361 self.use_resource(name, discern_type, ui, ctx)
4362 }
4363 }
4364
4365 pub fn use_resource(
4367 &mut self,
4368 name: &str,
4369 discern_type: &str,
4370 ui: &mut Ui,
4371 ctx: &Context,
4372 ) -> Result<(), RustConstructorError> {
4373 if self.check_resource_exists(name, discern_type).is_some() {
4374 match discern_type {
4375 "rust_constructor::CustomRect"
4376 | "rust_constructor::Text"
4377 | "rust_constructor::Image" => {
4378 self.add_active_resource(name, discern_type)?;
4379 }
4380 "rust_constructor::PageData" => {
4381 self.update_frame_stats();
4383 self.update_render_list();
4385 for i in 0..self.render_list.len() {
4387 self.draw_resource_by_index(ui, ctx, i)?;
4388 }
4389 self.update_render_layer();
4391 self.active_list.clear();
4393 for rcr in &mut self.rust_constructor_resource {
4395 if let Some(display_info) = &mut rcr.content.display_display_info() {
4396 rcr.content.modify_display_info(DisplayInfo {
4397 enable: true,
4398 hidden: display_info.hidden,
4399 ignore_render_layer: display_info.ignore_render_layer,
4400 });
4401 };
4402 }
4403 self.update_timer();
4405 let current_page = &self.current_page.clone();
4406 let page_data =
4407 self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
4408 if page_data.forced_update {
4409 ctx.request_repaint();
4410 };
4411 }
4412 "rust_constructor::Background" => {
4413 let background = self.get_resource::<Background>(name, discern_type)?.clone();
4414 if background.auto_update {
4415 match &background.background_type {
4416 BackgroundType::CustomRect(config) => {
4417 let mut custom_rect = self
4418 .get_resource::<CustomRect>(
4419 name,
4420 "rust_constructor::CustomRect",
4421 )?
4422 .clone()
4423 .from_config(config);
4424 if background.use_background_tags {
4425 custom_rect.modify_tags(&background.tags, false);
4426 };
4427 self.replace_resource(name, custom_rect)?;
4428 }
4429 BackgroundType::Image(config) => {
4430 let mut image = self
4431 .get_resource::<Image>(name, "rust_constructor::Image")?
4432 .clone()
4433 .from_config(config);
4434 if background.use_background_tags {
4435 image.modify_tags(&background.tags, false);
4436 };
4437 self.replace_resource(name, image)?;
4438 }
4439 };
4440 };
4441 match background.background_type {
4442 BackgroundType::CustomRect(_) => {
4443 self.use_resource(name, "rust_constructor::CustomRect", ui, ctx)
4444 }
4445 BackgroundType::Image(_) => {
4446 self.use_resource(name, "rust_constructor::Image", ui, ctx)
4447 }
4448 }?;
4449 }
4450 "rust_constructor::Switch" => {
4451 let mut switch = self
4452 .get_resource::<Switch>(name, "rust_constructor::Switch")?
4453 .clone();
4454 let mut background = self
4455 .get_resource::<Background>(
4456 &format!("{name}Background"),
4457 "rust_constructor::Background",
4458 )?
4459 .clone();
4460 let background_resource_type = match switch.background_type {
4461 BackgroundType::CustomRect(_) => "rust_constructor::CustomRect",
4462 BackgroundType::Image(_) => "rust_constructor::Image",
4463 };
4464 let background_resource: Box<dyn BasicFrontResource> =
4465 match background_resource_type {
4466 "rust_constructor::CustomRect" => Box::new(
4467 self.get_resource::<CustomRect>(
4468 &format!("{name}Background"),
4469 background_resource_type,
4470 )?
4471 .clone(),
4472 ),
4473 "rust_constructor::Image" => Box::new(
4474 self.get_resource::<Image>(
4475 &format!("{name}Background"),
4476 background_resource_type,
4477 )?
4478 .clone(),
4479 ),
4480 _ => {
4481 unreachable!()
4482 }
4483 };
4484 let mut text = self
4485 .get_resource::<Text>(&format!("{name}Text"), "rust_constructor::Text")?
4486 .clone();
4487 let mut hint_text = self
4488 .get_resource::<Text>(&format!("{name}HintText"), "rust_constructor::Text")?
4489 .clone();
4490 let rect = Rect::from_min_size(
4491 background_resource.display_position().into(),
4492 background_resource.display_size().into(),
4493 );
4494 switch.switched = false;
4495 let animation_count =
4496 1 + switch.enable_animation.iter().filter(|x| **x).count();
4497 let mut clicked = None;
4498 let mut hovered = false;
4499 let mut appearance_count = 0;
4500 if let Some(index) = self.get_render_layer_resource(
4502 &format!("{name}Background"),
4503 background_resource_type,
4504 ) && switch.enable
4505 && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
4506 && self.resource_get_focus(index, mouse_pos.into())
4507 {
4508 if rect.contains(mouse_pos) {
4510 if !switch.last_frame_hovered {
4511 self.reset_split_time(&format!("{name}StartHoverTime"))?;
4512 } else if self.timer.total_time
4513 - self.get_split_time(&format!("{name}StartHoverTime"))?[1]
4514 >= 2_f32
4515 || hint_text.alpha != 0
4516 {
4517 hint_text.alpha = 255;
4518 hint_text
4519 .basic_front_resource_config
4520 .position_size_config
4521 .origin_position = [mouse_pos.x, mouse_pos.y];
4522 };
4523 hint_text
4524 .basic_front_resource_config
4525 .position_size_config
4526 .display_method
4527 .0 = if mouse_pos.x + hint_text.actual_size[0]
4528 <= ctx.available_rect().width()
4529 {
4530 HorizontalAlign::Left
4531 } else {
4532 HorizontalAlign::Right
4533 };
4534 hint_text
4535 .basic_front_resource_config
4536 .position_size_config
4537 .display_method
4538 .1 = if mouse_pos.y + hint_text.actual_size[1]
4539 <= ctx.available_rect().height()
4540 {
4541 VerticalAlign::Top
4542 } else {
4543 VerticalAlign::Bottom
4544 };
4545 hovered = true;
4546 for (count, click_method) in switch.click_method.iter().enumerate() {
4547 if ui.input(|i| i.pointer.button_down(click_method.click_method)) {
4548 clicked = Some(count);
4549 break;
4550 };
4551 }
4552 if let Some(clicked_index) = switch.last_frame_clicked
4553 && clicked.is_none()
4554 {
4555 switch.switched = true;
4556 if switch.click_method[clicked_index].action {
4557 if switch.state
4558 < (switch.appearance.len() / animation_count - 1) as u32
4559 {
4560 switch.state += 1;
4561 } else {
4562 switch.state = 0;
4563 };
4564 };
4565 };
4566 appearance_count = if clicked.is_some() {
4567 match switch.enable_animation {
4568 [true, true] => 2,
4569 [true, false] | [false, true] => 1,
4570 [false, false] => 0,
4571 }
4572 } else if switch.enable_animation[0] {
4573 1
4574 } else {
4575 0
4576 };
4577 };
4578 };
4579
4580 if !hovered {
4582 if switch.last_frame_hovered {
4583 self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4584 };
4585 if self.timer.total_time
4586 - self.get_split_time(&format!("{name}HintFadeAnimation"))?[1]
4587 >= self.tick_interval
4588 {
4589 self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4590 hint_text.alpha = hint_text.alpha.saturating_sub(10);
4591 };
4592 };
4593
4594 hint_text.display_info.hidden = hint_text.alpha == 0;
4595
4596 background.background_type = switch.appearance
4598 [(switch.state * animation_count as u32 + appearance_count) as usize]
4599 .background_config
4600 .clone();
4601
4602 let alpha = hint_text.alpha;
4604 hint_text = hint_text.from_config(
4605 &switch.appearance
4606 [(switch.state * animation_count as u32 + appearance_count) as usize]
4607 .hint_text_config,
4608 );
4609 hint_text.background_alpha = alpha;
4610 hint_text.alpha = alpha;
4611
4612 text = text.from_config(
4614 &switch.appearance
4615 [(switch.state * animation_count as u32 + appearance_count) as usize]
4616 .text_config,
4617 );
4618
4619 switch.last_frame_hovered = hovered;
4620 switch.last_frame_clicked = clicked;
4621
4622 self.replace_resource(&format!("{name}Text"), text)?;
4623 self.replace_resource(&format!("{name}HintText"), hint_text)?;
4624 self.replace_resource(name, switch)?;
4625 self.replace_resource(&format!("{name}Background"), background)?;
4626
4627 self.use_resource(
4628 &format!("{name}Background"),
4629 "rust_constructor::Background",
4630 ui,
4631 ctx,
4632 )?;
4633 self.use_resource(&format!("{name}Text"), "rust_constructor::Text", ui, ctx)?;
4634 self.use_resource(
4635 &format!("{name}HintText"),
4636 "rust_constructor::Text",
4637 ui,
4638 ctx,
4639 )?;
4640 }
4641 "rust_constructor::ResourcePanel" => {
4642 let mut resource_panel = self
4643 .get_resource::<ResourcePanel>(name, "rust_constructor::ResourcePanel")?
4644 .clone();
4645 let background = self
4646 .get_resource::<Background>(
4647 &format!("{name}Background"),
4648 "rust_constructor::Background",
4649 )?
4650 .clone();
4651 let background_resource: Box<dyn BasicFrontResource> =
4652 match background.background_type.clone() {
4653 BackgroundType::CustomRect(_) => Box::new(
4654 self.get_resource::<CustomRect>(
4655 &format!("{name}Background"),
4656 "rust_constructor::CustomRect",
4657 )?
4658 .clone(),
4659 ),
4660 BackgroundType::Image(_) => Box::new(
4661 self.get_resource::<Image>(
4662 &format!("{name}Background"),
4663 "rust_constructor::Image",
4664 )?
4665 .clone(),
4666 ),
4667 };
4668 let (mut position_size_config, mut position, mut size) = (
4669 background_resource
4670 .display_basic_front_resource_config()
4671 .position_size_config,
4672 background_resource.display_position(),
4673 background_resource.display_size(),
4674 );
4675 let rect = Rect::from_min_size(position.into(), size.into());
4676 resource_panel.scrolled = [false, false];
4677 if resource_panel.resizable.contains(&true)
4678 || resource_panel.movable.contains(&true)
4679 {
4680 position_size_config.x_location_grid = [0_f32, 0_f32];
4681 position_size_config.y_location_grid = [0_f32, 0_f32];
4682 position_size_config.x_size_grid = [0_f32, 0_f32];
4683 position_size_config.y_size_grid = [0_f32, 0_f32];
4684 };
4685 if resource_panel.min_size[0] < 10_f32 {
4686 resource_panel.min_size[0] = 10_f32;
4687 };
4688 if resource_panel.min_size[1] < 10_f32 {
4689 resource_panel.min_size[1] = 10_f32;
4690 };
4691 if position_size_config.origin_size[0] < resource_panel.min_size[0] {
4692 position_size_config.origin_size[0] = resource_panel.min_size[0];
4693 };
4694 if position_size_config.origin_size[1] < resource_panel.min_size[1] {
4695 position_size_config.origin_size[1] = resource_panel.min_size[1];
4696 };
4697 [position, size] = self.position_size_processor(position_size_config, ctx);
4698 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4699 let top_rect = Rect::from_min_size(
4700 [position[0] - 3_f32, position[1] - 3_f32].into(),
4701 [size[0] + 6_f32, 6_f32].into(),
4702 );
4703 let bottom_rect = Rect::from_min_size(
4704 [position[0] - 3_f32, position[1] + size[1] - 3_f32].into(),
4705 [size[0] + 6_f32, 6_f32].into(),
4706 );
4707 let left_rect = Rect::from_min_size(
4708 [position[0] - 3_f32, position[1] - 3_f32].into(),
4709 [6_f32, size[1] + 6_f32].into(),
4710 );
4711 let right_rect = Rect::from_min_size(
4712 [position[0] + size[0] - 3_f32, position[1] - 3_f32].into(),
4713 [6_f32, size[1] + 6_f32].into(),
4714 );
4715 match [
4716 top_rect.contains(mouse_pos),
4717 bottom_rect.contains(mouse_pos),
4718 left_rect.contains(mouse_pos),
4719 right_rect.contains(mouse_pos),
4720 ] {
4721 [true, false, false, false] => {
4722 if resource_panel.resizable[0] {
4723 if resource_panel.last_frame_mouse_status.is_none()
4724 && ui.input(|i| i.pointer.primary_pressed())
4725 {
4726 resource_panel.last_frame_mouse_status = Some((
4727 mouse_pos.into(),
4728 ClickAim::TopResize,
4729 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4730 ))
4731 };
4732 if size[1] > resource_panel.min_size[1]
4733 && (resource_panel.max_size.is_none()
4734 || size[1] < resource_panel.max_size.unwrap()[1])
4735 {
4736 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4737 } else if resource_panel.max_size.is_some()
4738 && size[1] >= resource_panel.max_size.unwrap()[1]
4739 {
4740 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4741 } else {
4742 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4743 };
4744 };
4745 }
4746 [false, true, false, false] => {
4747 if resource_panel.resizable[1] {
4748 if resource_panel.last_frame_mouse_status.is_none()
4749 && ui.input(|i| i.pointer.primary_pressed())
4750 {
4751 resource_panel.last_frame_mouse_status = Some((
4752 mouse_pos.into(),
4753 ClickAim::BottomResize,
4754 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4755 ))
4756 };
4757 if size[1] > resource_panel.min_size[1]
4758 && (resource_panel.max_size.is_none()
4759 || size[1] < resource_panel.max_size.unwrap()[1])
4760 {
4761 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4762 } else if resource_panel.max_size.is_some()
4763 && size[1] >= resource_panel.max_size.unwrap()[1]
4764 {
4765 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4766 } else {
4767 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4768 };
4769 };
4770 }
4771 [false, false, true, false] => {
4772 if resource_panel.resizable[2] {
4773 if resource_panel.last_frame_mouse_status.is_none()
4774 && ui.input(|i| i.pointer.primary_pressed())
4775 {
4776 resource_panel.last_frame_mouse_status = Some((
4777 mouse_pos.into(),
4778 ClickAim::LeftResize,
4779 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4780 ))
4781 };
4782 if size[0] > resource_panel.min_size[0]
4783 && (resource_panel.max_size.is_none()
4784 || size[0] < resource_panel.max_size.unwrap()[0])
4785 {
4786 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4787 } else if resource_panel.max_size.is_some()
4788 && size[0] >= resource_panel.max_size.unwrap()[0]
4789 {
4790 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4791 } else {
4792 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4793 };
4794 };
4795 }
4796 [false, false, false, true] => {
4797 if resource_panel.resizable[3] {
4798 if resource_panel.last_frame_mouse_status.is_none()
4799 && ui.input(|i| i.pointer.primary_pressed())
4800 {
4801 resource_panel.last_frame_mouse_status = Some((
4802 mouse_pos.into(),
4803 ClickAim::RightResize,
4804 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4805 ))
4806 };
4807 if size[0] > resource_panel.min_size[0]
4808 && (resource_panel.max_size.is_none()
4809 || size[0] < resource_panel.max_size.unwrap()[0])
4810 {
4811 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4812 } else if resource_panel.max_size.is_some()
4813 && size[0] >= resource_panel.max_size.unwrap()[0]
4814 {
4815 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4816 } else {
4817 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4818 };
4819 };
4820 }
4821 [true, false, true, false] => {
4822 match [resource_panel.resizable[0], resource_panel.resizable[2]] {
4823 [true, true] => {
4824 if resource_panel.last_frame_mouse_status.is_none()
4825 && ui.input(|i| i.pointer.primary_pressed())
4826 {
4827 resource_panel.last_frame_mouse_status = Some((
4828 mouse_pos.into(),
4829 ClickAim::LeftTopResize,
4830 [
4831 mouse_pos.x - position[0],
4832 mouse_pos.y - position[1],
4833 ],
4834 ))
4835 };
4836 if size[0] > resource_panel.min_size[0]
4837 && (resource_panel.max_size.is_none()
4838 || size[0] < resource_panel.max_size.unwrap()[0])
4839 || size[1] > resource_panel.min_size[1]
4840 && (resource_panel.max_size.is_none()
4841 || size[1]
4842 < resource_panel.max_size.unwrap()[1])
4843 {
4844 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
4845 } else if resource_panel.max_size.is_some()
4846 && size[0] >= resource_panel.max_size.unwrap()[0]
4847 && size[1] >= resource_panel.max_size.unwrap()[1]
4848 {
4849 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
4850 } else {
4851 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
4852 };
4853 }
4854 [false, true] => {
4855 if resource_panel.last_frame_mouse_status.is_none()
4856 && ui.input(|i| i.pointer.primary_pressed())
4857 {
4858 resource_panel.last_frame_mouse_status = Some((
4859 mouse_pos.into(),
4860 ClickAim::LeftResize,
4861 [
4862 mouse_pos.x - position[0],
4863 mouse_pos.y - position[1],
4864 ],
4865 ))
4866 };
4867 if size[0] > resource_panel.min_size[0]
4868 && (resource_panel.max_size.is_none()
4869 || size[0] < resource_panel.max_size.unwrap()[0])
4870 {
4871 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4872 } else if resource_panel.max_size.is_some()
4873 && size[0] >= resource_panel.max_size.unwrap()[0]
4874 {
4875 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4876 } else {
4877 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4878 };
4879 }
4880 [true, false] => {
4881 if resource_panel.last_frame_mouse_status.is_none()
4882 && ui.input(|i| i.pointer.primary_pressed())
4883 {
4884 resource_panel.last_frame_mouse_status = Some((
4885 mouse_pos.into(),
4886 ClickAim::TopResize,
4887 [
4888 mouse_pos.x - position[0],
4889 mouse_pos.y - position[1],
4890 ],
4891 ))
4892 };
4893 if size[1] > resource_panel.min_size[1]
4894 && (resource_panel.max_size.is_none()
4895 || size[1] < resource_panel.max_size.unwrap()[1])
4896 {
4897 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4898 } else if resource_panel.max_size.is_some()
4899 && size[1] >= resource_panel.max_size.unwrap()[1]
4900 {
4901 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4902 } else {
4903 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4904 };
4905 }
4906 [false, false] => {}
4907 }
4908 }
4909 [false, true, false, true] => {
4910 match [resource_panel.resizable[1], resource_panel.resizable[3]] {
4911 [true, true] => {
4912 if resource_panel.last_frame_mouse_status.is_none()
4913 && ui.input(|i| i.pointer.primary_pressed())
4914 {
4915 resource_panel.last_frame_mouse_status = Some((
4916 mouse_pos.into(),
4917 ClickAim::RightBottomResize,
4918 [
4919 mouse_pos.x - position[0],
4920 mouse_pos.y - position[1],
4921 ],
4922 ))
4923 };
4924 if size[0] > resource_panel.min_size[0]
4925 && (resource_panel.max_size.is_none()
4926 || size[0] < resource_panel.max_size.unwrap()[0])
4927 || size[1] > resource_panel.min_size[1]
4928 && (resource_panel.max_size.is_none()
4929 || size[1]
4930 < resource_panel.max_size.unwrap()[1])
4931 {
4932 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
4933 } else if resource_panel.max_size.is_some()
4934 && size[0] >= resource_panel.max_size.unwrap()[0]
4935 && size[1] >= resource_panel.max_size.unwrap()[1]
4936 {
4937 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
4938 } else {
4939 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
4940 };
4941 }
4942 [false, true] => {
4943 if resource_panel.last_frame_mouse_status.is_none()
4944 && ui.input(|i| i.pointer.primary_pressed())
4945 {
4946 resource_panel.last_frame_mouse_status = Some((
4947 mouse_pos.into(),
4948 ClickAim::RightResize,
4949 [
4950 mouse_pos.x - position[0],
4951 mouse_pos.y - position[1],
4952 ],
4953 ))
4954 };
4955 if size[0] > resource_panel.min_size[0]
4956 && (resource_panel.max_size.is_none()
4957 || size[0] < resource_panel.max_size.unwrap()[0])
4958 {
4959 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4960 } else if resource_panel.max_size.is_some()
4961 && size[0] >= resource_panel.max_size.unwrap()[0]
4962 {
4963 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4964 } else {
4965 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4966 };
4967 }
4968 [true, false] => {
4969 if resource_panel.last_frame_mouse_status.is_none()
4970 && ui.input(|i| i.pointer.primary_pressed())
4971 {
4972 resource_panel.last_frame_mouse_status = Some((
4973 mouse_pos.into(),
4974 ClickAim::BottomResize,
4975 [
4976 mouse_pos.x - position[0],
4977 mouse_pos.y - position[1],
4978 ],
4979 ))
4980 };
4981 if size[1] > resource_panel.min_size[1]
4982 && (resource_panel.max_size.is_none()
4983 || size[1] < resource_panel.max_size.unwrap()[1])
4984 {
4985 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4986 } else if resource_panel.max_size.is_some()
4987 && size[1] >= resource_panel.max_size.unwrap()[1]
4988 {
4989 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4990 } else {
4991 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4992 };
4993 }
4994 [false, false] => {}
4995 }
4996 }
4997 [true, false, false, true] => {
4998 match [resource_panel.resizable[0], resource_panel.resizable[3]] {
4999 [true, true] => {
5000 if resource_panel.last_frame_mouse_status.is_none()
5001 && ui.input(|i| i.pointer.primary_pressed())
5002 {
5003 resource_panel.last_frame_mouse_status = Some((
5004 mouse_pos.into(),
5005 ClickAim::RightTopResize,
5006 [
5007 mouse_pos.x - position[0],
5008 mouse_pos.y - position[1],
5009 ],
5010 ))
5011 };
5012 if size[0] > resource_panel.min_size[0]
5013 && (resource_panel.max_size.is_none()
5014 || size[0] < resource_panel.max_size.unwrap()[0])
5015 || size[1] > resource_panel.min_size[1]
5016 && (resource_panel.max_size.is_none()
5017 || size[1]
5018 < resource_panel.max_size.unwrap()[1])
5019 {
5020 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5021 } else if resource_panel.max_size.is_some()
5022 && size[0] >= resource_panel.max_size.unwrap()[0]
5023 && size[1] >= resource_panel.max_size.unwrap()[1]
5024 {
5025 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5026 } else {
5027 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5028 };
5029 }
5030 [false, true] => {
5031 if resource_panel.last_frame_mouse_status.is_none()
5032 && ui.input(|i| i.pointer.primary_pressed())
5033 {
5034 resource_panel.last_frame_mouse_status = Some((
5035 mouse_pos.into(),
5036 ClickAim::RightResize,
5037 [
5038 mouse_pos.x - position[0],
5039 mouse_pos.y - position[1],
5040 ],
5041 ))
5042 };
5043 if size[0] > resource_panel.min_size[0]
5044 && (resource_panel.max_size.is_none()
5045 || size[0] < resource_panel.max_size.unwrap()[0])
5046 {
5047 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5048 } else if resource_panel.max_size.is_some()
5049 && size[0] >= resource_panel.max_size.unwrap()[0]
5050 {
5051 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5052 } else {
5053 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5054 };
5055 }
5056 [true, false] => {
5057 if resource_panel.last_frame_mouse_status.is_none()
5058 && ui.input(|i| i.pointer.primary_pressed())
5059 {
5060 resource_panel.last_frame_mouse_status = Some((
5061 mouse_pos.into(),
5062 ClickAim::TopResize,
5063 [
5064 mouse_pos.x - position[0],
5065 mouse_pos.y - position[1],
5066 ],
5067 ))
5068 };
5069 if size[1] > resource_panel.min_size[1]
5070 && (resource_panel.max_size.is_none()
5071 || size[1] < resource_panel.max_size.unwrap()[1])
5072 {
5073 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5074 } else if resource_panel.max_size.is_some()
5075 && size[1] >= resource_panel.max_size.unwrap()[1]
5076 {
5077 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5078 } else {
5079 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5080 };
5081 }
5082 [false, false] => {}
5083 }
5084 }
5085 [false, true, true, false] => {
5086 match [resource_panel.resizable[1], resource_panel.resizable[2]] {
5087 [true, true] => {
5088 if resource_panel.last_frame_mouse_status.is_none()
5089 && ui.input(|i| i.pointer.primary_pressed())
5090 {
5091 resource_panel.last_frame_mouse_status = Some((
5092 mouse_pos.into(),
5093 ClickAim::LeftBottomResize,
5094 [
5095 mouse_pos.x - position[0],
5096 mouse_pos.y - position[1],
5097 ],
5098 ))
5099 };
5100 if size[0] > resource_panel.min_size[0]
5101 && (resource_panel.max_size.is_none()
5102 || size[0] < resource_panel.max_size.unwrap()[0])
5103 || size[1] > resource_panel.min_size[1]
5104 && (resource_panel.max_size.is_none()
5105 || size[1]
5106 < resource_panel.max_size.unwrap()[1])
5107 {
5108 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5109 } else if resource_panel.max_size.is_some()
5110 && size[0] >= resource_panel.max_size.unwrap()[0]
5111 && size[1] >= resource_panel.max_size.unwrap()[1]
5112 {
5113 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5114 } else {
5115 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5116 };
5117 }
5118 [false, true] => {
5119 if resource_panel.last_frame_mouse_status.is_none()
5120 && ui.input(|i| i.pointer.primary_pressed())
5121 {
5122 resource_panel.last_frame_mouse_status = Some((
5123 mouse_pos.into(),
5124 ClickAim::LeftResize,
5125 [
5126 mouse_pos.x - position[0],
5127 mouse_pos.y - position[1],
5128 ],
5129 ))
5130 };
5131 if size[0] > resource_panel.min_size[0]
5132 && (resource_panel.max_size.is_none()
5133 || size[0] < resource_panel.max_size.unwrap()[0])
5134 {
5135 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5136 } else if resource_panel.max_size.is_some()
5137 && size[0] >= resource_panel.max_size.unwrap()[0]
5138 {
5139 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5140 } else {
5141 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5142 };
5143 }
5144 [true, false] => {
5145 if resource_panel.last_frame_mouse_status.is_none()
5146 && ui.input(|i| i.pointer.primary_pressed())
5147 {
5148 resource_panel.last_frame_mouse_status = Some((
5149 mouse_pos.into(),
5150 ClickAim::BottomResize,
5151 [
5152 mouse_pos.x - position[0],
5153 mouse_pos.y - position[1],
5154 ],
5155 ))
5156 };
5157 if size[1] > resource_panel.min_size[1]
5158 && (resource_panel.max_size.is_none()
5159 || size[1] < resource_panel.max_size.unwrap()[1])
5160 {
5161 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5162 } else if resource_panel.max_size.is_some()
5163 && size[1] >= resource_panel.max_size.unwrap()[1]
5164 {
5165 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5166 } else {
5167 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5168 };
5169 }
5170 [false, false] => {}
5171 }
5172 }
5173 _ => {}
5174 };
5175 resource_panel.last_frame_mouse_status =
5176 if resource_panel.last_frame_mouse_status.is_none()
5177 && rect.contains(mouse_pos)
5178 && ui.input(|i| i.pointer.primary_pressed())
5179 {
5180 Some((
5181 [mouse_pos.x, mouse_pos.y],
5182 ClickAim::Move,
5183 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
5184 ))
5185 } else if resource_panel.last_frame_mouse_status.is_some()
5186 && !ui.input(|i| i.pointer.primary_released())
5187 {
5188 Some((
5189 [mouse_pos.x, mouse_pos.y],
5190 resource_panel.last_frame_mouse_status.unwrap().1,
5191 resource_panel.last_frame_mouse_status.unwrap().2,
5192 ))
5193 } else {
5194 None
5195 };
5196 let [x_scroll_delta, y_scroll_delta] =
5197 if resource_panel.use_smooth_scroll_delta {
5198 ui.input(|i| i.smooth_scroll_delta).into()
5199 } else {
5200 ui.input(|i| i.raw_scroll_delta).into()
5201 };
5202 if resource_panel.scroll_length_method[0].is_some()
5203 && x_scroll_delta != 0_f32
5204 && rect.contains(mouse_pos)
5205 {
5206 resource_panel.scrolled[0] = true;
5207 resource_panel.scroll_progress[0] = if resource_panel.scroll_progress[0]
5208 + -x_scroll_delta * resource_panel.scroll_sensitivity
5209 > resource_panel.scroll_length[0]
5210 {
5211 resource_panel.scroll_length[0]
5212 } else if resource_panel.scroll_progress[0]
5213 + -x_scroll_delta * resource_panel.scroll_sensitivity
5214 > 0_f32
5215 {
5216 resource_panel.scroll_progress[0]
5217 + -x_scroll_delta * resource_panel.scroll_sensitivity
5218 } else {
5219 0_f32
5220 };
5221 };
5222 if resource_panel.scroll_length_method[1].is_some()
5223 && y_scroll_delta != 0_f32
5224 && rect.contains(mouse_pos)
5225 {
5226 resource_panel.scrolled[1] = true;
5227 resource_panel.scroll_progress[1] = if resource_panel.scroll_progress[1]
5228 + -y_scroll_delta * resource_panel.scroll_sensitivity
5229 > resource_panel.scroll_length[1]
5230 {
5231 resource_panel.scroll_length[1]
5232 } else if resource_panel.scroll_progress[1]
5233 + -y_scroll_delta * resource_panel.scroll_sensitivity
5234 > 0_f32
5235 {
5236 resource_panel.scroll_progress[1]
5237 + -y_scroll_delta * resource_panel.scroll_sensitivity
5238 } else {
5239 0_f32
5240 };
5241 };
5242 };
5243 if let Some((mouse_pos, click_aim, offset)) =
5244 resource_panel.last_frame_mouse_status
5245 {
5246 match click_aim {
5247 ClickAim::LeftTopResize => {
5248 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5249 && (resource_panel.max_size.is_none()
5250 || position[0] - mouse_pos[0] + size[0]
5251 < resource_panel.max_size.unwrap()[0])
5252 {
5253 position_size_config.origin_size[0] +=
5254 position[0] - mouse_pos[0];
5255 position_size_config.origin_position[0] = mouse_pos[0];
5256 } else if resource_panel.max_size.is_some()
5257 && position[0] - mouse_pos[0] + size[0]
5258 >= resource_panel.max_size.unwrap()[0]
5259 {
5260 position_size_config.origin_position[0] -=
5261 resource_panel.max_size.unwrap()[0]
5262 - position_size_config.origin_size[0];
5263 position_size_config.origin_size[0] =
5264 resource_panel.max_size.unwrap()[0];
5265 } else {
5266 position_size_config.origin_position[0] += position_size_config
5267 .origin_size[0]
5268 - resource_panel.min_size[0];
5269 position_size_config.origin_size[0] =
5270 resource_panel.min_size[0];
5271 };
5272 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5273 && (resource_panel.max_size.is_none()
5274 || position[1] - mouse_pos[1] + size[1]
5275 < resource_panel.max_size.unwrap()[1])
5276 {
5277 position_size_config.origin_size[1] +=
5278 position[1] - mouse_pos[1];
5279 position_size_config.origin_position[1] = mouse_pos[1];
5280 } else if resource_panel.max_size.is_some()
5281 && position[1] - mouse_pos[1] + size[1]
5282 >= resource_panel.max_size.unwrap()[1]
5283 {
5284 position_size_config.origin_position[1] -=
5285 resource_panel.max_size.unwrap()[1]
5286 - position_size_config.origin_size[1];
5287 position_size_config.origin_size[1] =
5288 resource_panel.max_size.unwrap()[1];
5289 } else {
5290 position_size_config.origin_position[1] += position_size_config
5291 .origin_size[1]
5292 - resource_panel.min_size[1];
5293 position_size_config.origin_size[1] =
5294 resource_panel.min_size[1];
5295 };
5296 if size[0] > resource_panel.min_size[0]
5297 && (resource_panel.max_size.is_none()
5298 || size[0] < resource_panel.max_size.unwrap()[0])
5299 || size[1] > resource_panel.min_size[1]
5300 && (resource_panel.max_size.is_none()
5301 || size[1] < resource_panel.max_size.unwrap()[1])
5302 {
5303 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5304 } else if resource_panel.max_size.is_some()
5305 && size[0] >= resource_panel.max_size.unwrap()[0]
5306 && size[1] >= resource_panel.max_size.unwrap()[1]
5307 {
5308 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
5309 } else {
5310 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
5311 };
5312 }
5313 ClickAim::RightBottomResize => {
5314 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5315 && (resource_panel.max_size.is_none()
5316 || mouse_pos[0] - position[0]
5317 < resource_panel.max_size.unwrap()[0])
5318 {
5319 position_size_config.origin_size[0] =
5320 mouse_pos[0] - position[0];
5321 } else if resource_panel.max_size.is_some()
5322 && mouse_pos[0] - position[0]
5323 >= resource_panel.max_size.unwrap()[0]
5324 {
5325 position_size_config.origin_size[0] =
5326 resource_panel.max_size.unwrap()[0];
5327 } else {
5328 position_size_config.origin_size[0] =
5329 resource_panel.min_size[0];
5330 };
5331 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5332 && (resource_panel.max_size.is_none()
5333 || mouse_pos[1] - position[1]
5334 < resource_panel.max_size.unwrap()[1])
5335 {
5336 position_size_config.origin_size[1] =
5337 mouse_pos[1] - position[1];
5338 } else if resource_panel.max_size.is_some()
5339 && mouse_pos[1] - position[1]
5340 >= resource_panel.max_size.unwrap()[1]
5341 {
5342 position_size_config.origin_size[1] =
5343 resource_panel.max_size.unwrap()[1];
5344 } else {
5345 position_size_config.origin_size[1] =
5346 resource_panel.min_size[1];
5347 };
5348 if size[0] > resource_panel.min_size[0]
5349 && (resource_panel.max_size.is_none()
5350 || size[0] < resource_panel.max_size.unwrap()[0])
5351 || size[1] > resource_panel.min_size[1]
5352 && (resource_panel.max_size.is_none()
5353 || size[1] < resource_panel.max_size.unwrap()[1])
5354 {
5355 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5356 } else if resource_panel.max_size.is_some()
5357 && size[0] >= resource_panel.max_size.unwrap()[0]
5358 && size[1] >= resource_panel.max_size.unwrap()[1]
5359 {
5360 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
5361 } else {
5362 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
5363 };
5364 }
5365 ClickAim::RightTopResize => {
5366 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5367 && (resource_panel.max_size.is_none()
5368 || mouse_pos[0] - position[0]
5369 < resource_panel.max_size.unwrap()[0])
5370 {
5371 position_size_config.origin_size[0] =
5372 mouse_pos[0] - position[0];
5373 } else if resource_panel.max_size.is_some()
5374 && mouse_pos[0] - position[0]
5375 >= resource_panel.max_size.unwrap()[0]
5376 {
5377 position_size_config.origin_size[0] =
5378 resource_panel.max_size.unwrap()[0];
5379 } else {
5380 position_size_config.origin_size[0] =
5381 resource_panel.min_size[0];
5382 };
5383 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5384 && (resource_panel.max_size.is_none()
5385 || position[1] - mouse_pos[1] + size[1]
5386 < resource_panel.max_size.unwrap()[1])
5387 {
5388 position_size_config.origin_size[1] +=
5389 position[1] - mouse_pos[1];
5390 position_size_config.origin_position[1] = mouse_pos[1];
5391 } else if resource_panel.max_size.is_some()
5392 && position[1] - mouse_pos[1] + size[1]
5393 >= resource_panel.max_size.unwrap()[1]
5394 {
5395 position_size_config.origin_position[1] -=
5396 resource_panel.max_size.unwrap()[1]
5397 - position_size_config.origin_size[1];
5398 position_size_config.origin_size[1] =
5399 resource_panel.max_size.unwrap()[1];
5400 } else {
5401 position_size_config.origin_position[1] += position_size_config
5402 .origin_size[1]
5403 - resource_panel.min_size[1];
5404 position_size_config.origin_size[1] =
5405 resource_panel.min_size[1];
5406 };
5407 if size[0] > resource_panel.min_size[0]
5408 && (resource_panel.max_size.is_none()
5409 || size[0] < resource_panel.max_size.unwrap()[0])
5410 || size[1] > resource_panel.min_size[1]
5411 && (resource_panel.max_size.is_none()
5412 || size[1] < resource_panel.max_size.unwrap()[1])
5413 {
5414 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5415 } else if resource_panel.max_size.is_some()
5416 && size[0] >= resource_panel.max_size.unwrap()[0]
5417 && size[1] >= resource_panel.max_size.unwrap()[1]
5418 {
5419 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5420 } else {
5421 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5422 };
5423 }
5424 ClickAim::LeftBottomResize => {
5425 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5426 && (resource_panel.max_size.is_none()
5427 || position[0] - mouse_pos[0] + size[0]
5428 < resource_panel.max_size.unwrap()[0])
5429 {
5430 position_size_config.origin_size[0] +=
5431 position[0] - mouse_pos[0];
5432 position_size_config.origin_position[0] = mouse_pos[0];
5433 } else if resource_panel.max_size.is_some()
5434 && position[0] - mouse_pos[0] + size[0]
5435 >= resource_panel.max_size.unwrap()[0]
5436 {
5437 position_size_config.origin_position[0] -=
5438 resource_panel.max_size.unwrap()[0]
5439 - position_size_config.origin_size[0];
5440 position_size_config.origin_size[0] =
5441 resource_panel.max_size.unwrap()[0];
5442 } else {
5443 position_size_config.origin_position[0] += position_size_config
5444 .origin_size[0]
5445 - resource_panel.min_size[0];
5446 position_size_config.origin_size[0] =
5447 resource_panel.min_size[0];
5448 };
5449 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5450 && (resource_panel.max_size.is_none()
5451 || mouse_pos[1] - position[1]
5452 < resource_panel.max_size.unwrap()[1])
5453 {
5454 position_size_config.origin_size[1] =
5455 mouse_pos[1] - position[1];
5456 } else if resource_panel.max_size.is_some()
5457 && mouse_pos[1] - position[1]
5458 >= resource_panel.max_size.unwrap()[1]
5459 {
5460 position_size_config.origin_size[1] =
5461 resource_panel.max_size.unwrap()[1];
5462 } else {
5463 position_size_config.origin_size[1] =
5464 resource_panel.min_size[1];
5465 };
5466 if size[0] > resource_panel.min_size[0]
5467 && (resource_panel.max_size.is_none()
5468 || size[0] < resource_panel.max_size.unwrap()[0])
5469 || size[1] > resource_panel.min_size[1]
5470 && (resource_panel.max_size.is_none()
5471 || size[1] < resource_panel.max_size.unwrap()[1])
5472 {
5473 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5474 } else if resource_panel.max_size.is_some()
5475 && size[0] >= resource_panel.max_size.unwrap()[0]
5476 && size[1] >= resource_panel.max_size.unwrap()[1]
5477 {
5478 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5479 } else {
5480 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5481 };
5482 }
5483 ClickAim::TopResize => {
5484 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5485 && (resource_panel.max_size.is_none()
5486 || position[1] - mouse_pos[1] + size[1]
5487 < resource_panel.max_size.unwrap()[1])
5488 {
5489 position_size_config.origin_size[1] +=
5490 position[1] - mouse_pos[1];
5491 position_size_config.origin_position[1] = mouse_pos[1];
5492 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5493 } else if resource_panel.max_size.is_some()
5494 && position[1] - mouse_pos[1] + size[1]
5495 >= resource_panel.max_size.unwrap()[1]
5496 {
5497 position_size_config.origin_position[1] -=
5498 resource_panel.max_size.unwrap()[1]
5499 - position_size_config.origin_size[1];
5500 position_size_config.origin_size[1] =
5501 resource_panel.max_size.unwrap()[1];
5502 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5503 } else {
5504 position_size_config.origin_position[1] += position_size_config
5505 .origin_size[1]
5506 - resource_panel.min_size[1];
5507 position_size_config.origin_size[1] =
5508 resource_panel.min_size[1];
5509 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5510 };
5511 }
5512 ClickAim::BottomResize => {
5513 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5514 && (resource_panel.max_size.is_none()
5515 || mouse_pos[1] - position[1]
5516 < resource_panel.max_size.unwrap()[1])
5517 {
5518 position_size_config.origin_size[1] =
5519 mouse_pos[1] - position[1];
5520 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5521 } else if resource_panel.max_size.is_some()
5522 && mouse_pos[1] - position[1]
5523 >= resource_panel.max_size.unwrap()[1]
5524 {
5525 position_size_config.origin_size[1] =
5526 resource_panel.max_size.unwrap()[1];
5527 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5528 } else {
5529 position_size_config.origin_size[1] =
5530 resource_panel.min_size[1];
5531 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5532 };
5533 }
5534 ClickAim::LeftResize => {
5535 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5536 && (resource_panel.max_size.is_none()
5537 || position[0] - mouse_pos[0] + size[0]
5538 < resource_panel.max_size.unwrap()[0])
5539 {
5540 position_size_config.origin_size[0] +=
5541 position[0] - mouse_pos[0];
5542 position_size_config.origin_position[0] = mouse_pos[0];
5543 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5544 } else if resource_panel.max_size.is_some()
5545 && position[0] - mouse_pos[0] + size[0]
5546 >= resource_panel.max_size.unwrap()[0]
5547 {
5548 position_size_config.origin_position[0] -=
5549 resource_panel.max_size.unwrap()[0]
5550 - position_size_config.origin_size[0];
5551 position_size_config.origin_size[0] =
5552 resource_panel.max_size.unwrap()[0];
5553 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5554 } else {
5555 position_size_config.origin_position[0] += position_size_config
5556 .origin_size[0]
5557 - resource_panel.min_size[0];
5558 position_size_config.origin_size[0] =
5559 resource_panel.min_size[0];
5560 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5561 };
5562 }
5563 ClickAim::RightResize => {
5564 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5565 && (resource_panel.max_size.is_none()
5566 || mouse_pos[0] - position[0]
5567 < resource_panel.max_size.unwrap()[0])
5568 {
5569 position_size_config.origin_size[0] =
5570 mouse_pos[0] - position[0];
5571 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5572 } else if resource_panel.max_size.is_some()
5573 && mouse_pos[0] - position[0]
5574 >= resource_panel.max_size.unwrap()[0]
5575 {
5576 position_size_config.origin_size[0] =
5577 resource_panel.max_size.unwrap()[0];
5578 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5579 } else {
5580 position_size_config.origin_size[0] =
5581 resource_panel.min_size[0];
5582 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5583 };
5584 }
5585 ClickAim::Move => {
5586 if resource_panel.movable[0] {
5587 position_size_config.origin_position[0] =
5588 mouse_pos[0] - offset[0];
5589 };
5590 if resource_panel.movable[1] {
5591 position_size_config.origin_position[1] =
5592 mouse_pos[1] - offset[1];
5593 };
5594 }
5595 };
5596 };
5597 [position, size] = self.position_size_processor(position_size_config, ctx);
5598 let background_type = match background.background_type.clone() {
5599 BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
5600 config.position_size_config(Some(position_size_config)),
5601 ),
5602 BackgroundType::Image(config) => BackgroundType::Image(
5603 config.position_size_config(Some(position_size_config)),
5604 ),
5605 };
5606 self.replace_resource(
5607 &format!("{name}Background"),
5608 background.clone().background_type(&background_type).clone(),
5609 )?;
5610 self.use_resource(
5611 &format!("{name}Background"),
5612 "rust_constructor::Background",
5613 ui,
5614 ctx,
5615 )?;
5616 let mut resource_point_list: Vec<([f32; 2], [f32; 2], [bool; 2])> = Vec::new();
5617 let mut use_resource_list = Vec::new();
5618 let mut replace_resource_list = Vec::new();
5619 for rcr in &self.rust_constructor_resource {
5620 if self
5621 .basic_front_resource_list
5622 .contains(&rcr.id.discern_type)
5623 && let Some(panel_name) =
5624 self.get_tag("panel_name", &rcr.content.display_tags())
5625 && panel_name.1 == name
5626 {
5627 if let [Some(citer_name), Some(citer_type)] = [
5628 self.get_tag("citer_name", &rcr.content.display_tags()),
5629 self.get_tag("citer_type", &rcr.content.display_tags()),
5630 ] {
5631 if !use_resource_list
5632 .iter()
5633 .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
5634 {
5635 use_resource_list.push([citer_name.1, citer_type.1]);
5636 };
5637 } else if !use_resource_list
5638 .iter()
5639 .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
5640 {
5641 use_resource_list
5642 .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
5643 };
5644 let mut basic_front_resource: Box<dyn BasicFrontResource> = match &*rcr
5645 .id
5646 .discern_type
5647 {
5648 "rust_constructor::Image" => Box::new(
5649 rcr.content
5650 .as_any()
5651 .downcast_ref::<Image>()
5652 .unwrap()
5653 .clone(),
5654 ),
5655 "rust_constructor::Text" => Box::new(
5656 rcr.content.as_any().downcast_ref::<Text>().unwrap().clone(),
5657 ),
5658 "rust_constructor::CustomRect" => Box::new(
5659 rcr.content
5660 .as_any()
5661 .downcast_ref::<CustomRect>()
5662 .unwrap()
5663 .clone(),
5664 ),
5665 _ => {
5666 unreachable!()
5667 }
5668 };
5669 let enable_scrolling = [
5670 self.get_tag("disable_x_scrolling", &rcr.content.display_tags())
5671 .is_none(),
5672 self.get_tag("disable_y_scrolling", &rcr.content.display_tags())
5673 .is_none(),
5674 ];
5675 let offset = basic_front_resource.display_position_size_config().offset;
5676 basic_front_resource.modify_position_size_config(
5677 basic_front_resource.display_position_size_config().offset(
5678 if enable_scrolling[0] {
5679 -resource_panel.scroll_progress[0]
5680 } else {
5681 offset[0]
5682 },
5683 if enable_scrolling[1] {
5684 -resource_panel.scroll_progress[1]
5685 } else {
5686 offset[1]
5687 },
5688 ),
5689 );
5690 let mut layout = resource_panel.overall_layout;
5691 for custom_layout in &resource_panel.custom_layout {
5692 match custom_layout {
5693 CustomPanelLayout::Id(layout_id, panel_layout) => {
5694 if rcr.id.cmp(layout_id) == Ordering::Equal {
5695 layout = *panel_layout;
5696 break;
5697 };
5698 }
5699 CustomPanelLayout::Type(layout_type, panel_layout) => {
5700 if *layout_type == rcr.id.discern_type {
5701 layout = *panel_layout;
5702 }
5703 }
5704 };
5705 }
5706 if enable_scrolling.contains(&false) {
5707 layout.panel_margin = match layout.panel_margin {
5708 PanelMargin::Horizontal([top, bottom, left, right], _) => {
5709 PanelMargin::None([top, bottom, left, right], false)
5710 }
5711 PanelMargin::Vertical([top, bottom, left, right], _) => {
5712 PanelMargin::None([top, bottom, left, right], false)
5713 }
5714 PanelMargin::None([_, _, _, _], _) => layout.panel_margin,
5715 };
5716 };
5717 match layout.panel_margin {
5718 PanelMargin::Vertical(
5719 [top, bottom, left, right],
5720 move_to_bottom,
5721 ) => {
5722 let mut modify_y = 0_f32;
5723 let [default_x_position, default_y_position] =
5724 match layout.panel_location {
5725 PanelLocation::Absolute([x, y]) => {
5726 [position[0] + x, position[1] + y]
5727 }
5728 PanelLocation::Relative([x, y]) => [
5729 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5730 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5731 ],
5732 };
5733 let default_x_position = match basic_front_resource
5734 .display_position_size_config()
5735 .display_method
5736 .0
5737 {
5738 HorizontalAlign::Left => default_x_position,
5739 HorizontalAlign::Center => {
5740 default_x_position
5741 - basic_front_resource.display_size()[0] / 2.0
5742 }
5743 HorizontalAlign::Right => {
5744 default_x_position
5745 - basic_front_resource.display_size()[0]
5746 }
5747 };
5748 let default_y_position = match basic_front_resource
5749 .display_position_size_config()
5750 .display_method
5751 .1
5752 {
5753 VerticalAlign::Top => default_y_position,
5754 VerticalAlign::Center => {
5755 default_y_position
5756 - basic_front_resource.display_size()[1] / 2.0
5757 }
5758 VerticalAlign::Bottom => {
5759 default_y_position
5760 - basic_front_resource.display_size()[1]
5761 }
5762 };
5763 for point in &resource_point_list {
5764 if default_x_position - left < point.1[0]
5765 && default_y_position - top + modify_y < point.1[1]
5766 && default_x_position
5767 + basic_front_resource.display_size()[0]
5768 + right
5769 > point.0[0]
5770 && default_y_position
5771 + basic_front_resource.display_size()[1]
5772 + bottom
5773 + modify_y
5774 > point.0[1]
5775 {
5776 if move_to_bottom
5777 && point.1[1] - default_y_position + top > modify_y
5778 {
5779 modify_y = point.1[1] - default_y_position + top;
5780 } else if !move_to_bottom
5781 && point.0[1]
5782 - default_y_position
5783 - basic_front_resource.display_size()[1]
5784 - bottom
5785 < modify_y
5786 {
5787 modify_y = point.0[1]
5788 - default_y_position
5789 - basic_front_resource.display_size()[1]
5790 - bottom;
5791 };
5792 };
5793 }
5794 let real_x_position = match basic_front_resource
5795 .display_position_size_config()
5796 .display_method
5797 .0
5798 {
5799 HorizontalAlign::Left => default_x_position,
5800 HorizontalAlign::Center => {
5801 default_x_position
5802 + basic_front_resource.display_size()[0] / 2.0
5803 }
5804 HorizontalAlign::Right => {
5805 default_x_position
5806 + basic_front_resource.display_size()[0]
5807 }
5808 };
5809 let real_y_position = match basic_front_resource
5810 .display_position_size_config()
5811 .display_method
5812 .1
5813 {
5814 VerticalAlign::Top => default_y_position + modify_y,
5815 VerticalAlign::Center => {
5816 default_y_position
5817 + modify_y
5818 + basic_front_resource.display_size()[1] / 2.0
5819 }
5820 VerticalAlign::Bottom => {
5821 default_y_position
5822 + modify_y
5823 + basic_front_resource.display_size()[1]
5824 }
5825 };
5826 basic_front_resource.modify_position_size_config(
5827 basic_front_resource
5828 .display_position_size_config()
5829 .origin_position(real_x_position, real_y_position),
5830 );
5831 replace_resource_list.push((
5832 basic_front_resource.display_position_size_config(),
5833 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
5834 ));
5835 resource_point_list.push((
5836 [real_x_position - left, real_y_position - top],
5837 [
5838 real_x_position
5839 + basic_front_resource.display_size()[0]
5840 + right,
5841 real_y_position
5842 + basic_front_resource.display_size()[1]
5843 + bottom,
5844 ],
5845 enable_scrolling,
5846 ));
5847 }
5848 PanelMargin::Horizontal(
5849 [top, bottom, left, right],
5850 move_to_right,
5851 ) => {
5852 let mut modify_x = 0_f32;
5853 let [default_x_position, default_y_position] =
5854 match layout.panel_location {
5855 PanelLocation::Absolute([x, y]) => {
5856 [position[0] + x, position[1] + y]
5857 }
5858 PanelLocation::Relative([x, y]) => [
5859 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5860 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5861 ],
5862 };
5863 let default_x_position = match basic_front_resource
5864 .display_position_size_config()
5865 .display_method
5866 .0
5867 {
5868 HorizontalAlign::Left => default_x_position,
5869 HorizontalAlign::Center => {
5870 default_x_position
5871 - basic_front_resource.display_size()[0] / 2.0
5872 }
5873 HorizontalAlign::Right => {
5874 default_x_position
5875 - basic_front_resource.display_size()[0]
5876 }
5877 };
5878 let default_y_position = match basic_front_resource
5879 .display_position_size_config()
5880 .display_method
5881 .1
5882 {
5883 VerticalAlign::Top => default_y_position,
5884 VerticalAlign::Center => {
5885 default_y_position
5886 - basic_front_resource.display_size()[1] / 2.0
5887 }
5888 VerticalAlign::Bottom => {
5889 default_y_position
5890 - basic_front_resource.display_size()[1]
5891 }
5892 };
5893 for point in &resource_point_list {
5894 if default_x_position - left + modify_x < point.1[0]
5895 && default_y_position - top < point.1[1]
5896 && default_x_position
5897 + basic_front_resource.display_size()[0]
5898 + right
5899 + modify_x
5900 > point.0[0]
5901 && default_y_position
5902 + basic_front_resource.display_size()[1]
5903 + bottom
5904 > point.0[1]
5905 {
5906 if move_to_right
5907 && point.1[0] - default_x_position + left > modify_x
5908 {
5909 modify_x = point.1[0] - default_x_position + left;
5910 } else if !move_to_right
5911 && point.0[0]
5912 - default_x_position
5913 - basic_front_resource.display_size()[0]
5914 - right
5915 < modify_x
5916 {
5917 modify_x = point.0[0]
5918 - default_x_position
5919 - basic_front_resource.display_size()[0]
5920 - right;
5921 };
5922 };
5923 }
5924 let real_x_position = match basic_front_resource
5925 .display_position_size_config()
5926 .display_method
5927 .0
5928 {
5929 HorizontalAlign::Left => default_x_position + modify_x,
5930 HorizontalAlign::Center => {
5931 default_x_position
5932 + modify_x
5933 + basic_front_resource.display_size()[0] / 2.0
5934 }
5935 HorizontalAlign::Right => {
5936 default_x_position
5937 + modify_x
5938 + basic_front_resource.display_size()[0]
5939 }
5940 };
5941 let real_y_position = match basic_front_resource
5942 .display_position_size_config()
5943 .display_method
5944 .1
5945 {
5946 VerticalAlign::Top => default_y_position,
5947 VerticalAlign::Center => {
5948 default_y_position
5949 + basic_front_resource.display_size()[1] / 2.0
5950 }
5951 VerticalAlign::Bottom => {
5952 default_y_position
5953 + basic_front_resource.display_size()[1]
5954 }
5955 };
5956 basic_front_resource.modify_position_size_config(
5957 basic_front_resource
5958 .display_position_size_config()
5959 .origin_position(real_x_position, real_y_position),
5960 );
5961 replace_resource_list.push((
5962 basic_front_resource.display_position_size_config(),
5963 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
5964 ));
5965 resource_point_list.push((
5966 [real_x_position - left, real_y_position - top],
5967 [
5968 real_x_position
5969 + basic_front_resource.display_size()[0]
5970 + right,
5971 real_y_position
5972 + basic_front_resource.display_size()[1]
5973 + bottom,
5974 ],
5975 enable_scrolling,
5976 ));
5977 }
5978 PanelMargin::None([top, bottom, left, right], influence_layout) => {
5979 let [default_x_position, default_y_position] =
5980 match layout.panel_location {
5981 PanelLocation::Absolute([x, y]) => {
5982 [position[0] + x, position[1] + y]
5983 }
5984 PanelLocation::Relative([x, y]) => [
5985 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5986 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5987 ],
5988 };
5989 basic_front_resource.modify_position_size_config(
5990 basic_front_resource
5991 .display_position_size_config()
5992 .origin_position(
5993 default_x_position,
5994 default_y_position,
5995 ),
5996 );
5997 replace_resource_list.push((
5998 basic_front_resource.display_position_size_config(),
5999 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
6000 ));
6001 if influence_layout {
6002 resource_point_list.push((
6003 [default_x_position - left, default_y_position - top],
6004 [
6005 default_x_position
6006 + basic_front_resource.display_size()[0]
6007 + right,
6008 default_y_position
6009 + basic_front_resource.display_size()[1]
6010 + bottom,
6011 ],
6012 enable_scrolling,
6013 ));
6014 };
6015 }
6016 };
6017 };
6018 }
6019 for (new_position_size_config, [name, discern_type]) in replace_resource_list {
6020 match &*discern_type {
6021 "rust_constructor::CustomRect" => {
6022 let mut custom_rect = self
6023 .get_resource::<CustomRect>(&name, &discern_type)?
6024 .clone();
6025 custom_rect.basic_front_resource_config.position_size_config =
6026 new_position_size_config;
6027 custom_rect.basic_front_resource_config.clip_rect =
6028 Some(position_size_config);
6029 self.replace_resource(&name, custom_rect)?;
6030 }
6031 "rust_constructor::Image" => {
6032 let mut image =
6033 self.get_resource::<Image>(&name, &discern_type)?.clone();
6034 image.basic_front_resource_config.position_size_config =
6035 new_position_size_config;
6036 image.basic_front_resource_config.clip_rect =
6037 Some(position_size_config);
6038 self.replace_resource(&name, image)?;
6039 }
6040 "rust_constructor::Text" => {
6041 let mut text =
6042 self.get_resource::<Text>(&name, &discern_type)?.clone();
6043 text.basic_front_resource_config.position_size_config =
6044 new_position_size_config;
6045 text.basic_front_resource_config.clip_rect =
6046 Some(position_size_config);
6047 self.replace_resource(&name, text)?;
6048 }
6049 _ => unreachable!(),
6050 }
6051 }
6052 for info in use_resource_list {
6053 self.use_resource(&info[0], &info[1], ui, ctx)?;
6054 }
6055 let mut resource_length = [None, None];
6056 for point in resource_point_list {
6057 resource_length = [
6058 if resource_length[0].is_none()
6059 || resource_length[0].is_some()
6060 && point.1[0] > resource_length[0].unwrap()
6061 && point.2[0]
6062 {
6063 Some(point.1[0])
6064 } else {
6065 resource_length[0]
6066 },
6067 if resource_length[1].is_none()
6068 || resource_length[1].is_some()
6069 && point.1[1] > resource_length[1].unwrap()
6070 && point.2[1]
6071 {
6072 Some(point.1[1])
6073 } else {
6074 resource_length[1]
6075 },
6076 ]
6077 }
6078 if let Some(horizontal_scroll_length_method) =
6079 resource_panel.scroll_length_method[0]
6080 {
6081 resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
6082 ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6083 ScrollLengthMethod::AutoFit => {
6084 if let Some(max) = resource_length[0] {
6085 let width = max - position[0];
6086 if width - size[0] > 0_f32 {
6087 width - size[0]
6088 } else {
6089 0_f32
6090 }
6091 } else {
6092 0_f32
6093 }
6094 }
6095 };
6096 resource_panel.scroll_progress[0] = if resource_panel.scroll_progress[0]
6097 > resource_panel.scroll_length[0]
6098 {
6099 resource_panel.scroll_length[0]
6100 } else {
6101 resource_panel.scroll_progress[0]
6102 };
6103 };
6104 if let Some(vertical_scroll_length_method) =
6105 resource_panel.scroll_length_method[1]
6106 {
6107 resource_panel.scroll_length[1] = match vertical_scroll_length_method {
6108 ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6109 ScrollLengthMethod::AutoFit => {
6110 if let Some(max) = resource_length[1] {
6111 let height = max - position[1];
6112 if height - size[1] > 0_f32 {
6113 height - size[1]
6114 } else {
6115 0_f32
6116 }
6117 } else {
6118 0_f32
6119 }
6120 }
6121 };
6122 resource_panel.scroll_progress[1] = if resource_panel.scroll_progress[1]
6123 > resource_panel.scroll_length[1]
6124 {
6125 resource_panel.scroll_length[1]
6126 } else {
6127 resource_panel.scroll_progress[1]
6128 };
6129 };
6130 match resource_panel.scroll_bar_display_method {
6131 ScrollBarDisplayMethod::Always(ref config, margin, width) => {
6132 let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6133 (size[0] - margin[0] * 2_f32)
6134 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6135 } else {
6136 (size[0] - width - margin[1] - margin[0] * 2_f32)
6137 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6138 };
6139 let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6140 position[0]
6141 + margin[0]
6142 + (size[0] - margin[0] * 2_f32 - line_length)
6143 * (resource_panel.scroll_progress[0]
6144 / resource_panel.scroll_length[0])
6145 } else {
6146 position[0]
6147 + margin[0]
6148 + (size[0]
6149 - margin[0] * 2_f32
6150 - width
6151 - margin[1]
6152 - line_length)
6153 * (resource_panel.scroll_progress[0]
6154 / resource_panel.scroll_length[0])
6155 };
6156 self.replace_resource(
6157 &format!("{name}XScroll"),
6158 background.clone().background_type(&match config.clone() {
6159 BackgroundType::CustomRect(config) => {
6160 BackgroundType::CustomRect(
6161 config.position_size_config(Some(
6162 PositionSizeConfig::default()
6163 .display_method(
6164 HorizontalAlign::Left,
6165 VerticalAlign::Bottom,
6166 )
6167 .origin_position(
6168 line_position,
6169 position[1] + size[1] - margin[1],
6170 )
6171 .origin_size(line_length, width),
6172 )),
6173 )
6174 }
6175 BackgroundType::Image(config) => BackgroundType::Image(
6176 config.position_size_config(Some(
6177 PositionSizeConfig::default()
6178 .display_method(
6179 HorizontalAlign::Left,
6180 VerticalAlign::Bottom,
6181 )
6182 .origin_position(
6183 line_position,
6184 position[1] + size[1] - margin[1],
6185 )
6186 .origin_size(line_length, width),
6187 )),
6188 ),
6189 }),
6190 )?;
6191 self.use_resource(
6192 &format!("{name}XScroll"),
6193 "rust_constructor::Background",
6194 ui,
6195 ctx,
6196 )?;
6197 let line_length = if resource_panel.scroll_length[0] == 0_f32 {
6198 (size[1] - margin[0] * 2_f32)
6199 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6200 } else {
6201 (size[1] - width - margin[1] - margin[0] * 2_f32)
6202 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6203 };
6204 let line_position = if resource_panel.scroll_length[0] == 0_f32 {
6205 position[1]
6206 + margin[0]
6207 + (size[1] - margin[0] * 2_f32 - line_length)
6208 * (resource_panel.scroll_progress[1]
6209 / resource_panel.scroll_length[1])
6210 } else {
6211 position[1]
6212 + margin[0]
6213 + (size[1]
6214 - margin[0] * 2_f32
6215 - width
6216 - margin[1]
6217 - line_length)
6218 * (resource_panel.scroll_progress[1]
6219 / resource_panel.scroll_length[1])
6220 };
6221 self.replace_resource(
6222 &format!("{name}YScroll"),
6223 background.background_type(&match config.clone() {
6224 BackgroundType::CustomRect(config) => {
6225 BackgroundType::CustomRect(
6226 config.position_size_config(Some(
6227 PositionSizeConfig::default()
6228 .display_method(
6229 HorizontalAlign::Right,
6230 VerticalAlign::Top,
6231 )
6232 .origin_position(
6233 position[0] + size[0] - margin[1],
6234 line_position,
6235 )
6236 .origin_size(width, line_length),
6237 )),
6238 )
6239 }
6240 BackgroundType::Image(config) => BackgroundType::Image(
6241 config.position_size_config(Some(
6242 PositionSizeConfig::default()
6243 .display_method(
6244 HorizontalAlign::Right,
6245 VerticalAlign::Top,
6246 )
6247 .origin_position(
6248 position[0] + size[0] - margin[1],
6249 line_position,
6250 )
6251 .origin_size(width, line_length),
6252 )),
6253 ),
6254 }),
6255 )?;
6256 self.use_resource(
6257 &format!("{name}YScroll"),
6258 "rust_constructor::Background",
6259 ui,
6260 ctx,
6261 )?;
6262 }
6263 ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
6264 resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
6265 self.reset_split_time(&format!("{name}ScrollBarXAlphaStart",))?;
6266 255
6267 } else if self.timer.now_time
6268 - self.get_split_time(&format!("{name}ScrollBarXAlphaStart",))?[0]
6269 >= 1_f32
6270 && self.timer.now_time
6271 - self.get_split_time(&format!("{name}ScrollBarXAlpha",))?[0]
6272 >= self.tick_interval
6273 {
6274 self.reset_split_time(&format!("{name}ScrollBarXAlpha",))?;
6275 resource_panel.scroll_bar_alpha[0].saturating_sub(10)
6276 } else {
6277 resource_panel.scroll_bar_alpha[0]
6278 };
6279 resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
6280 self.reset_split_time(&format!("{name}ScrollBarYAlphaStart",))?;
6281 255
6282 } else if self.timer.now_time
6283 - self.get_split_time(&format!("{name}ScrollBarYAlphaStart",))?[0]
6284 >= 1_f32
6285 && self.timer.now_time
6286 - self.get_split_time(&format!("{name}ScrollBarYAlpha",))?[0]
6287 >= self.tick_interval
6288 {
6289 self.reset_split_time(&format!("{name}ScrollBarYAlpha",))?;
6290 resource_panel.scroll_bar_alpha[1].saturating_sub(10)
6291 } else {
6292 resource_panel.scroll_bar_alpha[1]
6293 };
6294 let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6295 (size[0] - margin[0] * 2_f32)
6296 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6297 } else {
6298 (size[0] - width - margin[1] - margin[0] * 2_f32)
6299 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6300 };
6301 let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6302 position[0]
6303 + margin[0]
6304 + (size[0] - margin[0] * 2_f32 - line_length)
6305 * (resource_panel.scroll_progress[0]
6306 / resource_panel.scroll_length[0])
6307 } else {
6308 position[0]
6309 + margin[0]
6310 + (size[0]
6311 - margin[0] * 2_f32
6312 - width
6313 - margin[1]
6314 - line_length)
6315 * (resource_panel.scroll_progress[0]
6316 / resource_panel.scroll_length[0])
6317 };
6318 self.replace_resource(
6319 &format!("{name}XScroll"),
6320 background.clone().background_type(&match config.clone() {
6321 BackgroundType::CustomRect(config) => {
6322 BackgroundType::CustomRect(
6323 config
6324 .position_size_config(Some(
6325 PositionSizeConfig::default()
6326 .display_method(
6327 HorizontalAlign::Left,
6328 VerticalAlign::Bottom,
6329 )
6330 .origin_position(
6331 line_position,
6332 position[1] + size[1] - margin[1],
6333 )
6334 .origin_size(line_length, width),
6335 ))
6336 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6337 .border_alpha(Some(
6338 resource_panel.scroll_bar_alpha[0],
6339 )),
6340 )
6341 }
6342 BackgroundType::Image(config) => BackgroundType::Image(
6343 config
6344 .position_size_config(Some(
6345 PositionSizeConfig::default()
6346 .display_method(
6347 HorizontalAlign::Left,
6348 VerticalAlign::Bottom,
6349 )
6350 .origin_position(
6351 line_position,
6352 position[1] + size[1] - margin[1],
6353 )
6354 .origin_size(line_length, width),
6355 ))
6356 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6357 .background_alpha(Some(
6358 resource_panel.scroll_bar_alpha[0],
6359 ))
6360 .overlay_alpha(Some(
6361 resource_panel.scroll_bar_alpha[0],
6362 )),
6363 ),
6364 }),
6365 )?;
6366 self.use_resource(
6367 &format!("{name}XScroll"),
6368 "rust_constructor::Background",
6369 ui,
6370 ctx,
6371 )?;
6372 let line_length = if resource_panel.scroll_length[0] == 0_f32 {
6373 (size[1] - margin[0] * 2_f32)
6374 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6375 } else {
6376 (size[1] - width - margin[1] - margin[0] * 2_f32)
6377 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6378 };
6379 let line_position = if resource_panel.scroll_length[0] == 0_f32 {
6380 position[1]
6381 + margin[0]
6382 + (size[1] - margin[0] * 2_f32 - line_length)
6383 * (resource_panel.scroll_progress[1]
6384 / resource_panel.scroll_length[1])
6385 } else {
6386 position[1]
6387 + margin[0]
6388 + (size[1]
6389 - margin[0] * 2_f32
6390 - width
6391 - margin[1]
6392 - line_length)
6393 * (resource_panel.scroll_progress[1]
6394 / resource_panel.scroll_length[1])
6395 };
6396 self.replace_resource(
6397 &format!("{name}YScroll"),
6398 background.clone().background_type(&match config.clone() {
6399 BackgroundType::CustomRect(config) => {
6400 BackgroundType::CustomRect(
6401 config
6402 .position_size_config(Some(
6403 PositionSizeConfig::default()
6404 .display_method(
6405 HorizontalAlign::Right,
6406 VerticalAlign::Top,
6407 )
6408 .origin_position(
6409 position[0] + size[0] - margin[1],
6410 line_position,
6411 )
6412 .origin_size(width, line_length),
6413 ))
6414 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6415 .border_alpha(Some(
6416 resource_panel.scroll_bar_alpha[0],
6417 )),
6418 )
6419 }
6420 BackgroundType::Image(config) => BackgroundType::Image(
6421 config
6422 .position_size_config(Some(
6423 PositionSizeConfig::default()
6424 .display_method(
6425 HorizontalAlign::Right,
6426 VerticalAlign::Top,
6427 )
6428 .origin_position(
6429 position[0] + size[0] - margin[1],
6430 line_position,
6431 )
6432 .origin_size(width, line_length),
6433 ))
6434 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6435 .background_alpha(Some(
6436 resource_panel.scroll_bar_alpha[0],
6437 ))
6438 .overlay_alpha(Some(
6439 resource_panel.scroll_bar_alpha[0],
6440 )),
6441 ),
6442 }),
6443 )?;
6444 self.use_resource(
6445 &format!("{name}YScroll"),
6446 "rust_constructor::Background",
6447 ui,
6448 ctx,
6449 )?;
6450 }
6451 ScrollBarDisplayMethod::Hidden => {}
6452 };
6453 self.replace_resource(name, resource_panel.clone())?;
6454 }
6455 _ => {}
6456 };
6457 Ok(())
6458 } else {
6459 Err(RustConstructorError {
6460 error_id: "ResourceNotFound".to_string(),
6461 description: format!("Resource \"{name}({discern_type})\" not found."),
6462 })
6463 }
6464 }
6465
6466 pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
6468 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6469 page_data.enter_page_updated = false;
6470 self.timer.start_time = self.timer.total_time;
6471 self.current_page = name.to_string();
6472 self.update_timer();
6473 Ok(())
6474 }
6475
6476 pub fn get_font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
6478 let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
6479 Ok(font.font_definitions.clone())
6480 }
6481
6482 pub fn register_all_fonts(&mut self, ctx: &Context) {
6484 let mut font_definitions_amount = FontDefinitions::default();
6485 let mut fonts = Vec::new();
6486 for i in 0..self.rust_constructor_resource.len() {
6487 if let Some(font) = self.rust_constructor_resource[i]
6488 .content
6489 .as_any()
6490 .downcast_ref::<Font>()
6491 {
6492 fonts.push((
6493 self.rust_constructor_resource[i].id.name.clone(),
6494 font.font_definitions.clone(),
6495 ));
6496 };
6497 }
6498 for i in &fonts {
6499 if let Some(font_data) = i.1.font_data.get(&i.0) {
6501 font_definitions_amount
6502 .font_data
6503 .insert(i.0.clone(), Arc::clone(font_data));
6504 font_definitions_amount
6505 .families
6506 .entry(FontFamily::Name(i.0.clone().into()))
6507 .or_default()
6508 .push(i.0.clone());
6509 };
6510
6511 font_definitions_amount
6513 .families
6514 .entry(FontFamily::Proportional)
6515 .or_default()
6516 .insert(0, i.0.to_owned());
6517
6518 font_definitions_amount
6519 .families
6520 .entry(FontFamily::Monospace)
6521 .or_default()
6522 .insert(0, i.0.to_owned());
6523 }
6524 ctx.set_fonts(font_definitions_amount);
6525 }
6526
6527 pub fn position_size_processor(
6529 &self,
6530 position_size_config: PositionSizeConfig,
6531 ctx: &Context,
6532 ) -> [[f32; 2]; 2] {
6533 let mut position = [0_f32, 0_f32];
6534 let mut size = [0_f32, 0_f32];
6535 size[0] = match position_size_config.x_size_grid[0] {
6536 0_f32 => position_size_config.origin_size[0],
6537 _ => {
6538 (ctx.available_rect().width() / position_size_config.x_size_grid[1]
6539 * position_size_config.x_size_grid[0])
6540 + position_size_config.origin_size[0]
6541 }
6542 };
6543 size[1] = match position_size_config.y_size_grid[0] {
6544 0_f32 => position_size_config.origin_size[1],
6545 _ => {
6546 (ctx.available_rect().height() / position_size_config.y_size_grid[1]
6547 * position_size_config.y_size_grid[0])
6548 + position_size_config.origin_size[1]
6549 }
6550 };
6551 position[0] = match position_size_config.x_location_grid[1] {
6552 0_f32 => position_size_config.origin_position[0],
6553 _ => {
6554 (ctx.available_rect().width() / position_size_config.x_location_grid[1]
6555 * position_size_config.x_location_grid[0])
6556 + position_size_config.origin_position[0]
6557 }
6558 };
6559 position[1] = match position_size_config.y_location_grid[1] {
6560 0_f32 => position_size_config.origin_position[1],
6561 _ => {
6562 (ctx.available_rect().height() / position_size_config.y_location_grid[1]
6563 * position_size_config.y_location_grid[0])
6564 + position_size_config.origin_position[1]
6565 }
6566 };
6567 match position_size_config.display_method.0 {
6568 HorizontalAlign::Left => {}
6569 HorizontalAlign::Center => position[0] -= size[0] / 2.0,
6570 HorizontalAlign::Right => position[0] -= size[0],
6571 };
6572 match position_size_config.display_method.1 {
6573 VerticalAlign::Top => {}
6574 VerticalAlign::Center => position[1] -= size[1] / 2.0,
6575 VerticalAlign::Bottom => position[1] -= size[1],
6576 };
6577 position[0] += position_size_config.offset[0];
6578 position[1] += position_size_config.offset[1];
6579 [position, size]
6580 }
6581
6582 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
6584 let page_data = self
6585 .get_resource::<PageData>(name, "rust_constructor::PageData")?
6586 .clone();
6587 if !page_data.change_page_updated {
6588 self.new_page_update(name)?;
6589 };
6590 Ok(page_data.change_page_updated)
6591 }
6592
6593 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
6595 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6596 page_data.enter_page_updated = true;
6597 Ok(page_data.enter_page_updated)
6598 }
6599
6600 pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
6602 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6603 page_data.change_page_updated = true;
6604 self.timer.start_time = self.timer.total_time;
6605 self.update_timer();
6606 Ok(())
6607 }
6608
6609 pub fn update_frame_stats(&mut self) {
6611 let current_time = self.timer.total_time;
6612 if let Some(last) = self.last_frame_time {
6613 let delta = current_time - last;
6614 self.frame_times.push(delta);
6615 const MAX_SAMPLES: usize = 120;
6616 if self.frame_times.len() > MAX_SAMPLES {
6617 let remove_count = self.frame_times.len() - MAX_SAMPLES;
6618 self.frame_times.drain(0..remove_count);
6619 }
6620 }
6621 self.last_frame_time = Some(current_time);
6622 }
6623
6624 pub fn current_fps(&self) -> f32 {
6626 if self.frame_times.is_empty() {
6627 0.0
6628 } else {
6629 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
6630 }
6631 }
6632
6633 pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
6635 let new_time = [self.timer.now_time, self.timer.total_time];
6636 let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
6637 split_time.time = new_time;
6638 Ok(())
6639 }
6640
6641 pub fn get_split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
6643 let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
6644 Ok(split_time.time)
6645 }
6646
6647 pub fn update_timer(&mut self) {
6649 let elapsed = self.timer.timer.elapsed();
6650 let seconds = elapsed.as_secs();
6651 let milliseconds = elapsed.subsec_millis();
6652 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
6653 self.timer.now_time = self.timer.total_time - self.timer.start_time
6654 }
6655
6656 pub fn modify_variable<T: Debug + 'static>(
6658 &mut self,
6659 name: &str,
6660 value: Option<T>,
6661 ) -> Result<(), RustConstructorError> {
6662 let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
6663 variable.value = value;
6664 Ok(())
6665 }
6666
6667 pub fn get_variable<T: Debug + Clone + 'static>(
6669 &mut self,
6670 name: &str,
6671 ) -> Result<Option<T>, RustConstructorError> {
6672 if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
6673 Ok(variable.value.clone())
6674 } else if self
6675 .check_resource_exists(name, "rust_constructor::Variable")
6676 .is_none()
6677 {
6678 Err(RustConstructorError {
6679 error_id: "ResourceNotFound".to_string(),
6680 description: format!(
6681 "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
6682 ),
6683 })
6684 } else {
6685 Err(RustConstructorError {
6686 error_id: "ResourceGenericMismatch".to_string(),
6687 description: format!(
6688 "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
6689 ),
6690 })
6691 }
6692 }
6693
6694 pub fn get_image_texture(
6696 &mut self,
6697 name: &str,
6698 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
6699 let image_texture =
6700 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
6701 Ok(image_texture.texture.clone())
6702 }
6703
6704 pub fn reset_image_texture(
6706 &mut self,
6707 name: &str,
6708 path: &str,
6709 flip: [bool; 2],
6710 ctx: &Context,
6711 ) -> Result<(), RustConstructorError> {
6712 let image_texture =
6713 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
6714 if let Ok(mut file) = File::open(path) {
6715 let mut buffer = Vec::new();
6716 file.read_to_end(&mut buffer).unwrap();
6717 let img_bytes = buffer;
6718 let img = image::load_from_memory(&img_bytes).unwrap();
6719 let color_data = match flip {
6720 [true, true] => img.fliph().flipv().into_rgba8(),
6721 [true, false] => img.fliph().into_rgba8(),
6722 [false, true] => img.flipv().into_rgba8(),
6723 _ => img.into_rgba8(),
6724 };
6725 let (w, h) = (color_data.width(), color_data.height());
6726 let raw_data: Vec<u8> = color_data.into_raw();
6727
6728 let color_image =
6729 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
6730 let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
6731 image_texture.texture = Some(DebugTextureHandle::new(&texture));
6732 image_texture.cite_path = path.to_string();
6733 } else {
6734 return Err(RustConstructorError {
6735 error_id: "ImageLoadFailed".to_string(),
6736 description: format!(
6737 "Failed to load an image from the path \"{}\".",
6738 image_texture.cite_path
6739 ),
6740 });
6741 }
6742 Ok(())
6743 }
6744
6745 pub fn set_switch_enable(
6747 &mut self,
6748 name: &str,
6749 enable: bool,
6750 ) -> Result<(), RustConstructorError> {
6751 let switch = self.get_resource_mut::<Switch>(name, "rust_constructor::Switch")?;
6752 switch.enable = enable;
6753 Ok(())
6754 }
6755
6756 pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
6758 let switch = self.get_resource::<Switch>(name, "rust_constructor::Switch")?;
6759 Ok(SwitchData {
6760 switched: switch.switched,
6761 last_frame_clicked: switch.last_frame_clicked,
6762 state: switch.state,
6763 })
6764 }
6765}