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.truncate_size] = self.position_size_processor(
2713 text.basic_front_resource_config.position_size_config,
2714 ctx,
2715 );
2716 let display_content = if text.content.is_empty() {
2717 "".to_string()
2718 } else {
2719 let original_galley = ui.fonts_mut(|f| {
2720 f.layout(
2721 text.content.to_string(),
2722 FontId::proportional(text.font_size),
2723 Color32::default(),
2724 text.truncate_size[0],
2725 )
2726 });
2727
2728 let mut truncated = text.content.to_string();
2729 let mut ellipsis = "";
2730 if original_galley.size().y > text.truncate_size[1] {
2731 ellipsis = "...";
2733
2734 while !truncated.is_empty() {
2735 let test_text = format!("{}{}", truncated, ellipsis);
2736 let test_galley = ui.fonts_mut(|f| {
2737 f.layout(
2738 test_text,
2739 FontId::proportional(text.font_size),
2740 Color32::default(),
2741 text.truncate_size[0],
2742 )
2743 });
2744
2745 if test_galley.size().y <= text.truncate_size[1] {
2746 break;
2747 }
2748
2749 truncated.pop();
2751 }
2752 };
2753 format!("{}{}", truncated, ellipsis)
2754 };
2755 let galley: Arc<Galley> = ui.fonts_mut(|f| {
2757 f.layout(
2758 display_content.to_string(),
2759 if !text.font.is_empty() {
2760 if self
2761 .check_resource_exists(&text.font, "rust_constructor::Font")
2762 .is_none()
2763 {
2764 FontId::proportional(text.font_size)
2765 } else {
2766 FontId::new(
2767 text.font_size,
2768 FontFamily::Name(text.font.clone().into()),
2769 )
2770 }
2771 } else {
2772 FontId::proportional(text.font_size)
2773 },
2774 Color32::from_rgba_unmultiplied(
2775 text.color[0],
2776 text.color[1],
2777 text.color[2],
2778 text.alpha,
2779 ),
2780 text.truncate_size[0],
2781 )
2782 });
2783 text.size = [
2784 if text.auto_fit[0] {
2785 galley.size().x
2786 } else {
2787 text.truncate_size[0]
2788 },
2789 if text.auto_fit[1] {
2790 galley.size().y
2791 } else {
2792 text.truncate_size[1]
2793 },
2794 ];
2795 text.actual_size = [galley.size().x, galley.size().y];
2796 [text.position, _] = self.position_size_processor(
2797 text.basic_front_resource_config
2798 .position_size_config
2799 .x_size_grid(0_f32, 0_f32)
2800 .y_size_grid(0_f32, 0_f32)
2801 .origin_size(text.size[0], text.size[1]),
2802 ctx,
2803 );
2804 if text.last_frame_content != display_content {
2806 text.hyperlink_index.clear();
2807
2808 let byte_to_char_map: std::collections::HashMap<usize, usize> =
2810 display_content
2811 .char_indices()
2812 .enumerate()
2813 .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2814 .collect();
2815
2816 for (hyperlink_text, method) in &text.hyperlink_text {
2817 let matches: Vec<(usize, &str)> =
2818 display_content.match_indices(hyperlink_text).collect();
2819 let text_char_count = hyperlink_text.chars().count();
2820
2821 if let HyperlinkSelectMethod::All(url) = method {
2822 for (byte_index, _) in matches {
2823 if let Some(&start_char_index) =
2824 byte_to_char_map.get(&byte_index)
2825 {
2826 text.hyperlink_index.push((
2827 start_char_index,
2828 start_char_index + text_char_count,
2829 url.clone(),
2830 ));
2831 };
2832 }
2833 } else if let HyperlinkSelectMethod::Segment(list) = method {
2834 for (index, url) in list {
2835 if *index >= matches.len() {
2836 continue;
2837 };
2838 let (byte_index, _) = matches[*index];
2839 if let Some(&start_char_index) =
2840 byte_to_char_map.get(&byte_index)
2841 {
2842 text.hyperlink_index.push((
2843 start_char_index,
2844 start_char_index + text_char_count,
2845 url.clone(),
2846 ));
2847 };
2848 }
2849 };
2850 }
2851 };
2852 if !text.display_info.hidden {
2853 let rect =
2855 Rect::from_min_size(text.position.into(), text.actual_size.into());
2856 ui.painter().rect_filled(
2858 rect,
2859 text.background_rounding,
2860 Color32::from_rgba_unmultiplied(
2861 text.background_color[0],
2862 text.background_color[1],
2863 text.background_color[2],
2864 text.background_alpha,
2865 ),
2866 );
2867
2868 if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2869 let [min, size] = self.position_size_processor(clip_rect, ctx);
2870 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2871 };
2872
2873 ui.painter().galley(
2875 text.position.into(),
2876 galley.clone(),
2877 Color32::from_rgba_unmultiplied(
2878 text.color[0],
2879 text.color[1],
2880 text.color[2],
2881 text.alpha,
2882 ),
2883 );
2884
2885 for (start, end, _) in &text.hyperlink_index {
2887 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2889 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2890
2891 let start_pos = start_cursor.left_top();
2892 let end_pos = end_cursor.right_top();
2893 if start_cursor.min.y == end_cursor.min.y {
2896 let underline_y = text.position[1]
2898 + start_pos.y
2899 + galley.rows.first().map_or(14.0, |row| row.height())
2900 - 2.0;
2901
2902 let color = Color32::from_rgba_unmultiplied(
2904 text.color[0],
2905 text.color[1],
2906 text.color[2],
2907 text.alpha,
2908 );
2909
2910 ui.painter().line_segment(
2911 [
2912 Pos2::new(text.position[0] + start_pos.x, underline_y),
2913 Pos2::new(text.position[0] + end_pos.x, underline_y),
2914 ],
2915 Stroke::new(text.font_size / 10_f32, color),
2916 );
2917 } else {
2918 let row_height =
2920 galley.rows.first().map_or(14.0, |row| row.height()); let start_row = (start_pos.y / row_height).round() as usize;
2924 let end_row = (end_pos.y / row_height).round() as usize;
2925
2926 for row in start_row..=end_row {
2927 let row_y =
2928 text.position[1] + row as f32 * row_height + row_height
2929 - 2.0; if let Some(current_row) = galley.rows.get(row) {
2933 let row_rect = current_row.rect();
2934
2935 let color = Color32::from_rgba_unmultiplied(
2936 text.color[0],
2937 text.color[1],
2938 text.color[2],
2939 text.alpha,
2940 );
2941
2942 if row == start_row {
2943 ui.painter().line_segment(
2945 [
2946 Pos2::new(
2947 text.position[0] + start_pos.x,
2948 row_y,
2949 ),
2950 Pos2::new(
2951 text.position[0] + row_rect.max.x,
2952 row_y,
2953 ),
2954 ],
2955 Stroke::new(text.font_size / 10_f32, color),
2956 );
2957 } else if row == end_row {
2958 ui.painter().line_segment(
2960 [
2961 Pos2::new(
2962 text.position[0] + row_rect.min.x,
2963 row_y,
2964 ),
2965 Pos2::new(
2966 text.position[0] + end_pos.x,
2967 row_y,
2968 ),
2969 ],
2970 Stroke::new(text.font_size / 10_f32, color),
2971 );
2972 } else {
2973 ui.painter().line_segment(
2975 [
2976 Pos2::new(
2977 text.position[0] + row_rect.min.x,
2978 row_y,
2979 ),
2980 Pos2::new(
2981 text.position[0] + row_rect.max.x,
2982 row_y,
2983 ),
2984 ],
2985 Stroke::new(text.font_size / 10_f32, color),
2986 );
2987 };
2988 };
2989 }
2990 };
2991 }
2992
2993 if text.selectable {
2994 let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2996 let relative_pos = pointer_pos - text.position.into();
2997 let cursor = galley.cursor_from_pos(relative_pos);
2998 cursor.index
2999 };
3000
3001 let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
3002 let rect = Rect::from_min_size(
3003 text.position.into(),
3004 text.actual_size.into(),
3005 );
3006 let detect_result = ui.interact(
3007 rect,
3008 Id::new(&render_resource.name),
3009 Sense::click_and_drag(),
3010 );
3011
3012 if !detect_result.clicked()
3013 && (fullscreen_detect_result.any_click()
3014 || fullscreen_detect_result.any_pressed())
3015 {
3016 text.selection = None;
3017 };
3018
3019 if let Some(index) = self.get_render_layer_resource(
3020 &render_resource.name,
3021 "rust_constructor::Text",
3022 ) && let Some(mouse_pos) =
3023 fullscreen_detect_result.interact_pos()
3024 && self.resource_get_focus(index, mouse_pos.into())
3025 && (detect_result.clicked() || detect_result.drag_started())
3026 {
3027 let cursor = cursor_at_pointer(mouse_pos.to_vec2());
3028 text.selection = Some((cursor, cursor));
3029 };
3030
3031 if detect_result.dragged()
3032 && text.selection.is_some()
3033 && let Some(pointer_pos) =
3034 ui.input(|i| i.pointer.interact_pos())
3035 {
3036 let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3037 if let Some((start, _)) = text.selection {
3038 text.selection = Some((start, cursor));
3039 };
3040 };
3041
3042 if text.selection.is_some()
3043 && ui.input(|input| {
3044 input.key_released(Key::A) && input.modifiers.command
3045 })
3046 {
3047 text.selection = Some((0, display_content.chars().count()));
3048 };
3049
3050 let copy_triggered = ui.input(|input| {
3052 let c_released = input.key_released(Key::C);
3053 let cmd_pressed = input.modifiers.command;
3054 c_released && cmd_pressed
3055 });
3056 if copy_triggered && let Some((start, end)) = text.selection {
3057 let (start, end) = (start.min(end), start.max(end));
3058 let chars: Vec<char> = display_content.chars().collect();
3059 if start <= chars.len() && end <= chars.len() && start < end {
3060 let selected_text: String =
3061 chars[start..end].iter().collect();
3062 ui.ctx().copy_text(selected_text);
3063 };
3064 };
3065
3066 if let Some((start, end)) = text.selection {
3068 let (start, end) = (start.min(end), start.max(end));
3069 if start != end {
3070 let start_cursor =
3072 galley.pos_from_cursor(CCursor::new(start));
3073 let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3074
3075 let start_pos = start_cursor.left_top();
3076 let end_pos = end_cursor.right_top();
3077 if start_pos.y == end_pos.y {
3079 let rows = &galley.rows;
3081 let row_height = if !rows.is_empty() {
3082 if let Some(row) = rows.first() {
3084 row.height()
3085 } else {
3086 text.actual_size[1]
3087 / display_content.lines().count() as f32
3088 }
3089 } else {
3090 text.actual_size[1]
3091 / display_content.lines().count() as f32
3092 };
3093
3094 let selection_rect = Rect::from_min_max(
3095 Pos2::new(
3096 text.position[0] + start_pos.x,
3097 text.position[1] + start_pos.y,
3098 ),
3099 Pos2::new(
3100 text.position[0] + end_pos.x,
3101 text.position[1] + start_pos.y + row_height,
3102 ),
3103 );
3104 ui.painter().rect_filled(
3105 selection_rect,
3106 0.0,
3107 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3108 );
3109 } else {
3110 let rows = &galley.rows;
3112 let row_height = if !rows.is_empty() {
3113 rows[0].height()
3114 } else {
3115 text.actual_size[1]
3116 / display_content.lines().count() as f32
3117 };
3118
3119 let selection_top =
3121 text.position[1] + start_pos.y.min(end_pos.y);
3122 let selection_bottom =
3123 text.position[1] + start_pos.y.max(end_pos.y);
3124
3125 let start_row_index =
3127 (start_pos.y / row_height).floor() as usize;
3128 let end_row_index =
3129 (end_pos.y / row_height).floor() as usize;
3130 let (first_row_index, last_row_index) =
3131 if start_row_index <= end_row_index {
3132 (start_row_index, end_row_index)
3133 } else {
3134 (end_row_index, start_row_index)
3135 };
3136
3137 for (i, row) in rows.iter().enumerate() {
3138 let row_y =
3139 text.position[1] + row_height * i as f32;
3140 let row_bottom = row_y + row_height;
3141 if row_bottom > selection_top
3143 && row_y <= selection_bottom
3144 {
3145 let left = if i == first_row_index {
3146 text.position[0] + start_pos.x
3148 } else {
3149 text.position[0] + row.rect().min.x
3151 };
3152
3153 let right = if i == last_row_index {
3154 text.position[0] + end_pos.x
3156 } else {
3157 text.position[0] + row.rect().max.x
3159 };
3160
3161 let selection_rect = Rect::from_min_max(
3162 Pos2::new(left, row_y),
3163 Pos2::new(right, row_bottom),
3164 );
3165
3166 if selection_rect.width() > 0.0
3168 && selection_rect.height() > 0.0
3169 {
3170 ui.painter().rect_filled(
3171 selection_rect,
3172 0.0,
3173 Color32::from_rgba_unmultiplied(
3174 0, 120, 255, 100,
3175 ),
3176 );
3177 };
3178 };
3179 }
3180 };
3181 };
3182 };
3183 };
3184
3185 for (start, end, url) in &text.hyperlink_index {
3187 let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3189 let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3190
3191 let start_pos = start_cursor.left_top();
3192 let end_pos = end_cursor.right_top();
3193
3194 let row_height =
3195 galley.rows.first().map_or(14.0, |row| row.height());
3196
3197 let link_responses = if start_cursor.min.y == end_cursor.min.y {
3199 let link_rect = Rect::from_min_max(
3201 Pos2::new(
3202 text.position[0] + start_pos.x,
3203 text.position[1] + start_pos.y,
3204 ),
3205 Pos2::new(
3206 text.position[0] + end_pos.x,
3207 text.position[1] + start_pos.y + row_height,
3208 ),
3209 );
3210 vec![ui.interact(
3211 link_rect,
3212 egui::Id::new(format!(
3213 "link_{}_{}_{}",
3214 render_resource.name, start, end
3215 )),
3216 egui::Sense::click(),
3217 )]
3218 } else {
3219 let start_row = (start_pos.y / row_height).round() as usize;
3221 let end_row = (end_pos.y / row_height).round() as usize;
3222 let mut responses = Vec::new();
3223
3224 for row in start_row..=end_row {
3225 if let Some(current_row) = galley.rows.get(row) {
3226 let row_rect = current_row.rect();
3227 let row_y = text.position[1] + row as f32 * row_height;
3228
3229 let link_rect = if row == start_row {
3230 Rect::from_min_max(
3232 Pos2::new(
3233 text.position[0] + start_pos.x,
3234 row_y,
3235 ),
3236 Pos2::new(
3237 text.position[0] + row_rect.max.x,
3238 row_y + row_height,
3239 ),
3240 )
3241 } else if row == end_row {
3242 Rect::from_min_max(
3244 Pos2::new(
3245 text.position[0] + row_rect.min.x,
3246 row_y,
3247 ),
3248 Pos2::new(
3249 text.position[0] + end_pos.x,
3250 row_y + row_height,
3251 ),
3252 )
3253 } else {
3254 Rect::from_min_max(
3256 Pos2::new(
3257 text.position[0] + row_rect.min.x,
3258 row_y,
3259 ),
3260 Pos2::new(
3261 text.position[0] + row_rect.max.x,
3262 row_y + row_height,
3263 ),
3264 )
3265 };
3266
3267 responses.push(ui.interact(
3268 link_rect,
3269 Id::new(format!(
3270 "link_{}_{}_{}_row_{}",
3271 render_resource.name, start, end, row
3272 )),
3273 Sense::click(),
3274 ));
3275 };
3276 }
3277 responses
3278 };
3279
3280 let mut is_pressing_link = false;
3282 for link_response in &link_responses {
3283 if let Some(index) = self.get_render_layer_resource(
3284 &render_resource.name,
3285 "rust_constructor::Text",
3286 ) && let Some(mouse_pos) =
3287 ui.input(|i| i.pointer.interact_pos())
3288 && self.resource_get_focus(index, mouse_pos.into())
3289 {
3290 if link_response.is_pointer_button_down_on()
3291 && !link_response.drag_started()
3292 {
3293 text.selection = None;
3294 if let Some(pointer_pos) =
3295 ui.input(|i| i.pointer.interact_pos())
3296 {
3297 let relative_pos = pointer_pos
3298 - <[f32; 2] as Into<Pos2>>::into(text.position);
3299 let cursor = galley.cursor_from_pos(relative_pos);
3300 if cursor.index >= *start && cursor.index <= *end {
3301 is_pressing_link = true;
3302 break;
3303 };
3304 };
3305 };
3306 let mut clicked_on_link = false;
3308 for link_response in &link_responses {
3309 if link_response.clicked()
3310 && let Some(pointer_pos) =
3311 ui.input(|i| i.pointer.interact_pos())
3312 {
3313 let relative_pos = pointer_pos
3314 - <[f32; 2] as Into<Pos2>>::into(text.position);
3315 let cursor = galley.cursor_from_pos(relative_pos);
3316 if cursor.index >= *start && cursor.index <= *end {
3317 clicked_on_link = true;
3318 break;
3319 };
3320 };
3321 }
3322
3323 if clicked_on_link {
3324 if !url.is_empty() {
3326 ui.ctx().open_url(OpenUrl::new_tab(url));
3327 };
3328 };
3329 };
3330 }
3331
3332 if is_pressing_link {
3334 if start_cursor.min.y == end_cursor.min.y {
3335 let selection_rect = Rect::from_min_max(
3337 Pos2::new(
3338 text.position[0] + start_pos.x,
3339 text.position[1] + start_pos.y,
3340 ),
3341 Pos2::new(
3342 text.position[0] + end_pos.x,
3343 text.position[1]
3344 + start_pos.y
3345 + galley
3346 .rows
3347 .first()
3348 .map_or(14.0, |row| row.height()),
3349 ),
3350 );
3351 ui.painter().rect_filled(
3352 selection_rect,
3353 0.0,
3354 Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3355 );
3356 } else {
3357 let row_height =
3359 galley.rows.first().map_or(14.0, |row| row.height());
3360 let start_row = (start_pos.y / row_height).round() as usize;
3361 let end_row = (end_pos.y / row_height).round() as usize;
3362
3363 for row in start_row..=end_row {
3364 if let Some(current_row) = galley.rows.get(row) {
3365 let row_rect = current_row.rect();
3366
3367 if row == start_row {
3368 let selection_rect = Rect::from_min_max(
3370 Pos2::new(
3371 text.position[0] + start_pos.x,
3372 text.position[1]
3373 + row as f32 * row_height,
3374 ),
3375 Pos2::new(
3376 text.position[0] + row_rect.max.x,
3377 text.position[1]
3378 + row as f32 * row_height
3379 + row_height,
3380 ),
3381 );
3382 ui.painter().rect_filled(
3383 selection_rect,
3384 0.0,
3385 Color32::from_rgba_unmultiplied(
3386 0, 120, 255, 100,
3387 ),
3388 );
3389 } else if row == end_row {
3390 let selection_rect = Rect::from_min_max(
3392 Pos2::new(
3393 text.position[0] + row_rect.min.x,
3394 text.position[1]
3395 + row as f32 * row_height,
3396 ),
3397 Pos2::new(
3398 text.position[0] + end_pos.x,
3399 text.position[1]
3400 + row as f32 * row_height
3401 + row_height,
3402 ),
3403 );
3404 ui.painter().rect_filled(
3405 selection_rect,
3406 0.0,
3407 Color32::from_rgba_unmultiplied(
3408 0, 120, 255, 100,
3409 ),
3410 );
3411 } else {
3412 let selection_rect = Rect::from_min_max(
3414 Pos2::new(
3415 text.position[0] + row_rect.min.x,
3416 text.position[1]
3417 + row as f32 * row_height,
3418 ),
3419 Pos2::new(
3420 text.position[0] + row_rect.max.x,
3421 text.position[1]
3422 + row as f32 * row_height
3423 + row_height,
3424 ),
3425 );
3426 ui.painter().rect_filled(
3427 selection_rect,
3428 0.0,
3429 Color32::from_rgba_unmultiplied(
3430 0, 120, 255, 100,
3431 ),
3432 );
3433 };
3434 };
3435 }
3436 };
3437 };
3438 }
3439 if text.basic_front_resource_config.clip_rect.is_some() {
3440 ui.set_clip_rect(Rect::from_min_size(
3441 [0_f32, 0_f32].into(),
3442 [ctx.available_rect().width(), ctx.available_rect().height()]
3443 .into(),
3444 ));
3445 };
3446 } else {
3447 text.selection = None;
3448 };
3449 text.last_frame_content = display_content;
3450 self.replace_resource(&render_resource.name, text)?;
3451 };
3452 }
3453 "rust_constructor::CustomRect" => {
3454 let custom_rect = self.get_resource::<CustomRect>(
3455 &render_resource.name,
3456 "rust_constructor::CustomRect",
3457 )?;
3458 if custom_rect.display_info.enable {
3459 let mut custom_rect = custom_rect.clone();
3460 [custom_rect.position, custom_rect.size] = self.position_size_processor(
3461 custom_rect.basic_front_resource_config.position_size_config,
3462 ctx,
3463 );
3464 if !custom_rect.display_info.hidden {
3465 if let Some(clip_rect) =
3466 custom_rect.basic_front_resource_config.clip_rect
3467 {
3468 let [min, size] = self.position_size_processor(clip_rect, ctx);
3469 ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
3470 };
3471 ui.painter().rect(
3472 Rect::from_min_max(
3473 Pos2::new(custom_rect.position[0], custom_rect.position[1]),
3474 Pos2::new(
3475 custom_rect.position[0] + custom_rect.size[0],
3476 custom_rect.position[1] + custom_rect.size[1],
3477 ),
3478 ),
3479 custom_rect.rounding,
3480 Color32::from_rgba_unmultiplied(
3481 custom_rect.color[0],
3482 custom_rect.color[1],
3483 custom_rect.color[2],
3484 custom_rect.alpha,
3485 ),
3486 Stroke {
3487 width: custom_rect.border_width,
3488 color: Color32::from_rgba_unmultiplied(
3489 custom_rect.border_color[0],
3490 custom_rect.border_color[1],
3491 custom_rect.border_color[2],
3492 custom_rect.alpha,
3493 ),
3494 },
3495 match custom_rect.border_kind {
3496 BorderKind::Inside => StrokeKind::Inside,
3497 BorderKind::Middle => StrokeKind::Middle,
3498 BorderKind::Outside => StrokeKind::Outside,
3499 },
3500 );
3501 if custom_rect.basic_front_resource_config.clip_rect.is_some() {
3502 ui.set_clip_rect(Rect::from_min_size(
3503 [0_f32, 0_f32].into(),
3504 [ctx.available_rect().width(), ctx.available_rect().height()]
3505 .into(),
3506 ));
3507 };
3508 };
3509 self.replace_resource(&render_resource.name, custom_rect)?;
3510 };
3511 }
3512 _ => {
3513 unreachable!()
3514 }
3515 }
3516 Ok(())
3517 } else {
3518 Err(RustConstructorError {
3519 error_id: "IndexOutOfRange".to_string(),
3520 description: format!(
3521 "The maximum index of the target list is {}, but the index is {index}.",
3522 self.render_list.len() - 1
3523 ),
3524 })
3525 }
3526 }
3527
3528 pub fn active_list_info(&self, method: ActiveListInfoMethod) -> String {
3530 let mut text = String::from("Resource Active Info:\n");
3531 for info in &self.active_list {
3532 if let ActiveListInfoMethod::Detailed(format) = method {
3533 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3534 text += &if format {
3535 format!(
3536 "\nName: {}\nType: {}\nDetail: {:#?}\n",
3537 info.name, info.discern_type, self.rust_constructor_resource[index],
3538 )
3539 } else {
3540 format!(
3541 "\nName: {}\nType: {}\nDetail: {:?}\n",
3542 info.name, info.discern_type, self.rust_constructor_resource[index],
3543 )
3544 };
3545 };
3546 } else {
3547 text += &format!("\nName: {}\nType: {}\n", info.name, info.discern_type);
3548 };
3549 }
3550 text
3551 }
3552
3553 pub fn render_layer_info(&self) -> String {
3555 let mut text = String::from("Render Layer Info:\n");
3556 for (
3557 RustConstructorId { name, discern_type },
3558 [min_position, max_position],
3559 ignore_render_layer,
3560 ) in &self.render_layer
3561 {
3562 text += &format!(
3563 "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
3564 name, discern_type, min_position, max_position, ignore_render_layer
3565 );
3566 }
3567 text
3568 }
3569
3570 pub fn render_list_info(&self) -> String {
3572 let mut text = String::from("Render List Info:\n");
3573 for RustConstructorId { name, discern_type } in &self.render_list {
3574 text += &format!("\nName: {:?}\nType: {:?}\n", name, discern_type);
3575 }
3576 text
3577 }
3578
3579 pub fn update_render_list(&mut self) {
3581 if self.render_list.is_empty() {
3582 for info in &self.active_list {
3583 if self.basic_front_resource_list.contains(&info.discern_type) {
3584 self.render_list.push(RustConstructorId {
3585 name: info.name.clone(),
3586 discern_type: info.discern_type.clone(),
3587 });
3588 };
3589 }
3590 } else {
3591 let mut count = 0;
3592 for render_resource in &self.render_list.clone() {
3593 if !self.active_list.contains(render_resource) {
3594 self.render_list.remove(count);
3595 } else {
3596 count += 1;
3597 };
3598 }
3599 let mut insert_index = 0;
3600 for info in &self.active_list {
3601 if self.basic_front_resource_list.contains(&info.discern_type) {
3602 if !self.render_list.contains(info) {
3603 self.render_list.insert(
3604 insert_index,
3605 RustConstructorId {
3606 name: info.name.clone(),
3607 discern_type: info.discern_type.clone(),
3608 },
3609 );
3610 insert_index += 1;
3611 } else if self.render_list[insert_index].cmp(info) == Ordering::Equal {
3612 insert_index += 1;
3613 };
3614 };
3615 }
3616 };
3617 }
3618
3619 pub fn unsafe_request_jump_render_list(
3621 &mut self,
3622 requester: RequestMethod,
3623 request_type: RequestType,
3624 ) {
3625 #[allow(warnings)]
3626 self.request_jump_render_list(requester, request_type);
3627 }
3628
3629 pub fn request_jump_render_list(
3631 &mut self,
3632 requester: RequestMethod,
3633 request_type: RequestType,
3634 ) -> Result<(), RustConstructorError> {
3635 match requester {
3636 RequestMethod::Id(RustConstructorId { name, discern_type }) => {
3637 if let Some(index) = self
3638 .render_list
3639 .iter()
3640 .position(|x| x.name == name && x.discern_type == discern_type)
3641 {
3642 self.jump_render_list_processor(index, request_type)?;
3643 Ok(())
3644 } else {
3645 Err(RustConstructorError {
3646 error_id: "RenderResourceNotFound".to_string(),
3647 description: format!(
3648 "Render resource \"{name}({discern_type})\" not found.",
3649 ),
3650 })
3651 }
3652 }
3653 RequestMethod::Citer(RustConstructorId { name, discern_type }) => {
3654 for (i, render_resource) in self.render_list.iter().enumerate() {
3655 let [resource_name, resource_type] = [
3656 render_resource.name.clone(),
3657 render_resource.discern_type.clone(),
3658 ];
3659 let tags = self
3660 .get_box_resource(&resource_name, &resource_type)?
3661 .display_tags();
3662 if let [Some(tag_name), Some(tag_type)] = [
3663 self.get_tag("citer_name", &tags),
3664 self.get_tag("citer_type", &tags),
3665 ] && tag_name.1 == name
3666 && tag_type.1 == discern_type
3667 {
3668 self.jump_render_list_processor(i, request_type)?;
3669 return Ok(());
3670 };
3671 }
3672 Err(RustConstructorError {
3673 error_id: "RenderResourceNotFound".to_string(),
3674 description: format!("Render resource \"{name}({discern_type})\" not found.",),
3675 })
3676 }
3677 }
3678 }
3679
3680 pub fn jump_render_list_processor(
3682 &mut self,
3683 requester_index: usize,
3684 request_type: RequestType,
3685 ) -> Result<(), RustConstructorError> {
3686 if requester_index < self.render_list.len() {
3687 let requester = self.render_list.remove(requester_index);
3688 let new_index = match request_type {
3689 RequestType::Top => self.render_list.len(),
3690 RequestType::Up(up) => {
3691 if requester_index + up as usize <= self.render_list.len() {
3692 requester_index + up as usize
3693 } else {
3694 self.render_list.len()
3695 }
3696 }
3697 };
3698 self.render_list.insert(new_index, requester);
3699 Ok(())
3700 } else {
3701 Err(RustConstructorError {
3702 error_id: "IndexOutOfRange".to_string(),
3703 description: format!(
3704 "The maximum index of the target list is {}, but the index is {requester_index}.",
3705 self.render_list.len() - 1
3706 ),
3707 })
3708 }
3709 }
3710
3711 pub fn update_render_layer(&mut self) {
3713 self.render_layer.clear();
3714 for info in &self.render_list {
3715 if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3716 let basic_front_resource: Box<dyn BasicFrontResource> = match &*info.discern_type {
3717 "rust_constructor::Image" => Box::new(
3718 self.rust_constructor_resource[index]
3719 .content
3720 .as_any()
3721 .downcast_ref::<Image>()
3722 .unwrap()
3723 .clone(),
3724 ),
3725 "rust_constructor::Text" => Box::new(
3726 self.rust_constructor_resource[index]
3727 .content
3728 .as_any()
3729 .downcast_ref::<Text>()
3730 .unwrap()
3731 .clone(),
3732 ),
3733 "rust_constructor::CustomRect" => Box::new(
3734 self.rust_constructor_resource[index]
3735 .content
3736 .as_any()
3737 .downcast_ref::<CustomRect>()
3738 .unwrap()
3739 .clone(),
3740 ),
3741 _ => {
3742 unreachable!()
3743 }
3744 };
3745 if let Some(display_info) = basic_front_resource.display_display_info() {
3746 self.render_layer.push((
3747 info.clone(),
3748 [
3749 basic_front_resource.display_position(),
3750 [
3751 basic_front_resource.display_position()[0]
3752 + basic_front_resource.display_size()[0],
3753 basic_front_resource.display_position()[1]
3754 + basic_front_resource.display_size()[1],
3755 ],
3756 ],
3757 display_info.ignore_render_layer,
3758 ));
3759 };
3760 };
3761 }
3762 }
3763
3764 pub fn display_render_layer(
3766 &self,
3767 ui: &mut Ui,
3768 render_config: &RenderConfig,
3769 ignore_render_config: &RenderConfig,
3770 ) {
3771 for (_, point, ignore_render_layer) in &self.render_layer {
3772 match if *ignore_render_layer {
3773 ignore_render_config
3774 } else {
3775 render_config
3776 } {
3777 RenderConfig::Rect(
3778 corner_radius,
3779 fill_color,
3780 border_color,
3781 border_width,
3782 border_kind,
3783 ) => {
3784 let rect = Rect::from_min_max(point[0].into(), point[1].into());
3785 ui.painter().rect(
3786 rect,
3787 CornerRadius {
3788 nw: corner_radius[0],
3789 ne: corner_radius[1],
3790 sw: corner_radius[2],
3791 se: corner_radius[3],
3792 },
3793 Color32::from_rgba_unmultiplied(
3794 fill_color[0],
3795 fill_color[1],
3796 fill_color[2],
3797 fill_color[3],
3798 ),
3799 Stroke::new(
3800 *border_width,
3801 Color32::from_rgba_unmultiplied(
3802 border_color[0],
3803 border_color[1],
3804 border_color[2],
3805 border_color[3],
3806 ),
3807 ),
3808 match *border_kind {
3809 BorderKind::Inside => StrokeKind::Inside,
3810 BorderKind::Middle => StrokeKind::Middle,
3811 BorderKind::Outside => StrokeKind::Outside,
3812 },
3813 );
3814 }
3815 RenderConfig::Line(width, color) => {
3816 ui.painter().line_segment(
3817 [point[0].into(), point[1].into()],
3818 Stroke::new(
3819 *width,
3820 Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3821 ),
3822 );
3823 }
3824 };
3825 }
3826 }
3827
3828 pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3830 self.render_layer
3831 .iter()
3832 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
3833 }
3834
3835 pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3837 for i in index + 1..self.render_layer.len() {
3838 let point = self.render_layer[i].1;
3839 if mouse_pos[0] > point[0][0]
3840 && mouse_pos[1] > point[0][1]
3841 && mouse_pos[0] < point[1][0]
3842 && mouse_pos[1] < point[1][1]
3843 && !self.render_layer[i].2
3844 {
3845 return false;
3846 };
3847 }
3848 true
3849 }
3850
3851 pub fn add_active_resource(
3853 &mut self,
3854 name: &str,
3855 discern_type: &str,
3856 ) -> Result<(), RustConstructorError> {
3857 if self.check_resource_exists(name, discern_type).is_some() {
3858 self.active_list.push(RustConstructorId {
3859 name: name.to_string(),
3860 discern_type: discern_type.to_string(),
3861 });
3862 Ok(())
3863 } else {
3864 Err(RustConstructorError {
3865 error_id: "ResourceNotFound".to_string(),
3866 description: format!("Resource \"{name}({discern_type})\" not found."),
3867 })
3868 }
3869 }
3870
3871 pub fn add_resource<T: RustConstructorResource + 'static>(
3873 &mut self,
3874 name: &str,
3875 mut resource: T,
3876 ) -> Result<(), RustConstructorError> {
3877 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3878 list.0
3879 } else {
3880 type_name_of_val(&resource)
3881 };
3882 if self.check_resource_exists(name, discern_type).is_some() {
3883 return Err(RustConstructorError {
3884 error_id: "ResourceNameRepetition".to_string(),
3885 description: format!("Resource \"{name}({discern_type})\" has already existed."),
3886 });
3887 };
3888 if name.is_empty() {
3889 return Err(RustConstructorError {
3890 error_id: "ResourceUntitled".to_string(),
3891 description: "All resources must have a valid name.".to_string(),
3892 });
3893 };
3894 match discern_type {
3895 "rust_constructor::SplitTime" => {
3896 if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3897 split_time.time = [self.timer.now_time, self.timer.total_time];
3898 };
3899 }
3900 "rust_constructor::ImageTexture" => {
3901 if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3902 if let Ok(mut file) = File::open(&image_texture.cite_path) {
3903 let mut buffer = Vec::new();
3904 file.read_to_end(&mut buffer).unwrap();
3905 let img_bytes = buffer;
3906 let img = image::load_from_memory(&img_bytes).unwrap();
3907 let color_data = match image_texture.flip {
3908 [true, true] => img.fliph().flipv().into_rgba8(),
3909 [true, false] => img.fliph().into_rgba8(),
3910 [false, true] => img.flipv().into_rgba8(),
3911 _ => img.into_rgba8(),
3912 };
3913 let (w, h) = (color_data.width(), color_data.height());
3914 let raw_data: Vec<u8> = color_data.into_raw();
3915
3916 let color_image =
3917 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3918 let loaded_image_texture = image_texture.context.load_texture(
3919 name,
3920 color_image,
3921 TextureOptions::LINEAR,
3922 );
3923 image_texture.texture =
3924 Some(DebugTextureHandle::new(&loaded_image_texture));
3925 image_texture.cite_path = image_texture.cite_path.to_string();
3926 } else {
3927 return Err(RustConstructorError {
3928 error_id: "ImageLoadFailed".to_string(),
3929 description: format!(
3930 "Failed to load an image from the path \"{}\".",
3931 image_texture.cite_path
3932 ),
3933 });
3934 };
3935 };
3936 }
3937 "rust_constructor::Image" => {
3938 if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3939 let image_texture = self.get_resource::<ImageTexture>(
3940 &image.cite_texture,
3941 "rust_constructor::ImageTexture",
3942 )?;
3943 image.texture = image_texture.texture.clone();
3944 image.last_frame_cite_texture = image.cite_texture.clone();
3945 };
3946 }
3947 "rust_constructor::Font" => {
3948 if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3949 let mut fonts = FontDefinitions::default();
3950 if let Ok(font_read_data) = read(&font.path) {
3951 let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3952 fonts.font_data.insert(
3953 name.to_owned(),
3954 Arc::new(FontData::from_owned(
3955 Arc::try_unwrap(font_data).ok().unwrap(),
3956 )),
3957 );
3958
3959 fonts
3961 .families
3962 .entry(FontFamily::Proportional)
3963 .or_default()
3964 .insert(0, name.to_owned());
3965
3966 fonts
3967 .families
3968 .entry(FontFamily::Monospace)
3969 .or_default()
3970 .insert(0, name.to_owned());
3971
3972 font.font_definitions = fonts;
3973 } else {
3974 return Err(RustConstructorError {
3975 error_id: "FontLoadFailed".to_string(),
3976 description: format!(
3977 "Failed to load a font from the path \"{}\".",
3978 font.path
3979 ),
3980 });
3981 }
3982 };
3983 }
3984 "rust_constructor::Background" => {
3985 if let Some(background) = resource.as_any_mut().downcast_mut::<Background>() {
3986 match &background.background_type {
3987 BackgroundType::CustomRect(config) => {
3988 let mut custom_rect = CustomRect::default().from_config(config);
3989 if background.use_background_tags {
3990 custom_rect.modify_tags(&background.tags, false);
3991 };
3992 self.add_resource(name, custom_rect)
3993 }
3994 BackgroundType::Image(config) => {
3995 let mut image = Image::default().from_config(config);
3996 if background.use_background_tags {
3997 image.modify_tags(&background.tags, false);
3998 };
3999 self.add_resource(name, image)
4000 }
4001 }?;
4002 };
4003 }
4004 "rust_constructor::Switch" => {
4005 if let Some(switch) = resource.as_any_mut().downcast_mut::<Switch>() {
4006 let count = 1 + switch.enable_animation.iter().filter(|x| **x).count();
4007 if switch.appearance.len() != count * switch.state_amount as usize {
4008 return Err(RustConstructorError {
4009 error_id: "SwitchAppearanceConfigMismatch".to_string(),
4010 description: format!(
4011 "Expected {} elements, found {}.",
4012 count * switch.state_amount as usize,
4013 switch.appearance.len()
4014 ),
4015 });
4016 };
4017 self.add_resource(
4018 &format!("{name}Background"),
4019 Background::default()
4020 .background_type(&switch.background_type)
4021 .auto_update(true)
4022 .use_background_tags(true)
4023 .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}Text"),
4033 Text::default().from_config(&switch.text_config).tags(
4034 &[
4035 ["citer_name".to_string(), name.to_string()],
4036 ["citer_type".to_string(), discern_type.to_string()],
4037 ],
4038 false,
4039 ),
4040 )?;
4041 self.add_resource(
4042 &format!("{name}HintText"),
4043 Text::default()
4044 .from_config(&switch.hint_text_config)
4045 .ignore_render_layer(true)
4046 .hidden(true)
4047 .alpha(0)
4048 .tags(
4049 &[
4050 ["citer_name".to_string(), name.to_string()],
4051 ["citer_type".to_string(), discern_type.to_string()],
4052 ["disable_x_scrolling".to_string(), "".to_string()],
4053 ["disable_y_scrolling".to_string(), "".to_string()],
4054 ],
4055 false,
4056 ),
4057 )?;
4058 self.add_resource(
4059 &format!("{name}StartHoverTime"),
4060 SplitTime::default().tags(
4061 &[
4062 ["citer_name".to_string(), name.to_string()],
4063 ["citer_type".to_string(), discern_type.to_string()],
4064 ],
4065 false,
4066 ),
4067 )?;
4068 self.add_resource(
4069 &format!("{name}HintFadeAnimation"),
4070 SplitTime::default().tags(
4071 &[
4072 ["citer_name".to_string(), name.to_string()],
4073 ["citer_type".to_string(), discern_type.to_string()],
4074 ],
4075 false,
4076 ),
4077 )?;
4078 };
4079 }
4080 "rust_constructor::ResourcePanel" => {
4081 if let Some(resource_panel) = resource.as_any_mut().downcast_mut::<ResourcePanel>()
4082 {
4083 self.add_resource(
4084 &format!("{name}Background"),
4085 Background::default()
4086 .background_type(&resource_panel.background)
4087 .auto_update(true)
4088 .use_background_tags(true)
4089 .tags(
4090 &[
4091 ["citer_name".to_string(), name.to_string()],
4092 ["citer_type".to_string(), discern_type.to_string()],
4093 ],
4094 false,
4095 ),
4096 )?;
4097 if let ScrollBarDisplayMethod::Always(_, _, _) =
4098 &resource_panel.scroll_bar_display_method
4099 {
4100 self.add_resource(
4101 &format!("{name}XScroll"),
4102 Background::default()
4103 .auto_update(true)
4104 .use_background_tags(true)
4105 .tags(
4106 &[
4107 ["citer_name".to_string(), name.to_string()],
4108 ["citer_type".to_string(), discern_type.to_string()],
4109 ],
4110 false,
4111 ),
4112 )?;
4113 self.add_resource(
4114 &format!("{name}YScroll"),
4115 Background::default()
4116 .auto_update(true)
4117 .use_background_tags(true)
4118 .tags(
4119 &[
4120 ["citer_name".to_string(), name.to_string()],
4121 ["citer_type".to_string(), discern_type.to_string()],
4122 ],
4123 false,
4124 ),
4125 )?;
4126 };
4127 if let ScrollBarDisplayMethod::OnlyScroll(_, _, _) =
4128 &resource_panel.scroll_bar_display_method
4129 {
4130 self.add_resource(
4131 &format!("{name}XScroll"),
4132 Background::default()
4133 .auto_update(true)
4134 .use_background_tags(true)
4135 .tags(
4136 &[
4137 ["citer_name".to_string(), name.to_string()],
4138 ["citer_type".to_string(), discern_type.to_string()],
4139 ],
4140 false,
4141 ),
4142 )?;
4143 self.add_resource(
4144 &format!("{name}YScroll"),
4145 Background::default()
4146 .auto_update(true)
4147 .use_background_tags(true)
4148 .tags(
4149 &[
4150 ["citer_name".to_string(), name.to_string()],
4151 ["citer_type".to_string(), discern_type.to_string()],
4152 ],
4153 false,
4154 ),
4155 )?;
4156 self.add_resource(
4157 &format!("{name}ScrollBarXAlpha"),
4158 SplitTime::default().tags(
4159 &[
4160 ["citer_name".to_string(), name.to_string()],
4161 ["citer_type".to_string(), discern_type.to_string()],
4162 ],
4163 false,
4164 ),
4165 )?;
4166 self.add_resource(
4167 &format!("{name}ScrollBarXAlphaStart"),
4168 SplitTime::default().tags(
4169 &[
4170 ["citer_name".to_string(), name.to_string()],
4171 ["citer_type".to_string(), discern_type.to_string()],
4172 ],
4173 false,
4174 ),
4175 )?;
4176 self.add_resource(
4177 &format!("{name}ScrollBarYAlpha"),
4178 SplitTime::default().tags(
4179 &[
4180 ["citer_name".to_string(), name.to_string()],
4181 ["citer_type".to_string(), discern_type.to_string()],
4182 ],
4183 false,
4184 ),
4185 )?;
4186 self.add_resource(
4187 &format!("{name}ScrollBarYAlphaStart"),
4188 SplitTime::default().tags(
4189 &[
4190 ["citer_name".to_string(), name.to_string()],
4191 ["citer_type".to_string(), discern_type.to_string()],
4192 ],
4193 false,
4194 ),
4195 )?;
4196 };
4197 };
4198 }
4199 _ => {}
4200 };
4201 self.rust_constructor_resource
4202 .push(RustConstructorResourceBox::new(
4203 name,
4204 discern_type,
4205 Box::new(resource),
4206 ));
4207 Ok(())
4208 }
4209
4210 pub fn drop_resource(
4212 &mut self,
4213 name: &str,
4214 discern_type: &str,
4215 ) -> Result<(), RustConstructorError> {
4216 if let Some(index) = self.check_resource_exists(name, discern_type) {
4217 self.rust_constructor_resource.remove(index);
4218 if let Some(index) = self
4219 .active_list
4220 .iter()
4221 .position(|x| x.name == name && x.discern_type == discern_type)
4222 {
4223 self.active_list.remove(index);
4224 };
4225 if let Some(index) = self
4226 .render_layer
4227 .iter()
4228 .position(|x| x.0.name == name && x.0.discern_type == discern_type)
4229 {
4230 self.render_layer.remove(index);
4231 };
4232 Ok(())
4233 } else {
4234 Err(RustConstructorError {
4235 error_id: "ResourceNotFound".to_string(),
4236 description: format!("Resource \"{name}({discern_type})\" not found."),
4237 })
4238 }
4239 }
4240
4241 pub fn replace_resource<T>(
4243 &mut self,
4244 name: &str,
4245 resource: T,
4246 ) -> Result<(), RustConstructorError>
4247 where
4248 T: RustConstructorResource + 'static,
4249 {
4250 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4251 list.0
4252 } else {
4253 type_name_of_val(&resource)
4254 };
4255 if let Some(index) = self.check_resource_exists(name, discern_type) {
4256 self.rust_constructor_resource[index] =
4257 RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
4258 Ok(())
4259 } else {
4260 Err(RustConstructorError {
4261 error_id: "ResourceNotFound".to_string(),
4262 description: format!("Resource \"{name}({discern_type})\" not found."),
4263 })
4264 }
4265 }
4266
4267 pub fn get_box_resource(
4269 &self,
4270 name: &str,
4271 discern_type: &str,
4272 ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
4273 if let Some(index) = self.check_resource_exists(name, discern_type) {
4274 Ok(&*self.rust_constructor_resource[index].content)
4275 } else {
4276 Err(RustConstructorError {
4277 error_id: "ResourceNotFound".to_string(),
4278 description: format!("Resource \"{name}({discern_type})\" not found."),
4279 })
4280 }
4281 }
4282
4283 pub fn get_box_resource_mut(
4285 &mut self,
4286 name: &str,
4287 discern_type: &str,
4288 ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
4289 if let Some(index) = self.check_resource_exists(name, discern_type) {
4290 Ok(&mut *self.rust_constructor_resource[index].content)
4291 } else {
4292 Err(RustConstructorError {
4293 error_id: "ResourceNotFound".to_string(),
4294 description: format!("Resource \"{name}({discern_type})\" not found."),
4295 })
4296 }
4297 }
4298
4299 pub fn get_resource<T>(
4301 &self,
4302 name: &str,
4303 discern_type: &str,
4304 ) -> Result<&T, RustConstructorError>
4305 where
4306 T: RustConstructorResource + 'static,
4307 {
4308 if let Some(resource) = self
4309 .get_box_resource(name, discern_type)?
4310 .as_any()
4311 .downcast_ref::<T>()
4312 {
4313 Ok(resource)
4314 } else {
4315 Err(RustConstructorError {
4316 error_id: "ResourceGenericMismatch".to_string(),
4317 description: format!(
4318 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4319 ),
4320 })
4321 }
4322 }
4323
4324 pub fn get_resource_mut<T>(
4326 &mut self,
4327 name: &str,
4328 discern_type: &str,
4329 ) -> Result<&mut T, RustConstructorError>
4330 where
4331 T: RustConstructorResource + 'static,
4332 {
4333 if let Some(resource) = self
4334 .get_box_resource_mut(name, discern_type)?
4335 .as_any_mut()
4336 .downcast_mut::<T>()
4337 {
4338 Ok(resource)
4339 } else {
4340 Err(RustConstructorError {
4341 error_id: "ResourceGenericMismatch".to_string(),
4342 description: format!(
4343 "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4344 ),
4345 })
4346 }
4347 }
4348
4349 pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
4351 self.rust_constructor_resource
4352 .iter()
4353 .position(|x| x.id.name == name && x.id.discern_type == discern_type)
4354 }
4355
4356 pub fn quick_place<T: RustConstructorResource + 'static>(
4358 &mut self,
4359 name: &str,
4360 resource: T,
4361 ui: &mut Ui,
4362 ctx: &Context,
4363 ) -> Result<(), RustConstructorError> {
4364 let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4365 list.0
4366 } else {
4367 type_name_of_val(&resource)
4368 };
4369 if self.check_resource_exists(name, discern_type).is_none() {
4370 self.add_resource(name, resource)
4371 } else {
4372 self.use_resource(name, discern_type, ui, ctx)
4373 }
4374 }
4375
4376 pub fn use_resource(
4378 &mut self,
4379 name: &str,
4380 discern_type: &str,
4381 ui: &mut Ui,
4382 ctx: &Context,
4383 ) -> Result<(), RustConstructorError> {
4384 if self.check_resource_exists(name, discern_type).is_some() {
4385 match discern_type {
4386 "rust_constructor::CustomRect"
4387 | "rust_constructor::Text"
4388 | "rust_constructor::Image" => {
4389 self.add_active_resource(name, discern_type)?;
4390 }
4391 "rust_constructor::PageData" => {
4392 self.update_frame_stats();
4394 self.update_render_list();
4396 for i in 0..self.render_list.len() {
4398 self.draw_resource_by_index(ui, ctx, i)?;
4399 }
4400 self.update_render_layer();
4402 self.active_list.clear();
4404 for rcr in &mut self.rust_constructor_resource {
4406 if let Some(display_info) = &mut rcr.content.display_display_info() {
4407 rcr.content.modify_display_info(DisplayInfo {
4408 enable: true,
4409 hidden: display_info.hidden,
4410 ignore_render_layer: display_info.ignore_render_layer,
4411 });
4412 };
4413 }
4414 self.update_timer();
4416 let current_page = &self.current_page.clone();
4417 let page_data =
4418 self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
4419 if page_data.forced_update {
4420 ctx.request_repaint();
4421 };
4422 }
4423 "rust_constructor::Background" => {
4424 let background = self.get_resource::<Background>(name, discern_type)?.clone();
4425 if background.auto_update {
4426 match &background.background_type {
4427 BackgroundType::CustomRect(config) => {
4428 let mut custom_rect = self
4429 .get_resource::<CustomRect>(
4430 name,
4431 "rust_constructor::CustomRect",
4432 )?
4433 .clone()
4434 .from_config(config);
4435 if background.use_background_tags {
4436 custom_rect.modify_tags(&background.tags, false);
4437 };
4438 self.replace_resource(name, custom_rect)?;
4439 }
4440 BackgroundType::Image(config) => {
4441 let mut image = self
4442 .get_resource::<Image>(name, "rust_constructor::Image")?
4443 .clone()
4444 .from_config(config);
4445 if background.use_background_tags {
4446 image.modify_tags(&background.tags, false);
4447 };
4448 self.replace_resource(name, image)?;
4449 }
4450 };
4451 };
4452 match background.background_type {
4453 BackgroundType::CustomRect(_) => {
4454 self.use_resource(name, "rust_constructor::CustomRect", ui, ctx)
4455 }
4456 BackgroundType::Image(_) => {
4457 self.use_resource(name, "rust_constructor::Image", ui, ctx)
4458 }
4459 }?;
4460 }
4461 "rust_constructor::Switch" => {
4462 let mut switch = self
4463 .get_resource::<Switch>(name, "rust_constructor::Switch")?
4464 .clone();
4465 let mut background = self
4466 .get_resource::<Background>(
4467 &format!("{name}Background"),
4468 "rust_constructor::Background",
4469 )?
4470 .clone();
4471 let background_resource_type = match switch.background_type {
4472 BackgroundType::CustomRect(_) => "rust_constructor::CustomRect",
4473 BackgroundType::Image(_) => "rust_constructor::Image",
4474 };
4475 let background_resource: Box<dyn BasicFrontResource> =
4476 match background_resource_type {
4477 "rust_constructor::CustomRect" => Box::new(
4478 self.get_resource::<CustomRect>(
4479 &format!("{name}Background"),
4480 background_resource_type,
4481 )?
4482 .clone(),
4483 ),
4484 "rust_constructor::Image" => Box::new(
4485 self.get_resource::<Image>(
4486 &format!("{name}Background"),
4487 background_resource_type,
4488 )?
4489 .clone(),
4490 ),
4491 _ => {
4492 unreachable!()
4493 }
4494 };
4495 let mut text = self
4496 .get_resource::<Text>(&format!("{name}Text"), "rust_constructor::Text")?
4497 .clone();
4498 let mut hint_text = self
4499 .get_resource::<Text>(&format!("{name}HintText"), "rust_constructor::Text")?
4500 .clone();
4501 let rect = Rect::from_min_size(
4502 background_resource.display_position().into(),
4503 background_resource.display_size().into(),
4504 );
4505 switch.switched = false;
4506 let animation_count =
4507 1 + switch.enable_animation.iter().filter(|x| **x).count();
4508 let mut clicked = None;
4509 let mut hovered = false;
4510 let mut appearance_count = 0;
4511 if let Some(index) = self.get_render_layer_resource(
4513 &format!("{name}Background"),
4514 background_resource_type,
4515 ) && switch.enable
4516 && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
4517 && self.resource_get_focus(index, mouse_pos.into())
4518 {
4519 if rect.contains(mouse_pos) {
4521 if !switch.last_frame_hovered {
4522 self.reset_split_time(&format!("{name}StartHoverTime"))?;
4523 } else if self.timer.total_time
4524 - self.get_split_time(&format!("{name}StartHoverTime"))?[1]
4525 >= 2_f32
4526 || hint_text.alpha != 0
4527 {
4528 hint_text.alpha = 255;
4529 hint_text
4530 .basic_front_resource_config
4531 .position_size_config
4532 .origin_position = [mouse_pos.x, mouse_pos.y];
4533 };
4534 hint_text
4535 .basic_front_resource_config
4536 .position_size_config
4537 .display_method
4538 .0 = if mouse_pos.x + hint_text.actual_size[0]
4539 <= ctx.available_rect().width()
4540 {
4541 HorizontalAlign::Left
4542 } else {
4543 HorizontalAlign::Right
4544 };
4545 hint_text
4546 .basic_front_resource_config
4547 .position_size_config
4548 .display_method
4549 .1 = if mouse_pos.y + hint_text.actual_size[1]
4550 <= ctx.available_rect().height()
4551 {
4552 VerticalAlign::Top
4553 } else {
4554 VerticalAlign::Bottom
4555 };
4556 hovered = true;
4557 for (count, click_method) in switch.click_method.iter().enumerate() {
4558 if ui.input(|i| i.pointer.button_down(click_method.click_method)) {
4559 clicked = Some(count);
4560 break;
4561 };
4562 }
4563 if let Some(clicked_index) = switch.last_frame_clicked
4564 && clicked.is_none()
4565 {
4566 switch.switched = true;
4567 if switch.click_method[clicked_index].action {
4568 if switch.state
4569 < (switch.appearance.len() / animation_count - 1) as u32
4570 {
4571 switch.state += 1;
4572 } else {
4573 switch.state = 0;
4574 };
4575 };
4576 };
4577 appearance_count = if clicked.is_some() {
4578 match switch.enable_animation {
4579 [true, true] => 2,
4580 [true, false] | [false, true] => 1,
4581 [false, false] => 0,
4582 }
4583 } else if switch.enable_animation[0] {
4584 1
4585 } else {
4586 0
4587 };
4588 };
4589 };
4590
4591 if !hovered {
4593 if switch.last_frame_hovered {
4594 self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4595 };
4596 if self.timer.total_time
4597 - self.get_split_time(&format!("{name}HintFadeAnimation"))?[1]
4598 >= self.tick_interval
4599 {
4600 self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4601 hint_text.alpha = hint_text.alpha.saturating_sub(10);
4602 };
4603 };
4604
4605 hint_text.display_info.hidden = hint_text.alpha == 0;
4606
4607 background.background_type = switch.appearance
4609 [(switch.state * animation_count as u32 + appearance_count) as usize]
4610 .background_config
4611 .clone();
4612
4613 let alpha = hint_text.alpha;
4615 hint_text = hint_text.from_config(
4616 &switch.appearance
4617 [(switch.state * animation_count as u32 + appearance_count) as usize]
4618 .hint_text_config,
4619 );
4620 hint_text.background_alpha = alpha;
4621 hint_text.alpha = alpha;
4622
4623 text = text.from_config(
4625 &switch.appearance
4626 [(switch.state * animation_count as u32 + appearance_count) as usize]
4627 .text_config,
4628 );
4629
4630 switch.last_frame_hovered = hovered;
4631 switch.last_frame_clicked = clicked;
4632
4633 self.replace_resource(&format!("{name}Text"), text)?;
4634 self.replace_resource(&format!("{name}HintText"), hint_text)?;
4635 self.replace_resource(name, switch)?;
4636 self.replace_resource(&format!("{name}Background"), background)?;
4637
4638 self.use_resource(
4639 &format!("{name}Background"),
4640 "rust_constructor::Background",
4641 ui,
4642 ctx,
4643 )?;
4644 self.use_resource(&format!("{name}Text"), "rust_constructor::Text", ui, ctx)?;
4645 self.use_resource(
4646 &format!("{name}HintText"),
4647 "rust_constructor::Text",
4648 ui,
4649 ctx,
4650 )?;
4651 }
4652 "rust_constructor::ResourcePanel" => {
4653 let mut resource_panel = self
4654 .get_resource::<ResourcePanel>(name, "rust_constructor::ResourcePanel")?
4655 .clone();
4656 let background = self
4657 .get_resource::<Background>(
4658 &format!("{name}Background"),
4659 "rust_constructor::Background",
4660 )?
4661 .clone();
4662 let background_resource: Box<dyn BasicFrontResource> =
4663 match background.background_type.clone() {
4664 BackgroundType::CustomRect(_) => Box::new(
4665 self.get_resource::<CustomRect>(
4666 &format!("{name}Background"),
4667 "rust_constructor::CustomRect",
4668 )?
4669 .clone(),
4670 ),
4671 BackgroundType::Image(_) => Box::new(
4672 self.get_resource::<Image>(
4673 &format!("{name}Background"),
4674 "rust_constructor::Image",
4675 )?
4676 .clone(),
4677 ),
4678 };
4679 let (mut position_size_config, mut position, mut size) = (
4680 background_resource
4681 .display_basic_front_resource_config()
4682 .position_size_config,
4683 background_resource.display_position(),
4684 background_resource.display_size(),
4685 );
4686 let rect = Rect::from_min_size(position.into(), size.into());
4687 resource_panel.scrolled = [false, false];
4688 if resource_panel.resizable.contains(&true)
4689 || resource_panel.movable.contains(&true)
4690 {
4691 position_size_config.x_location_grid = [0_f32, 0_f32];
4692 position_size_config.y_location_grid = [0_f32, 0_f32];
4693 position_size_config.x_size_grid = [0_f32, 0_f32];
4694 position_size_config.y_size_grid = [0_f32, 0_f32];
4695 };
4696 if resource_panel.min_size[0] < 10_f32 {
4697 resource_panel.min_size[0] = 10_f32;
4698 };
4699 if resource_panel.min_size[1] < 10_f32 {
4700 resource_panel.min_size[1] = 10_f32;
4701 };
4702 if position_size_config.origin_size[0] < resource_panel.min_size[0] {
4703 position_size_config.origin_size[0] = resource_panel.min_size[0];
4704 };
4705 if position_size_config.origin_size[1] < resource_panel.min_size[1] {
4706 position_size_config.origin_size[1] = resource_panel.min_size[1];
4707 };
4708 [position, size] = self.position_size_processor(position_size_config, ctx);
4709 if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4710 let top_rect = Rect::from_min_size(
4711 [position[0] - 3_f32, position[1] - 3_f32].into(),
4712 [size[0] + 6_f32, 6_f32].into(),
4713 );
4714 let bottom_rect = Rect::from_min_size(
4715 [position[0] - 3_f32, position[1] + size[1] - 3_f32].into(),
4716 [size[0] + 6_f32, 6_f32].into(),
4717 );
4718 let left_rect = Rect::from_min_size(
4719 [position[0] - 3_f32, position[1] - 3_f32].into(),
4720 [6_f32, size[1] + 6_f32].into(),
4721 );
4722 let right_rect = Rect::from_min_size(
4723 [position[0] + size[0] - 3_f32, position[1] - 3_f32].into(),
4724 [6_f32, size[1] + 6_f32].into(),
4725 );
4726 match [
4727 top_rect.contains(mouse_pos),
4728 bottom_rect.contains(mouse_pos),
4729 left_rect.contains(mouse_pos),
4730 right_rect.contains(mouse_pos),
4731 ] {
4732 [true, false, false, false] => {
4733 if resource_panel.resizable[0] {
4734 if resource_panel.last_frame_mouse_status.is_none()
4735 && ui.input(|i| i.pointer.primary_pressed())
4736 {
4737 resource_panel.last_frame_mouse_status = Some((
4738 mouse_pos.into(),
4739 ClickAim::TopResize,
4740 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4741 ))
4742 };
4743 if size[1] > resource_panel.min_size[1]
4744 && (resource_panel.max_size.is_none()
4745 || size[1] < resource_panel.max_size.unwrap()[1])
4746 {
4747 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4748 } else if resource_panel.max_size.is_some()
4749 && size[1] >= resource_panel.max_size.unwrap()[1]
4750 {
4751 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4752 } else {
4753 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4754 };
4755 };
4756 }
4757 [false, true, false, false] => {
4758 if resource_panel.resizable[1] {
4759 if resource_panel.last_frame_mouse_status.is_none()
4760 && ui.input(|i| i.pointer.primary_pressed())
4761 {
4762 resource_panel.last_frame_mouse_status = Some((
4763 mouse_pos.into(),
4764 ClickAim::BottomResize,
4765 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4766 ))
4767 };
4768 if size[1] > resource_panel.min_size[1]
4769 && (resource_panel.max_size.is_none()
4770 || size[1] < resource_panel.max_size.unwrap()[1])
4771 {
4772 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4773 } else if resource_panel.max_size.is_some()
4774 && size[1] >= resource_panel.max_size.unwrap()[1]
4775 {
4776 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4777 } else {
4778 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4779 };
4780 };
4781 }
4782 [false, false, true, false] => {
4783 if resource_panel.resizable[2] {
4784 if resource_panel.last_frame_mouse_status.is_none()
4785 && ui.input(|i| i.pointer.primary_pressed())
4786 {
4787 resource_panel.last_frame_mouse_status = Some((
4788 mouse_pos.into(),
4789 ClickAim::LeftResize,
4790 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4791 ))
4792 };
4793 if size[0] > resource_panel.min_size[0]
4794 && (resource_panel.max_size.is_none()
4795 || size[0] < resource_panel.max_size.unwrap()[0])
4796 {
4797 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4798 } else if resource_panel.max_size.is_some()
4799 && size[0] >= resource_panel.max_size.unwrap()[0]
4800 {
4801 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4802 } else {
4803 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4804 };
4805 };
4806 }
4807 [false, false, false, true] => {
4808 if resource_panel.resizable[3] {
4809 if resource_panel.last_frame_mouse_status.is_none()
4810 && ui.input(|i| i.pointer.primary_pressed())
4811 {
4812 resource_panel.last_frame_mouse_status = Some((
4813 mouse_pos.into(),
4814 ClickAim::RightResize,
4815 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
4816 ))
4817 };
4818 if size[0] > resource_panel.min_size[0]
4819 && (resource_panel.max_size.is_none()
4820 || size[0] < resource_panel.max_size.unwrap()[0])
4821 {
4822 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4823 } else if resource_panel.max_size.is_some()
4824 && size[0] >= resource_panel.max_size.unwrap()[0]
4825 {
4826 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4827 } else {
4828 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4829 };
4830 };
4831 }
4832 [true, false, true, false] => {
4833 match [resource_panel.resizable[0], resource_panel.resizable[2]] {
4834 [true, true] => {
4835 if resource_panel.last_frame_mouse_status.is_none()
4836 && ui.input(|i| i.pointer.primary_pressed())
4837 {
4838 resource_panel.last_frame_mouse_status = Some((
4839 mouse_pos.into(),
4840 ClickAim::LeftTopResize,
4841 [
4842 mouse_pos.x - position[0],
4843 mouse_pos.y - position[1],
4844 ],
4845 ))
4846 };
4847 if size[0] > resource_panel.min_size[0]
4848 && (resource_panel.max_size.is_none()
4849 || size[0] < resource_panel.max_size.unwrap()[0])
4850 || size[1] > resource_panel.min_size[1]
4851 && (resource_panel.max_size.is_none()
4852 || size[1]
4853 < resource_panel.max_size.unwrap()[1])
4854 {
4855 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
4856 } else if resource_panel.max_size.is_some()
4857 && size[0] >= resource_panel.max_size.unwrap()[0]
4858 && size[1] >= resource_panel.max_size.unwrap()[1]
4859 {
4860 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
4861 } else {
4862 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
4863 };
4864 }
4865 [false, true] => {
4866 if resource_panel.last_frame_mouse_status.is_none()
4867 && ui.input(|i| i.pointer.primary_pressed())
4868 {
4869 resource_panel.last_frame_mouse_status = Some((
4870 mouse_pos.into(),
4871 ClickAim::LeftResize,
4872 [
4873 mouse_pos.x - position[0],
4874 mouse_pos.y - position[1],
4875 ],
4876 ))
4877 };
4878 if size[0] > resource_panel.min_size[0]
4879 && (resource_panel.max_size.is_none()
4880 || size[0] < resource_panel.max_size.unwrap()[0])
4881 {
4882 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4883 } else if resource_panel.max_size.is_some()
4884 && size[0] >= resource_panel.max_size.unwrap()[0]
4885 {
4886 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4887 } else {
4888 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4889 };
4890 }
4891 [true, false] => {
4892 if resource_panel.last_frame_mouse_status.is_none()
4893 && ui.input(|i| i.pointer.primary_pressed())
4894 {
4895 resource_panel.last_frame_mouse_status = Some((
4896 mouse_pos.into(),
4897 ClickAim::TopResize,
4898 [
4899 mouse_pos.x - position[0],
4900 mouse_pos.y - position[1],
4901 ],
4902 ))
4903 };
4904 if size[1] > resource_panel.min_size[1]
4905 && (resource_panel.max_size.is_none()
4906 || size[1] < resource_panel.max_size.unwrap()[1])
4907 {
4908 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4909 } else if resource_panel.max_size.is_some()
4910 && size[1] >= resource_panel.max_size.unwrap()[1]
4911 {
4912 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4913 } else {
4914 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4915 };
4916 }
4917 [false, false] => {}
4918 }
4919 }
4920 [false, true, false, true] => {
4921 match [resource_panel.resizable[1], resource_panel.resizable[3]] {
4922 [true, true] => {
4923 if resource_panel.last_frame_mouse_status.is_none()
4924 && ui.input(|i| i.pointer.primary_pressed())
4925 {
4926 resource_panel.last_frame_mouse_status = Some((
4927 mouse_pos.into(),
4928 ClickAim::RightBottomResize,
4929 [
4930 mouse_pos.x - position[0],
4931 mouse_pos.y - position[1],
4932 ],
4933 ))
4934 };
4935 if size[0] > resource_panel.min_size[0]
4936 && (resource_panel.max_size.is_none()
4937 || size[0] < resource_panel.max_size.unwrap()[0])
4938 || size[1] > resource_panel.min_size[1]
4939 && (resource_panel.max_size.is_none()
4940 || size[1]
4941 < resource_panel.max_size.unwrap()[1])
4942 {
4943 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
4944 } else if resource_panel.max_size.is_some()
4945 && size[0] >= resource_panel.max_size.unwrap()[0]
4946 && size[1] >= resource_panel.max_size.unwrap()[1]
4947 {
4948 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
4949 } else {
4950 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
4951 };
4952 }
4953 [false, true] => {
4954 if resource_panel.last_frame_mouse_status.is_none()
4955 && ui.input(|i| i.pointer.primary_pressed())
4956 {
4957 resource_panel.last_frame_mouse_status = Some((
4958 mouse_pos.into(),
4959 ClickAim::RightResize,
4960 [
4961 mouse_pos.x - position[0],
4962 mouse_pos.y - position[1],
4963 ],
4964 ))
4965 };
4966 if size[0] > resource_panel.min_size[0]
4967 && (resource_panel.max_size.is_none()
4968 || size[0] < resource_panel.max_size.unwrap()[0])
4969 {
4970 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4971 } else if resource_panel.max_size.is_some()
4972 && size[0] >= resource_panel.max_size.unwrap()[0]
4973 {
4974 ctx.set_cursor_icon(CursorIcon::ResizeWest);
4975 } else {
4976 ctx.set_cursor_icon(CursorIcon::ResizeEast);
4977 };
4978 }
4979 [true, false] => {
4980 if resource_panel.last_frame_mouse_status.is_none()
4981 && ui.input(|i| i.pointer.primary_pressed())
4982 {
4983 resource_panel.last_frame_mouse_status = Some((
4984 mouse_pos.into(),
4985 ClickAim::BottomResize,
4986 [
4987 mouse_pos.x - position[0],
4988 mouse_pos.y - position[1],
4989 ],
4990 ))
4991 };
4992 if size[1] > resource_panel.min_size[1]
4993 && (resource_panel.max_size.is_none()
4994 || size[1] < resource_panel.max_size.unwrap()[1])
4995 {
4996 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4997 } else if resource_panel.max_size.is_some()
4998 && size[1] >= resource_panel.max_size.unwrap()[1]
4999 {
5000 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5001 } else {
5002 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5003 };
5004 }
5005 [false, false] => {}
5006 }
5007 }
5008 [true, false, false, true] => {
5009 match [resource_panel.resizable[0], resource_panel.resizable[3]] {
5010 [true, true] => {
5011 if resource_panel.last_frame_mouse_status.is_none()
5012 && ui.input(|i| i.pointer.primary_pressed())
5013 {
5014 resource_panel.last_frame_mouse_status = Some((
5015 mouse_pos.into(),
5016 ClickAim::RightTopResize,
5017 [
5018 mouse_pos.x - position[0],
5019 mouse_pos.y - position[1],
5020 ],
5021 ))
5022 };
5023 if size[0] > resource_panel.min_size[0]
5024 && (resource_panel.max_size.is_none()
5025 || size[0] < resource_panel.max_size.unwrap()[0])
5026 || size[1] > resource_panel.min_size[1]
5027 && (resource_panel.max_size.is_none()
5028 || size[1]
5029 < resource_panel.max_size.unwrap()[1])
5030 {
5031 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5032 } else if resource_panel.max_size.is_some()
5033 && size[0] >= resource_panel.max_size.unwrap()[0]
5034 && size[1] >= resource_panel.max_size.unwrap()[1]
5035 {
5036 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5037 } else {
5038 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5039 };
5040 }
5041 [false, true] => {
5042 if resource_panel.last_frame_mouse_status.is_none()
5043 && ui.input(|i| i.pointer.primary_pressed())
5044 {
5045 resource_panel.last_frame_mouse_status = Some((
5046 mouse_pos.into(),
5047 ClickAim::RightResize,
5048 [
5049 mouse_pos.x - position[0],
5050 mouse_pos.y - position[1],
5051 ],
5052 ))
5053 };
5054 if size[0] > resource_panel.min_size[0]
5055 && (resource_panel.max_size.is_none()
5056 || size[0] < resource_panel.max_size.unwrap()[0])
5057 {
5058 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5059 } else if resource_panel.max_size.is_some()
5060 && size[0] >= resource_panel.max_size.unwrap()[0]
5061 {
5062 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5063 } else {
5064 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5065 };
5066 }
5067 [true, false] => {
5068 if resource_panel.last_frame_mouse_status.is_none()
5069 && ui.input(|i| i.pointer.primary_pressed())
5070 {
5071 resource_panel.last_frame_mouse_status = Some((
5072 mouse_pos.into(),
5073 ClickAim::TopResize,
5074 [
5075 mouse_pos.x - position[0],
5076 mouse_pos.y - position[1],
5077 ],
5078 ))
5079 };
5080 if size[1] > resource_panel.min_size[1]
5081 && (resource_panel.max_size.is_none()
5082 || size[1] < resource_panel.max_size.unwrap()[1])
5083 {
5084 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5085 } else if resource_panel.max_size.is_some()
5086 && size[1] >= resource_panel.max_size.unwrap()[1]
5087 {
5088 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5089 } else {
5090 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5091 };
5092 }
5093 [false, false] => {}
5094 }
5095 }
5096 [false, true, true, false] => {
5097 match [resource_panel.resizable[1], resource_panel.resizable[2]] {
5098 [true, true] => {
5099 if resource_panel.last_frame_mouse_status.is_none()
5100 && ui.input(|i| i.pointer.primary_pressed())
5101 {
5102 resource_panel.last_frame_mouse_status = Some((
5103 mouse_pos.into(),
5104 ClickAim::LeftBottomResize,
5105 [
5106 mouse_pos.x - position[0],
5107 mouse_pos.y - position[1],
5108 ],
5109 ))
5110 };
5111 if size[0] > resource_panel.min_size[0]
5112 && (resource_panel.max_size.is_none()
5113 || size[0] < resource_panel.max_size.unwrap()[0])
5114 || size[1] > resource_panel.min_size[1]
5115 && (resource_panel.max_size.is_none()
5116 || size[1]
5117 < resource_panel.max_size.unwrap()[1])
5118 {
5119 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5120 } else if resource_panel.max_size.is_some()
5121 && size[0] >= resource_panel.max_size.unwrap()[0]
5122 && size[1] >= resource_panel.max_size.unwrap()[1]
5123 {
5124 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5125 } else {
5126 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5127 };
5128 }
5129 [false, true] => {
5130 if resource_panel.last_frame_mouse_status.is_none()
5131 && ui.input(|i| i.pointer.primary_pressed())
5132 {
5133 resource_panel.last_frame_mouse_status = Some((
5134 mouse_pos.into(),
5135 ClickAim::LeftResize,
5136 [
5137 mouse_pos.x - position[0],
5138 mouse_pos.y - position[1],
5139 ],
5140 ))
5141 };
5142 if size[0] > resource_panel.min_size[0]
5143 && (resource_panel.max_size.is_none()
5144 || size[0] < resource_panel.max_size.unwrap()[0])
5145 {
5146 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5147 } else if resource_panel.max_size.is_some()
5148 && size[0] >= resource_panel.max_size.unwrap()[0]
5149 {
5150 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5151 } else {
5152 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5153 };
5154 }
5155 [true, false] => {
5156 if resource_panel.last_frame_mouse_status.is_none()
5157 && ui.input(|i| i.pointer.primary_pressed())
5158 {
5159 resource_panel.last_frame_mouse_status = Some((
5160 mouse_pos.into(),
5161 ClickAim::BottomResize,
5162 [
5163 mouse_pos.x - position[0],
5164 mouse_pos.y - position[1],
5165 ],
5166 ))
5167 };
5168 if size[1] > resource_panel.min_size[1]
5169 && (resource_panel.max_size.is_none()
5170 || size[1] < resource_panel.max_size.unwrap()[1])
5171 {
5172 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5173 } else if resource_panel.max_size.is_some()
5174 && size[1] >= resource_panel.max_size.unwrap()[1]
5175 {
5176 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5177 } else {
5178 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5179 };
5180 }
5181 [false, false] => {}
5182 }
5183 }
5184 _ => {}
5185 };
5186 resource_panel.last_frame_mouse_status =
5187 if resource_panel.last_frame_mouse_status.is_none()
5188 && rect.contains(mouse_pos)
5189 && ui.input(|i| i.pointer.primary_pressed())
5190 {
5191 Some((
5192 [mouse_pos.x, mouse_pos.y],
5193 ClickAim::Move,
5194 [mouse_pos.x - position[0], mouse_pos.y - position[1]],
5195 ))
5196 } else if resource_panel.last_frame_mouse_status.is_some()
5197 && !ui.input(|i| i.pointer.primary_released())
5198 {
5199 Some((
5200 [mouse_pos.x, mouse_pos.y],
5201 resource_panel.last_frame_mouse_status.unwrap().1,
5202 resource_panel.last_frame_mouse_status.unwrap().2,
5203 ))
5204 } else {
5205 None
5206 };
5207 let [x_scroll_delta, y_scroll_delta] =
5208 if resource_panel.use_smooth_scroll_delta {
5209 ui.input(|i| i.smooth_scroll_delta).into()
5210 } else {
5211 ui.input(|i| i.raw_scroll_delta).into()
5212 };
5213 if resource_panel.scroll_length_method[0].is_some()
5214 && x_scroll_delta != 0_f32
5215 && rect.contains(mouse_pos)
5216 {
5217 resource_panel.scrolled[0] = true;
5218 resource_panel.scroll_progress[0] = if resource_panel.scroll_progress[0]
5219 + -x_scroll_delta * resource_panel.scroll_sensitivity
5220 > resource_panel.scroll_length[0]
5221 {
5222 resource_panel.scroll_length[0]
5223 } else if resource_panel.scroll_progress[0]
5224 + -x_scroll_delta * resource_panel.scroll_sensitivity
5225 > 0_f32
5226 {
5227 resource_panel.scroll_progress[0]
5228 + -x_scroll_delta * resource_panel.scroll_sensitivity
5229 } else {
5230 0_f32
5231 };
5232 };
5233 if resource_panel.scroll_length_method[1].is_some()
5234 && y_scroll_delta != 0_f32
5235 && rect.contains(mouse_pos)
5236 {
5237 resource_panel.scrolled[1] = true;
5238 resource_panel.scroll_progress[1] = if resource_panel.scroll_progress[1]
5239 + -y_scroll_delta * resource_panel.scroll_sensitivity
5240 > resource_panel.scroll_length[1]
5241 {
5242 resource_panel.scroll_length[1]
5243 } else if resource_panel.scroll_progress[1]
5244 + -y_scroll_delta * resource_panel.scroll_sensitivity
5245 > 0_f32
5246 {
5247 resource_panel.scroll_progress[1]
5248 + -y_scroll_delta * resource_panel.scroll_sensitivity
5249 } else {
5250 0_f32
5251 };
5252 };
5253 };
5254 if let Some((mouse_pos, click_aim, offset)) =
5255 resource_panel.last_frame_mouse_status
5256 {
5257 match click_aim {
5258 ClickAim::LeftTopResize => {
5259 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5260 && (resource_panel.max_size.is_none()
5261 || position[0] - mouse_pos[0] + size[0]
5262 < resource_panel.max_size.unwrap()[0])
5263 {
5264 position_size_config.origin_size[0] +=
5265 position[0] - mouse_pos[0];
5266 position_size_config.origin_position[0] = mouse_pos[0];
5267 } else if resource_panel.max_size.is_some()
5268 && position[0] - mouse_pos[0] + size[0]
5269 >= resource_panel.max_size.unwrap()[0]
5270 {
5271 position_size_config.origin_position[0] -=
5272 resource_panel.max_size.unwrap()[0]
5273 - position_size_config.origin_size[0];
5274 position_size_config.origin_size[0] =
5275 resource_panel.max_size.unwrap()[0];
5276 } else {
5277 position_size_config.origin_position[0] += position_size_config
5278 .origin_size[0]
5279 - resource_panel.min_size[0];
5280 position_size_config.origin_size[0] =
5281 resource_panel.min_size[0];
5282 };
5283 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5284 && (resource_panel.max_size.is_none()
5285 || position[1] - mouse_pos[1] + size[1]
5286 < resource_panel.max_size.unwrap()[1])
5287 {
5288 position_size_config.origin_size[1] +=
5289 position[1] - mouse_pos[1];
5290 position_size_config.origin_position[1] = mouse_pos[1];
5291 } else if resource_panel.max_size.is_some()
5292 && position[1] - mouse_pos[1] + size[1]
5293 >= resource_panel.max_size.unwrap()[1]
5294 {
5295 position_size_config.origin_position[1] -=
5296 resource_panel.max_size.unwrap()[1]
5297 - position_size_config.origin_size[1];
5298 position_size_config.origin_size[1] =
5299 resource_panel.max_size.unwrap()[1];
5300 } else {
5301 position_size_config.origin_position[1] += position_size_config
5302 .origin_size[1]
5303 - resource_panel.min_size[1];
5304 position_size_config.origin_size[1] =
5305 resource_panel.min_size[1];
5306 };
5307 if size[0] > resource_panel.min_size[0]
5308 && (resource_panel.max_size.is_none()
5309 || size[0] < resource_panel.max_size.unwrap()[0])
5310 || size[1] > resource_panel.min_size[1]
5311 && (resource_panel.max_size.is_none()
5312 || size[1] < resource_panel.max_size.unwrap()[1])
5313 {
5314 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5315 } else if resource_panel.max_size.is_some()
5316 && size[0] >= resource_panel.max_size.unwrap()[0]
5317 && size[1] >= resource_panel.max_size.unwrap()[1]
5318 {
5319 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
5320 } else {
5321 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
5322 };
5323 }
5324 ClickAim::RightBottomResize => {
5325 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5326 && (resource_panel.max_size.is_none()
5327 || mouse_pos[0] - position[0]
5328 < resource_panel.max_size.unwrap()[0])
5329 {
5330 position_size_config.origin_size[0] =
5331 mouse_pos[0] - position[0];
5332 } else if resource_panel.max_size.is_some()
5333 && mouse_pos[0] - position[0]
5334 >= resource_panel.max_size.unwrap()[0]
5335 {
5336 position_size_config.origin_size[0] =
5337 resource_panel.max_size.unwrap()[0];
5338 } else {
5339 position_size_config.origin_size[0] =
5340 resource_panel.min_size[0];
5341 };
5342 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5343 && (resource_panel.max_size.is_none()
5344 || mouse_pos[1] - position[1]
5345 < resource_panel.max_size.unwrap()[1])
5346 {
5347 position_size_config.origin_size[1] =
5348 mouse_pos[1] - position[1];
5349 } else if resource_panel.max_size.is_some()
5350 && mouse_pos[1] - position[1]
5351 >= resource_panel.max_size.unwrap()[1]
5352 {
5353 position_size_config.origin_size[1] =
5354 resource_panel.max_size.unwrap()[1];
5355 } else {
5356 position_size_config.origin_size[1] =
5357 resource_panel.min_size[1];
5358 };
5359 if size[0] > resource_panel.min_size[0]
5360 && (resource_panel.max_size.is_none()
5361 || size[0] < resource_panel.max_size.unwrap()[0])
5362 || size[1] > resource_panel.min_size[1]
5363 && (resource_panel.max_size.is_none()
5364 || size[1] < resource_panel.max_size.unwrap()[1])
5365 {
5366 ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5367 } else if resource_panel.max_size.is_some()
5368 && size[0] >= resource_panel.max_size.unwrap()[0]
5369 && size[1] >= resource_panel.max_size.unwrap()[1]
5370 {
5371 ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
5372 } else {
5373 ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
5374 };
5375 }
5376 ClickAim::RightTopResize => {
5377 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5378 && (resource_panel.max_size.is_none()
5379 || mouse_pos[0] - position[0]
5380 < resource_panel.max_size.unwrap()[0])
5381 {
5382 position_size_config.origin_size[0] =
5383 mouse_pos[0] - position[0];
5384 } else if resource_panel.max_size.is_some()
5385 && mouse_pos[0] - position[0]
5386 >= resource_panel.max_size.unwrap()[0]
5387 {
5388 position_size_config.origin_size[0] =
5389 resource_panel.max_size.unwrap()[0];
5390 } else {
5391 position_size_config.origin_size[0] =
5392 resource_panel.min_size[0];
5393 };
5394 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5395 && (resource_panel.max_size.is_none()
5396 || position[1] - mouse_pos[1] + size[1]
5397 < resource_panel.max_size.unwrap()[1])
5398 {
5399 position_size_config.origin_size[1] +=
5400 position[1] - mouse_pos[1];
5401 position_size_config.origin_position[1] = mouse_pos[1];
5402 } else if resource_panel.max_size.is_some()
5403 && position[1] - mouse_pos[1] + size[1]
5404 >= resource_panel.max_size.unwrap()[1]
5405 {
5406 position_size_config.origin_position[1] -=
5407 resource_panel.max_size.unwrap()[1]
5408 - position_size_config.origin_size[1];
5409 position_size_config.origin_size[1] =
5410 resource_panel.max_size.unwrap()[1];
5411 } else {
5412 position_size_config.origin_position[1] += position_size_config
5413 .origin_size[1]
5414 - resource_panel.min_size[1];
5415 position_size_config.origin_size[1] =
5416 resource_panel.min_size[1];
5417 };
5418 if size[0] > resource_panel.min_size[0]
5419 && (resource_panel.max_size.is_none()
5420 || size[0] < resource_panel.max_size.unwrap()[0])
5421 || size[1] > resource_panel.min_size[1]
5422 && (resource_panel.max_size.is_none()
5423 || size[1] < resource_panel.max_size.unwrap()[1])
5424 {
5425 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5426 } else if resource_panel.max_size.is_some()
5427 && size[0] >= resource_panel.max_size.unwrap()[0]
5428 && size[1] >= resource_panel.max_size.unwrap()[1]
5429 {
5430 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5431 } else {
5432 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5433 };
5434 }
5435 ClickAim::LeftBottomResize => {
5436 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5437 && (resource_panel.max_size.is_none()
5438 || position[0] - mouse_pos[0] + size[0]
5439 < resource_panel.max_size.unwrap()[0])
5440 {
5441 position_size_config.origin_size[0] +=
5442 position[0] - mouse_pos[0];
5443 position_size_config.origin_position[0] = mouse_pos[0];
5444 } else if resource_panel.max_size.is_some()
5445 && position[0] - mouse_pos[0] + size[0]
5446 >= resource_panel.max_size.unwrap()[0]
5447 {
5448 position_size_config.origin_position[0] -=
5449 resource_panel.max_size.unwrap()[0]
5450 - position_size_config.origin_size[0];
5451 position_size_config.origin_size[0] =
5452 resource_panel.max_size.unwrap()[0];
5453 } else {
5454 position_size_config.origin_position[0] += position_size_config
5455 .origin_size[0]
5456 - resource_panel.min_size[0];
5457 position_size_config.origin_size[0] =
5458 resource_panel.min_size[0];
5459 };
5460 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5461 && (resource_panel.max_size.is_none()
5462 || mouse_pos[1] - position[1]
5463 < resource_panel.max_size.unwrap()[1])
5464 {
5465 position_size_config.origin_size[1] =
5466 mouse_pos[1] - position[1];
5467 } else if resource_panel.max_size.is_some()
5468 && mouse_pos[1] - position[1]
5469 >= resource_panel.max_size.unwrap()[1]
5470 {
5471 position_size_config.origin_size[1] =
5472 resource_panel.max_size.unwrap()[1];
5473 } else {
5474 position_size_config.origin_size[1] =
5475 resource_panel.min_size[1];
5476 };
5477 if size[0] > resource_panel.min_size[0]
5478 && (resource_panel.max_size.is_none()
5479 || size[0] < resource_panel.max_size.unwrap()[0])
5480 || size[1] > resource_panel.min_size[1]
5481 && (resource_panel.max_size.is_none()
5482 || size[1] < resource_panel.max_size.unwrap()[1])
5483 {
5484 ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5485 } else if resource_panel.max_size.is_some()
5486 && size[0] >= resource_panel.max_size.unwrap()[0]
5487 && size[1] >= resource_panel.max_size.unwrap()[1]
5488 {
5489 ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5490 } else {
5491 ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5492 };
5493 }
5494 ClickAim::TopResize => {
5495 if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5496 && (resource_panel.max_size.is_none()
5497 || position[1] - mouse_pos[1] + size[1]
5498 < resource_panel.max_size.unwrap()[1])
5499 {
5500 position_size_config.origin_size[1] +=
5501 position[1] - mouse_pos[1];
5502 position_size_config.origin_position[1] = mouse_pos[1];
5503 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5504 } else if resource_panel.max_size.is_some()
5505 && position[1] - mouse_pos[1] + size[1]
5506 >= resource_panel.max_size.unwrap()[1]
5507 {
5508 position_size_config.origin_position[1] -=
5509 resource_panel.max_size.unwrap()[1]
5510 - position_size_config.origin_size[1];
5511 position_size_config.origin_size[1] =
5512 resource_panel.max_size.unwrap()[1];
5513 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5514 } else {
5515 position_size_config.origin_position[1] += position_size_config
5516 .origin_size[1]
5517 - resource_panel.min_size[1];
5518 position_size_config.origin_size[1] =
5519 resource_panel.min_size[1];
5520 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5521 };
5522 }
5523 ClickAim::BottomResize => {
5524 if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5525 && (resource_panel.max_size.is_none()
5526 || mouse_pos[1] - position[1]
5527 < resource_panel.max_size.unwrap()[1])
5528 {
5529 position_size_config.origin_size[1] =
5530 mouse_pos[1] - position[1];
5531 ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5532 } else if resource_panel.max_size.is_some()
5533 && mouse_pos[1] - position[1]
5534 >= resource_panel.max_size.unwrap()[1]
5535 {
5536 position_size_config.origin_size[1] =
5537 resource_panel.max_size.unwrap()[1];
5538 ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5539 } else {
5540 position_size_config.origin_size[1] =
5541 resource_panel.min_size[1];
5542 ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5543 };
5544 }
5545 ClickAim::LeftResize => {
5546 if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5547 && (resource_panel.max_size.is_none()
5548 || position[0] - mouse_pos[0] + size[0]
5549 < resource_panel.max_size.unwrap()[0])
5550 {
5551 position_size_config.origin_size[0] +=
5552 position[0] - mouse_pos[0];
5553 position_size_config.origin_position[0] = mouse_pos[0];
5554 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5555 } else if resource_panel.max_size.is_some()
5556 && position[0] - mouse_pos[0] + size[0]
5557 >= resource_panel.max_size.unwrap()[0]
5558 {
5559 position_size_config.origin_position[0] -=
5560 resource_panel.max_size.unwrap()[0]
5561 - position_size_config.origin_size[0];
5562 position_size_config.origin_size[0] =
5563 resource_panel.max_size.unwrap()[0];
5564 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5565 } else {
5566 position_size_config.origin_position[0] += position_size_config
5567 .origin_size[0]
5568 - resource_panel.min_size[0];
5569 position_size_config.origin_size[0] =
5570 resource_panel.min_size[0];
5571 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5572 };
5573 }
5574 ClickAim::RightResize => {
5575 if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5576 && (resource_panel.max_size.is_none()
5577 || mouse_pos[0] - position[0]
5578 < resource_panel.max_size.unwrap()[0])
5579 {
5580 position_size_config.origin_size[0] =
5581 mouse_pos[0] - position[0];
5582 ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5583 } else if resource_panel.max_size.is_some()
5584 && mouse_pos[0] - position[0]
5585 >= resource_panel.max_size.unwrap()[0]
5586 {
5587 position_size_config.origin_size[0] =
5588 resource_panel.max_size.unwrap()[0];
5589 ctx.set_cursor_icon(CursorIcon::ResizeWest);
5590 } else {
5591 position_size_config.origin_size[0] =
5592 resource_panel.min_size[0];
5593 ctx.set_cursor_icon(CursorIcon::ResizeEast);
5594 };
5595 }
5596 ClickAim::Move => {
5597 if resource_panel.movable[0] {
5598 position_size_config.origin_position[0] =
5599 mouse_pos[0] - offset[0];
5600 };
5601 if resource_panel.movable[1] {
5602 position_size_config.origin_position[1] =
5603 mouse_pos[1] - offset[1];
5604 };
5605 }
5606 };
5607 };
5608 [position, size] = self.position_size_processor(position_size_config, ctx);
5609 let background_type = match background.background_type.clone() {
5610 BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
5611 config.position_size_config(Some(position_size_config)),
5612 ),
5613 BackgroundType::Image(config) => BackgroundType::Image(
5614 config.position_size_config(Some(position_size_config)),
5615 ),
5616 };
5617 self.replace_resource(
5618 &format!("{name}Background"),
5619 background.clone().background_type(&background_type).clone(),
5620 )?;
5621 self.use_resource(
5622 &format!("{name}Background"),
5623 "rust_constructor::Background",
5624 ui,
5625 ctx,
5626 )?;
5627 let mut resource_point_list: Vec<([f32; 2], [f32; 2], [bool; 2])> = Vec::new();
5628 let mut use_resource_list = Vec::new();
5629 let mut replace_resource_list = Vec::new();
5630 for rcr in &self.rust_constructor_resource {
5631 if self
5632 .basic_front_resource_list
5633 .contains(&rcr.id.discern_type)
5634 && let Some(panel_name) =
5635 self.get_tag("panel_name", &rcr.content.display_tags())
5636 && panel_name.1 == name
5637 {
5638 if let [Some(citer_name), Some(citer_type)] = [
5639 self.get_tag("citer_name", &rcr.content.display_tags()),
5640 self.get_tag("citer_type", &rcr.content.display_tags()),
5641 ] {
5642 if !use_resource_list
5643 .iter()
5644 .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
5645 {
5646 use_resource_list.push([citer_name.1, citer_type.1]);
5647 };
5648 } else if !use_resource_list
5649 .iter()
5650 .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
5651 {
5652 use_resource_list
5653 .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
5654 };
5655 let mut basic_front_resource: Box<dyn BasicFrontResource> = match &*rcr
5656 .id
5657 .discern_type
5658 {
5659 "rust_constructor::Image" => Box::new(
5660 rcr.content
5661 .as_any()
5662 .downcast_ref::<Image>()
5663 .unwrap()
5664 .clone(),
5665 ),
5666 "rust_constructor::Text" => Box::new(
5667 rcr.content.as_any().downcast_ref::<Text>().unwrap().clone(),
5668 ),
5669 "rust_constructor::CustomRect" => Box::new(
5670 rcr.content
5671 .as_any()
5672 .downcast_ref::<CustomRect>()
5673 .unwrap()
5674 .clone(),
5675 ),
5676 _ => {
5677 unreachable!()
5678 }
5679 };
5680 let enable_scrolling = [
5681 self.get_tag("disable_x_scrolling", &rcr.content.display_tags())
5682 .is_none(),
5683 self.get_tag("disable_y_scrolling", &rcr.content.display_tags())
5684 .is_none(),
5685 ];
5686 let offset = basic_front_resource.display_position_size_config().offset;
5687 basic_front_resource.modify_position_size_config(
5688 basic_front_resource.display_position_size_config().offset(
5689 if enable_scrolling[0] {
5690 -resource_panel.scroll_progress[0]
5691 } else {
5692 offset[0]
5693 },
5694 if enable_scrolling[1] {
5695 -resource_panel.scroll_progress[1]
5696 } else {
5697 offset[1]
5698 },
5699 ),
5700 );
5701 let mut layout = resource_panel.overall_layout;
5702 for custom_layout in &resource_panel.custom_layout {
5703 match custom_layout {
5704 CustomPanelLayout::Id(layout_id, panel_layout) => {
5705 if rcr.id.cmp(layout_id) == Ordering::Equal {
5706 layout = *panel_layout;
5707 break;
5708 };
5709 }
5710 CustomPanelLayout::Type(layout_type, panel_layout) => {
5711 if *layout_type == rcr.id.discern_type {
5712 layout = *panel_layout;
5713 }
5714 }
5715 };
5716 }
5717 if enable_scrolling.contains(&false) {
5718 layout.panel_margin = match layout.panel_margin {
5719 PanelMargin::Horizontal([top, bottom, left, right], _) => {
5720 PanelMargin::None([top, bottom, left, right], false)
5721 }
5722 PanelMargin::Vertical([top, bottom, left, right], _) => {
5723 PanelMargin::None([top, bottom, left, right], false)
5724 }
5725 PanelMargin::None([_, _, _, _], _) => layout.panel_margin,
5726 };
5727 };
5728 match layout.panel_margin {
5729 PanelMargin::Vertical(
5730 [top, bottom, left, right],
5731 move_to_bottom,
5732 ) => {
5733 let mut modify_y = 0_f32;
5734 let [default_x_position, default_y_position] =
5735 match layout.panel_location {
5736 PanelLocation::Absolute([x, y]) => {
5737 [position[0] + x, position[1] + y]
5738 }
5739 PanelLocation::Relative([x, y]) => [
5740 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5741 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5742 ],
5743 };
5744 let default_x_position = match basic_front_resource
5745 .display_position_size_config()
5746 .display_method
5747 .0
5748 {
5749 HorizontalAlign::Left => default_x_position,
5750 HorizontalAlign::Center => {
5751 default_x_position
5752 - basic_front_resource.display_size()[0] / 2.0
5753 }
5754 HorizontalAlign::Right => {
5755 default_x_position
5756 - basic_front_resource.display_size()[0]
5757 }
5758 };
5759 let default_y_position = match basic_front_resource
5760 .display_position_size_config()
5761 .display_method
5762 .1
5763 {
5764 VerticalAlign::Top => default_y_position,
5765 VerticalAlign::Center => {
5766 default_y_position
5767 - basic_front_resource.display_size()[1] / 2.0
5768 }
5769 VerticalAlign::Bottom => {
5770 default_y_position
5771 - basic_front_resource.display_size()[1]
5772 }
5773 };
5774 for point in &resource_point_list {
5775 if default_x_position - left < point.1[0]
5776 && default_y_position - top + modify_y < point.1[1]
5777 && default_x_position
5778 + basic_front_resource.display_size()[0]
5779 + right
5780 > point.0[0]
5781 && default_y_position
5782 + basic_front_resource.display_size()[1]
5783 + bottom
5784 + modify_y
5785 > point.0[1]
5786 {
5787 if move_to_bottom
5788 && point.1[1] - default_y_position + top > modify_y
5789 {
5790 modify_y = point.1[1] - default_y_position + top;
5791 } else if !move_to_bottom
5792 && point.0[1]
5793 - default_y_position
5794 - basic_front_resource.display_size()[1]
5795 - bottom
5796 < modify_y
5797 {
5798 modify_y = point.0[1]
5799 - default_y_position
5800 - basic_front_resource.display_size()[1]
5801 - bottom;
5802 };
5803 };
5804 }
5805 let real_x_position = match basic_front_resource
5806 .display_position_size_config()
5807 .display_method
5808 .0
5809 {
5810 HorizontalAlign::Left => default_x_position,
5811 HorizontalAlign::Center => {
5812 default_x_position
5813 + basic_front_resource.display_size()[0] / 2.0
5814 }
5815 HorizontalAlign::Right => {
5816 default_x_position
5817 + basic_front_resource.display_size()[0]
5818 }
5819 };
5820 let real_y_position = match basic_front_resource
5821 .display_position_size_config()
5822 .display_method
5823 .1
5824 {
5825 VerticalAlign::Top => default_y_position + modify_y,
5826 VerticalAlign::Center => {
5827 default_y_position
5828 + modify_y
5829 + basic_front_resource.display_size()[1] / 2.0
5830 }
5831 VerticalAlign::Bottom => {
5832 default_y_position
5833 + modify_y
5834 + basic_front_resource.display_size()[1]
5835 }
5836 };
5837 basic_front_resource.modify_position_size_config(
5838 basic_front_resource
5839 .display_position_size_config()
5840 .origin_position(real_x_position, real_y_position),
5841 );
5842 replace_resource_list.push((
5843 basic_front_resource.display_position_size_config(),
5844 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
5845 ));
5846 resource_point_list.push((
5847 [real_x_position - left, real_y_position - top],
5848 [
5849 real_x_position
5850 + basic_front_resource.display_size()[0]
5851 + right,
5852 real_y_position
5853 + basic_front_resource.display_size()[1]
5854 + bottom,
5855 ],
5856 enable_scrolling,
5857 ));
5858 }
5859 PanelMargin::Horizontal(
5860 [top, bottom, left, right],
5861 move_to_right,
5862 ) => {
5863 let mut modify_x = 0_f32;
5864 let [default_x_position, default_y_position] =
5865 match layout.panel_location {
5866 PanelLocation::Absolute([x, y]) => {
5867 [position[0] + x, position[1] + y]
5868 }
5869 PanelLocation::Relative([x, y]) => [
5870 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5871 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5872 ],
5873 };
5874 let default_x_position = match basic_front_resource
5875 .display_position_size_config()
5876 .display_method
5877 .0
5878 {
5879 HorizontalAlign::Left => default_x_position,
5880 HorizontalAlign::Center => {
5881 default_x_position
5882 - basic_front_resource.display_size()[0] / 2.0
5883 }
5884 HorizontalAlign::Right => {
5885 default_x_position
5886 - basic_front_resource.display_size()[0]
5887 }
5888 };
5889 let default_y_position = match basic_front_resource
5890 .display_position_size_config()
5891 .display_method
5892 .1
5893 {
5894 VerticalAlign::Top => default_y_position,
5895 VerticalAlign::Center => {
5896 default_y_position
5897 - basic_front_resource.display_size()[1] / 2.0
5898 }
5899 VerticalAlign::Bottom => {
5900 default_y_position
5901 - basic_front_resource.display_size()[1]
5902 }
5903 };
5904 for point in &resource_point_list {
5905 if default_x_position - left + modify_x < point.1[0]
5906 && default_y_position - top < point.1[1]
5907 && default_x_position
5908 + basic_front_resource.display_size()[0]
5909 + right
5910 + modify_x
5911 > point.0[0]
5912 && default_y_position
5913 + basic_front_resource.display_size()[1]
5914 + bottom
5915 > point.0[1]
5916 {
5917 if move_to_right
5918 && point.1[0] - default_x_position + left > modify_x
5919 {
5920 modify_x = point.1[0] - default_x_position + left;
5921 } else if !move_to_right
5922 && point.0[0]
5923 - default_x_position
5924 - basic_front_resource.display_size()[0]
5925 - right
5926 < modify_x
5927 {
5928 modify_x = point.0[0]
5929 - default_x_position
5930 - basic_front_resource.display_size()[0]
5931 - right;
5932 };
5933 };
5934 }
5935 let real_x_position = match basic_front_resource
5936 .display_position_size_config()
5937 .display_method
5938 .0
5939 {
5940 HorizontalAlign::Left => default_x_position + modify_x,
5941 HorizontalAlign::Center => {
5942 default_x_position
5943 + modify_x
5944 + basic_front_resource.display_size()[0] / 2.0
5945 }
5946 HorizontalAlign::Right => {
5947 default_x_position
5948 + modify_x
5949 + basic_front_resource.display_size()[0]
5950 }
5951 };
5952 let real_y_position = match basic_front_resource
5953 .display_position_size_config()
5954 .display_method
5955 .1
5956 {
5957 VerticalAlign::Top => default_y_position,
5958 VerticalAlign::Center => {
5959 default_y_position
5960 + basic_front_resource.display_size()[1] / 2.0
5961 }
5962 VerticalAlign::Bottom => {
5963 default_y_position
5964 + basic_front_resource.display_size()[1]
5965 }
5966 };
5967 basic_front_resource.modify_position_size_config(
5968 basic_front_resource
5969 .display_position_size_config()
5970 .origin_position(real_x_position, real_y_position),
5971 );
5972 replace_resource_list.push((
5973 basic_front_resource.display_position_size_config(),
5974 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
5975 ));
5976 resource_point_list.push((
5977 [real_x_position - left, real_y_position - top],
5978 [
5979 real_x_position
5980 + basic_front_resource.display_size()[0]
5981 + right,
5982 real_y_position
5983 + basic_front_resource.display_size()[1]
5984 + bottom,
5985 ],
5986 enable_scrolling,
5987 ));
5988 }
5989 PanelMargin::None([top, bottom, left, right], influence_layout) => {
5990 let [default_x_position, default_y_position] =
5991 match layout.panel_location {
5992 PanelLocation::Absolute([x, y]) => {
5993 [position[0] + x, position[1] + y]
5994 }
5995 PanelLocation::Relative([x, y]) => [
5996 position[0] + (size[0] / x[1] as f32 * x[0] as f32),
5997 position[1] + (size[1] / y[1] as f32 * y[0] as f32),
5998 ],
5999 };
6000 basic_front_resource.modify_position_size_config(
6001 basic_front_resource
6002 .display_position_size_config()
6003 .origin_position(
6004 default_x_position,
6005 default_y_position,
6006 ),
6007 );
6008 replace_resource_list.push((
6009 basic_front_resource.display_position_size_config(),
6010 [rcr.id.name.clone(), rcr.id.discern_type.clone()],
6011 ));
6012 if influence_layout {
6013 resource_point_list.push((
6014 [default_x_position - left, default_y_position - top],
6015 [
6016 default_x_position
6017 + basic_front_resource.display_size()[0]
6018 + right,
6019 default_y_position
6020 + basic_front_resource.display_size()[1]
6021 + bottom,
6022 ],
6023 enable_scrolling,
6024 ));
6025 };
6026 }
6027 };
6028 };
6029 }
6030 for (new_position_size_config, [name, discern_type]) in replace_resource_list {
6031 match &*discern_type {
6032 "rust_constructor::CustomRect" => {
6033 let mut custom_rect = self
6034 .get_resource::<CustomRect>(&name, &discern_type)?
6035 .clone();
6036 custom_rect.basic_front_resource_config.position_size_config =
6037 new_position_size_config;
6038 custom_rect.basic_front_resource_config.clip_rect =
6039 Some(position_size_config);
6040 self.replace_resource(&name, custom_rect)?;
6041 }
6042 "rust_constructor::Image" => {
6043 let mut image =
6044 self.get_resource::<Image>(&name, &discern_type)?.clone();
6045 image.basic_front_resource_config.position_size_config =
6046 new_position_size_config;
6047 image.basic_front_resource_config.clip_rect =
6048 Some(position_size_config);
6049 self.replace_resource(&name, image)?;
6050 }
6051 "rust_constructor::Text" => {
6052 let mut text =
6053 self.get_resource::<Text>(&name, &discern_type)?.clone();
6054 text.basic_front_resource_config.position_size_config =
6055 new_position_size_config;
6056 text.basic_front_resource_config.clip_rect =
6057 Some(position_size_config);
6058 self.replace_resource(&name, text)?;
6059 }
6060 _ => unreachable!(),
6061 }
6062 }
6063 for info in use_resource_list {
6064 self.use_resource(&info[0], &info[1], ui, ctx)?;
6065 }
6066 let mut resource_length = [None, None];
6067 for point in resource_point_list {
6068 resource_length = [
6069 if resource_length[0].is_none()
6070 || resource_length[0].is_some()
6071 && point.1[0] > resource_length[0].unwrap()
6072 && point.2[0]
6073 {
6074 Some(point.1[0])
6075 } else {
6076 resource_length[0]
6077 },
6078 if resource_length[1].is_none()
6079 || resource_length[1].is_some()
6080 && point.1[1] > resource_length[1].unwrap()
6081 && point.2[1]
6082 {
6083 Some(point.1[1])
6084 } else {
6085 resource_length[1]
6086 },
6087 ]
6088 }
6089 if let Some(horizontal_scroll_length_method) =
6090 resource_panel.scroll_length_method[0]
6091 {
6092 resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
6093 ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6094 ScrollLengthMethod::AutoFit => {
6095 if let Some(max) = resource_length[0] {
6096 let width = max - position[0];
6097 if width - size[0] > 0_f32 {
6098 width - size[0]
6099 } else {
6100 0_f32
6101 }
6102 } else {
6103 0_f32
6104 }
6105 }
6106 };
6107 resource_panel.scroll_progress[0] = if resource_panel.scroll_progress[0]
6108 > resource_panel.scroll_length[0]
6109 {
6110 resource_panel.scroll_length[0]
6111 } else {
6112 resource_panel.scroll_progress[0]
6113 };
6114 };
6115 if let Some(vertical_scroll_length_method) =
6116 resource_panel.scroll_length_method[1]
6117 {
6118 resource_panel.scroll_length[1] = match vertical_scroll_length_method {
6119 ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6120 ScrollLengthMethod::AutoFit => {
6121 if let Some(max) = resource_length[1] {
6122 let height = max - position[1];
6123 if height - size[1] > 0_f32 {
6124 height - size[1]
6125 } else {
6126 0_f32
6127 }
6128 } else {
6129 0_f32
6130 }
6131 }
6132 };
6133 resource_panel.scroll_progress[1] = if resource_panel.scroll_progress[1]
6134 > resource_panel.scroll_length[1]
6135 {
6136 resource_panel.scroll_length[1]
6137 } else {
6138 resource_panel.scroll_progress[1]
6139 };
6140 };
6141 match resource_panel.scroll_bar_display_method {
6142 ScrollBarDisplayMethod::Always(ref config, margin, width) => {
6143 let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6144 (size[0] - margin[0] * 2_f32)
6145 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6146 } else {
6147 (size[0] - width - margin[1] - margin[0] * 2_f32)
6148 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6149 };
6150 let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6151 position[0]
6152 + margin[0]
6153 + (size[0] - margin[0] * 2_f32 - line_length)
6154 * (resource_panel.scroll_progress[0]
6155 / resource_panel.scroll_length[0])
6156 } else {
6157 position[0]
6158 + margin[0]
6159 + (size[0]
6160 - margin[0] * 2_f32
6161 - width
6162 - margin[1]
6163 - line_length)
6164 * (resource_panel.scroll_progress[0]
6165 / resource_panel.scroll_length[0])
6166 };
6167 self.replace_resource(
6168 &format!("{name}XScroll"),
6169 background.clone().background_type(&match config.clone() {
6170 BackgroundType::CustomRect(config) => {
6171 BackgroundType::CustomRect(
6172 config.position_size_config(Some(
6173 PositionSizeConfig::default()
6174 .display_method(
6175 HorizontalAlign::Left,
6176 VerticalAlign::Bottom,
6177 )
6178 .origin_position(
6179 line_position,
6180 position[1] + size[1] - margin[1],
6181 )
6182 .origin_size(line_length, width),
6183 )),
6184 )
6185 }
6186 BackgroundType::Image(config) => BackgroundType::Image(
6187 config.position_size_config(Some(
6188 PositionSizeConfig::default()
6189 .display_method(
6190 HorizontalAlign::Left,
6191 VerticalAlign::Bottom,
6192 )
6193 .origin_position(
6194 line_position,
6195 position[1] + size[1] - margin[1],
6196 )
6197 .origin_size(line_length, width),
6198 )),
6199 ),
6200 }),
6201 )?;
6202 self.use_resource(
6203 &format!("{name}XScroll"),
6204 "rust_constructor::Background",
6205 ui,
6206 ctx,
6207 )?;
6208 let line_length = if resource_panel.scroll_length[0] == 0_f32 {
6209 (size[1] - margin[0] * 2_f32)
6210 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6211 } else {
6212 (size[1] - width - margin[1] - margin[0] * 2_f32)
6213 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6214 };
6215 let line_position = if resource_panel.scroll_length[0] == 0_f32 {
6216 position[1]
6217 + margin[0]
6218 + (size[1] - margin[0] * 2_f32 - line_length)
6219 * (resource_panel.scroll_progress[1]
6220 / resource_panel.scroll_length[1])
6221 } else {
6222 position[1]
6223 + margin[0]
6224 + (size[1]
6225 - margin[0] * 2_f32
6226 - width
6227 - margin[1]
6228 - line_length)
6229 * (resource_panel.scroll_progress[1]
6230 / resource_panel.scroll_length[1])
6231 };
6232 self.replace_resource(
6233 &format!("{name}YScroll"),
6234 background.background_type(&match config.clone() {
6235 BackgroundType::CustomRect(config) => {
6236 BackgroundType::CustomRect(
6237 config.position_size_config(Some(
6238 PositionSizeConfig::default()
6239 .display_method(
6240 HorizontalAlign::Right,
6241 VerticalAlign::Top,
6242 )
6243 .origin_position(
6244 position[0] + size[0] - margin[1],
6245 line_position,
6246 )
6247 .origin_size(width, line_length),
6248 )),
6249 )
6250 }
6251 BackgroundType::Image(config) => BackgroundType::Image(
6252 config.position_size_config(Some(
6253 PositionSizeConfig::default()
6254 .display_method(
6255 HorizontalAlign::Right,
6256 VerticalAlign::Top,
6257 )
6258 .origin_position(
6259 position[0] + size[0] - margin[1],
6260 line_position,
6261 )
6262 .origin_size(width, line_length),
6263 )),
6264 ),
6265 }),
6266 )?;
6267 self.use_resource(
6268 &format!("{name}YScroll"),
6269 "rust_constructor::Background",
6270 ui,
6271 ctx,
6272 )?;
6273 }
6274 ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
6275 resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
6276 self.reset_split_time(&format!("{name}ScrollBarXAlphaStart",))?;
6277 255
6278 } else if self.timer.now_time
6279 - self.get_split_time(&format!("{name}ScrollBarXAlphaStart",))?[0]
6280 >= 1_f32
6281 && self.timer.now_time
6282 - self.get_split_time(&format!("{name}ScrollBarXAlpha",))?[0]
6283 >= self.tick_interval
6284 {
6285 self.reset_split_time(&format!("{name}ScrollBarXAlpha",))?;
6286 resource_panel.scroll_bar_alpha[0].saturating_sub(10)
6287 } else {
6288 resource_panel.scroll_bar_alpha[0]
6289 };
6290 resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
6291 self.reset_split_time(&format!("{name}ScrollBarYAlphaStart",))?;
6292 255
6293 } else if self.timer.now_time
6294 - self.get_split_time(&format!("{name}ScrollBarYAlphaStart",))?[0]
6295 >= 1_f32
6296 && self.timer.now_time
6297 - self.get_split_time(&format!("{name}ScrollBarYAlpha",))?[0]
6298 >= self.tick_interval
6299 {
6300 self.reset_split_time(&format!("{name}ScrollBarYAlpha",))?;
6301 resource_panel.scroll_bar_alpha[1].saturating_sub(10)
6302 } else {
6303 resource_panel.scroll_bar_alpha[1]
6304 };
6305 let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6306 (size[0] - margin[0] * 2_f32)
6307 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6308 } else {
6309 (size[0] - width - margin[1] - margin[0] * 2_f32)
6310 * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6311 };
6312 let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6313 position[0]
6314 + margin[0]
6315 + (size[0] - margin[0] * 2_f32 - line_length)
6316 * (resource_panel.scroll_progress[0]
6317 / resource_panel.scroll_length[0])
6318 } else {
6319 position[0]
6320 + margin[0]
6321 + (size[0]
6322 - margin[0] * 2_f32
6323 - width
6324 - margin[1]
6325 - line_length)
6326 * (resource_panel.scroll_progress[0]
6327 / resource_panel.scroll_length[0])
6328 };
6329 self.replace_resource(
6330 &format!("{name}XScroll"),
6331 background.clone().background_type(&match config.clone() {
6332 BackgroundType::CustomRect(config) => {
6333 BackgroundType::CustomRect(
6334 config
6335 .position_size_config(Some(
6336 PositionSizeConfig::default()
6337 .display_method(
6338 HorizontalAlign::Left,
6339 VerticalAlign::Bottom,
6340 )
6341 .origin_position(
6342 line_position,
6343 position[1] + size[1] - margin[1],
6344 )
6345 .origin_size(line_length, width),
6346 ))
6347 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6348 .border_alpha(Some(
6349 resource_panel.scroll_bar_alpha[0],
6350 )),
6351 )
6352 }
6353 BackgroundType::Image(config) => BackgroundType::Image(
6354 config
6355 .position_size_config(Some(
6356 PositionSizeConfig::default()
6357 .display_method(
6358 HorizontalAlign::Left,
6359 VerticalAlign::Bottom,
6360 )
6361 .origin_position(
6362 line_position,
6363 position[1] + size[1] - margin[1],
6364 )
6365 .origin_size(line_length, width),
6366 ))
6367 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6368 .background_alpha(Some(
6369 resource_panel.scroll_bar_alpha[0],
6370 ))
6371 .overlay_alpha(Some(
6372 resource_panel.scroll_bar_alpha[0],
6373 )),
6374 ),
6375 }),
6376 )?;
6377 self.use_resource(
6378 &format!("{name}XScroll"),
6379 "rust_constructor::Background",
6380 ui,
6381 ctx,
6382 )?;
6383 let line_length = if resource_panel.scroll_length[0] == 0_f32 {
6384 (size[1] - margin[0] * 2_f32)
6385 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6386 } else {
6387 (size[1] - width - margin[1] - margin[0] * 2_f32)
6388 * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6389 };
6390 let line_position = if resource_panel.scroll_length[0] == 0_f32 {
6391 position[1]
6392 + margin[0]
6393 + (size[1] - margin[0] * 2_f32 - line_length)
6394 * (resource_panel.scroll_progress[1]
6395 / resource_panel.scroll_length[1])
6396 } else {
6397 position[1]
6398 + margin[0]
6399 + (size[1]
6400 - margin[0] * 2_f32
6401 - width
6402 - margin[1]
6403 - line_length)
6404 * (resource_panel.scroll_progress[1]
6405 / resource_panel.scroll_length[1])
6406 };
6407 self.replace_resource(
6408 &format!("{name}YScroll"),
6409 background.clone().background_type(&match config.clone() {
6410 BackgroundType::CustomRect(config) => {
6411 BackgroundType::CustomRect(
6412 config
6413 .position_size_config(Some(
6414 PositionSizeConfig::default()
6415 .display_method(
6416 HorizontalAlign::Right,
6417 VerticalAlign::Top,
6418 )
6419 .origin_position(
6420 position[0] + size[0] - margin[1],
6421 line_position,
6422 )
6423 .origin_size(width, line_length),
6424 ))
6425 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6426 .border_alpha(Some(
6427 resource_panel.scroll_bar_alpha[0],
6428 )),
6429 )
6430 }
6431 BackgroundType::Image(config) => BackgroundType::Image(
6432 config
6433 .position_size_config(Some(
6434 PositionSizeConfig::default()
6435 .display_method(
6436 HorizontalAlign::Right,
6437 VerticalAlign::Top,
6438 )
6439 .origin_position(
6440 position[0] + size[0] - margin[1],
6441 line_position,
6442 )
6443 .origin_size(width, line_length),
6444 ))
6445 .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6446 .background_alpha(Some(
6447 resource_panel.scroll_bar_alpha[0],
6448 ))
6449 .overlay_alpha(Some(
6450 resource_panel.scroll_bar_alpha[0],
6451 )),
6452 ),
6453 }),
6454 )?;
6455 self.use_resource(
6456 &format!("{name}YScroll"),
6457 "rust_constructor::Background",
6458 ui,
6459 ctx,
6460 )?;
6461 }
6462 ScrollBarDisplayMethod::Hidden => {}
6463 };
6464 self.replace_resource(name, resource_panel.clone())?;
6465 }
6466 _ => {}
6467 };
6468 Ok(())
6469 } else {
6470 Err(RustConstructorError {
6471 error_id: "ResourceNotFound".to_string(),
6472 description: format!("Resource \"{name}({discern_type})\" not found."),
6473 })
6474 }
6475 }
6476
6477 pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
6479 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6480 page_data.enter_page_updated = false;
6481 self.timer.start_time = self.timer.total_time;
6482 self.current_page = name.to_string();
6483 self.update_timer();
6484 Ok(())
6485 }
6486
6487 pub fn get_font(&self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
6489 let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
6490 Ok(font.font_definitions.clone())
6491 }
6492
6493 pub fn register_all_fonts(&self, ctx: &Context) {
6495 let mut font_definitions_amount = FontDefinitions::default();
6496 let mut fonts = Vec::new();
6497 for i in 0..self.rust_constructor_resource.len() {
6498 if let Some(font) = self.rust_constructor_resource[i]
6499 .content
6500 .as_any()
6501 .downcast_ref::<Font>()
6502 {
6503 fonts.push((
6504 self.rust_constructor_resource[i].id.name.clone(),
6505 font.font_definitions.clone(),
6506 ));
6507 };
6508 }
6509 for i in &fonts {
6510 if let Some(font_data) = i.1.font_data.get(&i.0) {
6512 font_definitions_amount
6513 .font_data
6514 .insert(i.0.clone(), Arc::clone(font_data));
6515 font_definitions_amount
6516 .families
6517 .entry(FontFamily::Name(i.0.clone().into()))
6518 .or_default()
6519 .push(i.0.clone());
6520 };
6521
6522 font_definitions_amount
6524 .families
6525 .entry(FontFamily::Proportional)
6526 .or_default()
6527 .insert(0, i.0.to_owned());
6528
6529 font_definitions_amount
6530 .families
6531 .entry(FontFamily::Monospace)
6532 .or_default()
6533 .insert(0, i.0.to_owned());
6534 }
6535 ctx.set_fonts(font_definitions_amount);
6536 }
6537
6538 pub fn position_size_processor(
6540 &self,
6541 position_size_config: PositionSizeConfig,
6542 ctx: &Context,
6543 ) -> [[f32; 2]; 2] {
6544 let mut position = [0_f32, 0_f32];
6545 let mut size = [0_f32, 0_f32];
6546 size[0] = match position_size_config.x_size_grid[0] {
6547 0_f32 => position_size_config.origin_size[0],
6548 _ => {
6549 (ctx.available_rect().width() / position_size_config.x_size_grid[1]
6550 * position_size_config.x_size_grid[0])
6551 + position_size_config.origin_size[0]
6552 }
6553 };
6554 size[1] = match position_size_config.y_size_grid[0] {
6555 0_f32 => position_size_config.origin_size[1],
6556 _ => {
6557 (ctx.available_rect().height() / position_size_config.y_size_grid[1]
6558 * position_size_config.y_size_grid[0])
6559 + position_size_config.origin_size[1]
6560 }
6561 };
6562 position[0] = match position_size_config.x_location_grid[1] {
6563 0_f32 => position_size_config.origin_position[0],
6564 _ => {
6565 (ctx.available_rect().width() / position_size_config.x_location_grid[1]
6566 * position_size_config.x_location_grid[0])
6567 + position_size_config.origin_position[0]
6568 }
6569 };
6570 position[1] = match position_size_config.y_location_grid[1] {
6571 0_f32 => position_size_config.origin_position[1],
6572 _ => {
6573 (ctx.available_rect().height() / position_size_config.y_location_grid[1]
6574 * position_size_config.y_location_grid[0])
6575 + position_size_config.origin_position[1]
6576 }
6577 };
6578 match position_size_config.display_method.0 {
6579 HorizontalAlign::Left => {}
6580 HorizontalAlign::Center => position[0] -= size[0] / 2.0,
6581 HorizontalAlign::Right => position[0] -= size[0],
6582 };
6583 match position_size_config.display_method.1 {
6584 VerticalAlign::Top => {}
6585 VerticalAlign::Center => position[1] -= size[1] / 2.0,
6586 VerticalAlign::Bottom => position[1] -= size[1],
6587 };
6588 position[0] += position_size_config.offset[0];
6589 position[1] += position_size_config.offset[1];
6590 [position, size]
6591 }
6592
6593 pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
6595 let page_data = self
6596 .get_resource::<PageData>(name, "rust_constructor::PageData")?
6597 .clone();
6598 if !page_data.change_page_updated {
6599 self.new_page_update(name)?;
6600 };
6601 Ok(page_data.change_page_updated)
6602 }
6603
6604 pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
6606 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6607 page_data.enter_page_updated = true;
6608 Ok(page_data.enter_page_updated)
6609 }
6610
6611 pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
6613 let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
6614 page_data.change_page_updated = true;
6615 self.timer.start_time = self.timer.total_time;
6616 self.update_timer();
6617 Ok(())
6618 }
6619
6620 pub fn update_frame_stats(&mut self) {
6622 let current_time = self.timer.total_time;
6623 if let Some(last) = self.last_frame_time {
6624 let delta = current_time - last;
6625 self.frame_times.push(delta);
6626 const MAX_SAMPLES: usize = 120;
6627 if self.frame_times.len() > MAX_SAMPLES {
6628 let remove_count = self.frame_times.len() - MAX_SAMPLES;
6629 self.frame_times.drain(0..remove_count);
6630 }
6631 }
6632 self.last_frame_time = Some(current_time);
6633 }
6634
6635 pub fn current_fps(&self) -> f32 {
6637 if self.frame_times.is_empty() {
6638 0.0
6639 } else {
6640 1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
6641 }
6642 }
6643
6644 pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
6646 let new_time = [self.timer.now_time, self.timer.total_time];
6647 let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
6648 split_time.time = new_time;
6649 Ok(())
6650 }
6651
6652 pub fn get_split_time(&self, name: &str) -> Result<[f32; 2], RustConstructorError> {
6654 let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
6655 Ok(split_time.time)
6656 }
6657
6658 pub fn update_timer(&mut self) {
6660 let elapsed = self.timer.timer.elapsed();
6661 let seconds = elapsed.as_secs();
6662 let milliseconds = elapsed.subsec_millis();
6663 self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
6664 self.timer.now_time = self.timer.total_time - self.timer.start_time
6665 }
6666
6667 pub fn modify_variable<T: Debug + 'static>(
6669 &mut self,
6670 name: &str,
6671 value: Option<T>,
6672 ) -> Result<(), RustConstructorError> {
6673 let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
6674 variable.value = value;
6675 Ok(())
6676 }
6677
6678 pub fn get_variable<T: Debug + Clone + 'static>(
6680 &self,
6681 name: &str,
6682 ) -> Result<Option<T>, RustConstructorError> {
6683 if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
6684 Ok(variable.value.clone())
6685 } else if self
6686 .check_resource_exists(name, "rust_constructor::Variable")
6687 .is_none()
6688 {
6689 Err(RustConstructorError {
6690 error_id: "ResourceNotFound".to_string(),
6691 description: format!(
6692 "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
6693 ),
6694 })
6695 } else {
6696 Err(RustConstructorError {
6697 error_id: "ResourceGenericMismatch".to_string(),
6698 description: format!(
6699 "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
6700 ),
6701 })
6702 }
6703 }
6704
6705 pub fn get_image_texture(
6707 &self,
6708 name: &str,
6709 ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
6710 let image_texture =
6711 self.get_resource::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
6712 Ok(image_texture.texture.clone())
6713 }
6714
6715 pub fn reset_image_texture(
6717 &mut self,
6718 name: &str,
6719 path: &str,
6720 flip: [bool; 2],
6721 ctx: &Context,
6722 ) -> Result<(), RustConstructorError> {
6723 let image_texture =
6724 self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
6725 if let Ok(mut file) = File::open(path) {
6726 let mut buffer = Vec::new();
6727 file.read_to_end(&mut buffer).unwrap();
6728 let img_bytes = buffer;
6729 let img = image::load_from_memory(&img_bytes).unwrap();
6730 let color_data = match flip {
6731 [true, true] => img.fliph().flipv().into_rgba8(),
6732 [true, false] => img.fliph().into_rgba8(),
6733 [false, true] => img.flipv().into_rgba8(),
6734 _ => img.into_rgba8(),
6735 };
6736 let (w, h) = (color_data.width(), color_data.height());
6737 let raw_data: Vec<u8> = color_data.into_raw();
6738
6739 let color_image =
6740 ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
6741 let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
6742 image_texture.texture = Some(DebugTextureHandle::new(&texture));
6743 image_texture.cite_path = path.to_string();
6744 } else {
6745 return Err(RustConstructorError {
6746 error_id: "ImageLoadFailed".to_string(),
6747 description: format!(
6748 "Failed to load an image from the path \"{}\".",
6749 image_texture.cite_path
6750 ),
6751 });
6752 }
6753 Ok(())
6754 }
6755
6756 pub fn set_switch_enable(
6758 &mut self,
6759 name: &str,
6760 enable: bool,
6761 ) -> Result<(), RustConstructorError> {
6762 let switch = self.get_resource_mut::<Switch>(name, "rust_constructor::Switch")?;
6763 switch.enable = enable;
6764 Ok(())
6765 }
6766
6767 pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
6769 let switch = self.get_resource::<Switch>(name, "rust_constructor::Switch")?;
6770 Ok(SwitchData {
6771 switched: switch.switched,
6772 last_frame_clicked: switch.last_frame_clicked,
6773 state: switch.state,
6774 })
6775 }
6776}