rust_constructor/
lib.rs

1//! # `Rust Constructor V2`
2//!
3//!
4//! 基于`egui`构建的跨平台`GUI`框架, 用`Rust`开发`GUI`项目最简单的方式
5//!
6//! A cross-platform `GUI` framework built on `egui`, the simplest way to develop `GUI` projects in `Rust`
7//!
8//!
9//! 有关`Rust Constructor`的使用方法,请参考[Rust Constructor 指南](https://github.com/ChepleBob30/Rust-Constructor-Guide)。
10//!
11//! 关于源代码及更多内容,请访问`Rust Constructor`的[GitHub 仓库](https://github.com/ChepleBob30/Rust-Constructor)以获取。
12//!
13//!
14//! About the usage method of `Rust Constructor`, please refer to the [Rust Constructor Guide](https://github.com/ChepleBob30/Rust-Constructor-Guide).
15//!
16//! About the source code and more content, please visit the `Rust Constructor` [GitHub Repository](https://github.com/ChepleBob30/Rust-Constructor) to get.
17//!
18//!
19//! 如果你对此项目感兴趣,你也可以来看看我们的组织[必达](https://github.com/Binder-organize)的其他项目。
20//!
21//! If you are interested in this project, You can also come and take a look at other projects of our organization [Binder](https://github.com/Binder-organize).
22use eframe::{
23    Result,
24    emath::Rect,
25    epaint::{Stroke, textures::TextureOptions},
26};
27use egui::{
28    Color32, ColorImage, Context, CursorIcon, FontData, FontDefinitions, FontFamily, FontId,
29    Galley, Id, ImageSource, Key, OpenUrl, PointerButton, Pos2, Sense, StrokeKind, TextureHandle,
30    Ui, Vec2, text::CCursor,
31};
32use std::{
33    any::Any,
34    error::Error,
35    fmt::{Debug, Display, Formatter},
36    fs::{File, read},
37    io::Read,
38    sync::Arc,
39    time::Instant,
40    vec::Vec,
41};
42
43/// 核心特征,用于统一管理Rust Constructor资源。
44pub trait RustConstructorResource: Debug {
45    /// 返回资源名称。
46    fn name(&self) -> &str;
47
48    /// 返回资源类型。
49    fn expose_type(&self) -> &str;
50
51    /// 返回活跃状态。
52    fn active(&self) -> bool;
53
54    /// 改变活跃状态。
55    fn modify_active(&mut self, active: bool);
56
57    /// 用于不可变类型转换。
58    fn as_any(&self) -> &dyn Any;
59
60    /// 用于可变类型转换。
61    fn as_any_mut(&mut self) -> &mut dyn Any;
62}
63
64/// 标记并管理用于显示给用户的基本前端资源。
65pub trait BasicFrontResource: RustConstructorResource {
66    /// 获取资源尺寸。
67    fn display_size(&self) -> [f32; 2];
68
69    /// 获取资源位置。
70    fn display_position(&self) -> [f32; 2];
71
72    /// 获取资源偏移量。
73    fn display_offset(&self) -> [f32; 2];
74
75    /// 获取资源渲染范围。
76    fn display_clip_rect(&self) -> &Option<PositionConfig>;
77
78    /// 获取资源板名称。
79    fn display_panel_name(&self) -> &str;
80
81    /// 获取资源板排版。
82    fn display_panel_layout(&self) -> &Option<(PanelLocation, PanelLayout)>;
83
84    /// 获取资源对齐方法。
85    fn display_center_display(&self) -> &(HorizontalAlign, VerticalAlign);
86
87    /// 获取是否允许资源板滚动。
88    fn display_allow_scrolling(&self) -> [bool; 2];
89
90    /// 修改资源尺寸。
91    fn modify_size(&mut self, width: f32, height: f32);
92
93    /// 修改资源位置。
94    fn modify_position(&mut self, x: f32, y: f32);
95
96    /// 修改资源偏移量。
97    fn modify_offset(&mut self, x: f32, y: f32);
98
99    /// 修改资源渲染范围。
100    fn modify_clip_rect(&mut self, clip_rect: &Option<PositionConfig>);
101
102    /// 修改资源板名称。
103    fn modify_panel_name(&mut self, panel_name: &str);
104
105    /// 修改资源板排版。
106    fn modify_panel_layout(&mut self, panel_layout: &Option<(PanelLocation, PanelLayout)>);
107
108    /// 修改资源对齐方法。
109    fn modify_center_display(
110        &mut self,
111        horizontal_align: &HorizontalAlign,
112        vertical_align: &VerticalAlign,
113    );
114
115    /// 修改是否允许资源板滚动。
116    fn modify_allow_scrolling(&mut self, horizontal: bool, vertical: bool);
117}
118
119/// 用于配置资源位置的结构体。
120#[derive(Debug, Clone, PartialEq, PartialOrd)]
121pub struct PositionConfig {
122    /// 原始位置。
123    pub origin_position: [f32; 2],
124    /// 原始尺寸。
125    pub origin_size: [f32; 2],
126    /// x轴的网格式定位。
127    pub x_location_grid: [u32; 2],
128    /// y轴的网格式定位。
129    pub y_location_grid: [u32; 2],
130    /// x轴的网格式缩放。
131    pub x_size_grid: [u32; 2],
132    /// y轴的网格式缩放。
133    pub y_size_grid: [u32; 2],
134    /// 对齐方法。
135    pub center_display: (HorizontalAlign, VerticalAlign),
136    /// 偏移量。
137    pub offset: [f32; 2],
138}
139
140impl Default for PositionConfig {
141    fn default() -> Self {
142        PositionConfig {
143            origin_position: [0_f32, 0_f32],
144            origin_size: [100_f32, 100_f32],
145            x_location_grid: [0, 0],
146            y_location_grid: [0, 0],
147            x_size_grid: [0, 0],
148            y_size_grid: [0, 0],
149            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
150            offset: [0_f32, 0_f32],
151        }
152    }
153}
154
155impl PositionConfig {
156    pub fn from_image(image: &Image) -> Self {
157        Self {
158            origin_position: image.origin_position,
159            origin_size: image.origin_size,
160            x_size_grid: image.x_size_grid,
161            y_size_grid: image.y_size_grid,
162            x_location_grid: image.x_location_grid,
163            y_location_grid: image.y_location_grid,
164            center_display: image.center_display,
165            offset: image.offset,
166        }
167    }
168
169    pub fn from_image_config(image_config: &ImageConfig) -> Self {
170        Self {
171            origin_position: image_config.origin_position,
172            origin_size: image_config.origin_size,
173            x_size_grid: image_config.x_size_grid,
174            y_size_grid: image_config.y_size_grid,
175            x_location_grid: image_config.x_location_grid,
176            y_location_grid: image_config.y_location_grid,
177            center_display: image_config.center_display,
178            offset: image_config.offset,
179        }
180    }
181
182    pub fn from_custom_rect(custom_rect: &CustomRect) -> Self {
183        Self {
184            origin_position: custom_rect.origin_position,
185            origin_size: custom_rect.origin_size,
186            x_size_grid: custom_rect.x_size_grid,
187            y_size_grid: custom_rect.y_size_grid,
188            x_location_grid: custom_rect.x_location_grid,
189            y_location_grid: custom_rect.y_location_grid,
190            center_display: custom_rect.center_display,
191            offset: custom_rect.offset,
192        }
193    }
194
195    pub fn from_custom_rect_config(custom_rect_config: &CustomRectConfig) -> Self {
196        Self {
197            origin_position: custom_rect_config.origin_position,
198            origin_size: custom_rect_config.origin_size,
199            x_size_grid: custom_rect_config.x_size_grid,
200            y_size_grid: custom_rect_config.y_size_grid,
201            x_location_grid: custom_rect_config.x_location_grid,
202            y_location_grid: custom_rect_config.y_location_grid,
203            center_display: custom_rect_config.center_display,
204            offset: custom_rect_config.offset,
205        }
206    }
207
208    pub fn from_text(text: &Text) -> Self {
209        Self {
210            origin_position: text.origin_position,
211            origin_size: text.origin_size,
212            x_size_grid: text.x_size_grid,
213            y_size_grid: text.y_size_grid,
214            x_location_grid: text.x_location_grid,
215            y_location_grid: text.y_location_grid,
216            center_display: text.center_display,
217            offset: text.offset,
218        }
219    }
220
221    pub fn from_text_config(text_config: &TextConfig) -> Self {
222        Self {
223            origin_position: text_config.origin_position,
224            origin_size: text_config.origin_size,
225            x_size_grid: text_config.x_size_grid,
226            y_size_grid: text_config.y_size_grid,
227            x_location_grid: text_config.x_location_grid,
228            y_location_grid: text_config.y_location_grid,
229            center_display: text_config.center_display,
230            offset: text_config.offset,
231        }
232    }
233
234    pub fn from_mouse_detector(mouse_detector: &MouseDetector) -> Self {
235        Self {
236            origin_position: mouse_detector.origin_position,
237            origin_size: mouse_detector.origin_size,
238            x_size_grid: mouse_detector.x_size_grid,
239            y_size_grid: mouse_detector.y_size_grid,
240            x_location_grid: mouse_detector.x_location_grid,
241            y_location_grid: mouse_detector.y_location_grid,
242            center_display: mouse_detector.center_display,
243            offset: mouse_detector.offset,
244        }
245    }
246
247    pub fn from_resource_panel(resource_panel: &ResourcePanel) -> Self {
248        Self {
249            origin_position: resource_panel.origin_position,
250            origin_size: resource_panel.origin_size,
251            x_size_grid: resource_panel.x_size_grid,
252            y_size_grid: resource_panel.y_size_grid,
253            x_location_grid: resource_panel.x_location_grid,
254            y_location_grid: resource_panel.y_location_grid,
255            center_display: resource_panel.center_display,
256            offset: resource_panel.offset,
257        }
258    }
259
260    #[inline]
261    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
262        self.origin_position = [x, y];
263        self
264    }
265
266    #[inline]
267    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
268        self.origin_size = [width, height];
269        self
270    }
271
272    #[inline]
273    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
274        self.x_size_grid = [fetch, total];
275        self
276    }
277
278    #[inline]
279    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
280        self.y_size_grid = [fetch, total];
281        self
282    }
283
284    #[inline]
285    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
286        self.x_location_grid = [fetch, total];
287        self
288    }
289
290    #[inline]
291    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
292        self.y_location_grid = [fetch, total];
293        self
294    }
295
296    #[inline]
297    pub fn center_display(
298        mut self,
299        horizontal_align: HorizontalAlign,
300        vertical_align: VerticalAlign,
301    ) -> Self {
302        self.center_display = (horizontal_align, vertical_align);
303        self
304    }
305
306    #[inline]
307    pub fn offset(mut self, x: f32, y: f32) -> Self {
308        self.offset = [x, y];
309        self
310    }
311}
312
313/// 报告发生问题时的状态。
314#[derive(Debug, Clone, PartialEq, PartialOrd)]
315pub struct ReportState {
316    /// 问题发生时所在页面。
317    pub current_page: String,
318    /// 问题发生时程序总运行时间。
319    pub current_total_runtime: f32,
320    /// 问题发生时页面运行时间。
321    pub current_page_runtime: f32,
322}
323
324/// 出现问题时用于存储问题内容、状态及注释的结构体。
325#[derive(Debug, Clone, PartialEq, PartialOrd)]
326pub struct Problem {
327    /// 问题严重程度。
328    pub severity_level: SeverityLevel,
329    /// 问题描述。
330    pub problem: String,
331    /// 问题备注。
332    pub annotation: String,
333    /// 问题报告状态。
334    pub report_state: ReportState,
335    /// 问题类型。
336    pub problem_type: RustConstructorError,
337}
338
339/// 衡量问题的严重等级。
340#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
341pub enum SeverityLevel {
342    /// 弱警告:会影响程序正常执行,但一般情况下不会有严重后果。
343    MildWarning,
344    /// 强警告:会影响程序正常执行,且可能导致意外情况。
345    SevereWarning,
346    /// 错误:会导致程序无法运行。
347    Error,
348}
349
350/// 用于确认基本前端资源在资源板中的排版方式。
351#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
352pub enum PanelLayout {
353    /// 垂直布局。
354    Vertical(f32, f32, f32, f32, bool),
355    /// 水平布局。
356    Horizontal(f32, f32, f32, f32, bool),
357    /// 无布局。
358    None(f32, f32, f32, f32, bool),
359}
360
361/// 用于控制基本前端资源在资源板中的定位方式。
362#[derive(Debug, Clone, PartialEq, PartialOrd)]
363pub enum PanelLocation {
364    /// 依照此资源到资源板左上角的距离定位。
365    Absolute(f32, f32),
366    /// 依照网格式定位方法进行定位。
367    Relative([[u32; 2]; 2]),
368}
369
370/// 用于存储页面数据的RC资源。
371#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
372pub struct PageData {
373    pub discern_type: String,
374    pub name: String,
375    pub active: bool,
376    /// 是否强制在每帧都刷新页面。
377    pub forced_update: bool,
378    /// 是否已经加载完首次进入此页面所需内容。
379    pub change_page_updated: bool,
380    /// 是否已经加载完进入此页面所需内容。
381    pub enter_page_updated: bool,
382}
383
384impl RustConstructorResource for PageData {
385    fn name(&self) -> &str {
386        &self.name
387    }
388
389    fn expose_type(&self) -> &str {
390        &self.discern_type
391    }
392
393    fn active(&self) -> bool {
394        self.active
395    }
396
397    fn modify_active(&mut self, active: bool) {
398        self.active = active;
399    }
400
401    fn as_any(&self) -> &dyn Any {
402        self
403    }
404
405    fn as_any_mut(&mut self) -> &mut dyn Any {
406        self
407    }
408}
409
410impl Default for PageData {
411    fn default() -> Self {
412        PageData {
413            discern_type: String::from("PageData"),
414            name: String::from("PageData"),
415            active: false,
416            forced_update: true,
417            change_page_updated: false,
418            enter_page_updated: false,
419        }
420    }
421}
422
423impl PageData {
424    #[inline]
425    pub fn name(mut self, name: &str) -> Self {
426        self.name = name.to_string();
427        self
428    }
429
430    #[inline]
431    pub fn forced_update(mut self, forced_update: bool) -> Self {
432        self.forced_update = forced_update;
433        self
434    }
435}
436
437/// 用于存储运行时间的计时器。
438#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
439pub struct Timer {
440    /// 进入页面的时间。
441    pub start_time: f32,
442    /// 程序总运行时间。
443    pub total_time: f32,
444    /// 核心计时器。
445    pub timer: Instant,
446    /// 当前页面运行时间。
447    pub now_time: f32,
448}
449
450impl Default for Timer {
451    fn default() -> Self {
452        Timer {
453            start_time: 0_f32,
454            total_time: 0_f32,
455            timer: Instant::now(),
456            now_time: 0_f32,
457        }
458    }
459}
460
461/// 为图片纹理支持派生Debug特征。
462#[derive(Clone, PartialEq, Eq, Hash)]
463pub struct DebugTextureHandle(TextureHandle);
464
465impl Debug for DebugTextureHandle {
466    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
467        // 只输出类型信息,不输出具体纹理数据
468        f.debug_struct("DebugTextureHandle").finish()
469    }
470}
471
472impl DebugTextureHandle {
473    pub fn new(texture_handle: TextureHandle) -> Self {
474        Self(texture_handle)
475    }
476}
477
478/// 用于存储图片纹理的RC资源。
479#[derive(Debug, Clone, PartialEq)]
480pub struct ImageTexture {
481    pub discern_type: String,
482    pub name: String,
483    pub active: bool,
484    /// 图片纹理。
485    pub texture: Option<DebugTextureHandle>,
486    /// 图片路径。
487    pub cite_path: String,
488    /// 翻转图片。
489    pub flip: [bool; 2],
490    /// 加载资源。
491    pub ctx: Context,
492}
493
494impl RustConstructorResource for ImageTexture {
495    fn name(&self) -> &str {
496        &self.name
497    }
498
499    fn expose_type(&self) -> &str {
500        &self.discern_type
501    }
502
503    fn active(&self) -> bool {
504        self.active
505    }
506
507    fn modify_active(&mut self, active: bool) {
508        self.active = active;
509    }
510
511    fn as_any(&self) -> &dyn Any {
512        self
513    }
514
515    fn as_any_mut(&mut self) -> &mut dyn Any {
516        self
517    }
518}
519
520impl Default for ImageTexture {
521    fn default() -> Self {
522        ImageTexture {
523            discern_type: String::from("ImageTexture"),
524            name: String::from("ImageTexture"),
525            active: false,
526            texture: None,
527            cite_path: String::from(""),
528            flip: [false, false],
529            ctx: Context::default(),
530        }
531    }
532}
533
534impl ImageTexture {
535    #[inline]
536    pub fn name(mut self, name: &str) -> Self {
537        self.name = name.to_string();
538        self
539    }
540
541    #[inline]
542    pub fn cite_path(mut self, cite_path: &str) -> Self {
543        self.cite_path = cite_path.to_string();
544        self
545    }
546
547    #[inline]
548    pub fn flip(mut self, horizontal_flip: bool, vertical_flip: bool) -> Self {
549        self.flip = [horizontal_flip, vertical_flip];
550        self
551    }
552
553    #[inline]
554    pub fn ctx(mut self, ctx: &Context) -> Self {
555        self.ctx = ctx.clone();
556        self
557    }
558}
559
560/// 矩形的可配置项。
561#[derive(Debug, Clone, PartialEq, PartialOrd)]
562pub struct CustomRectConfig {
563    /// 原始尺寸。
564    pub origin_size: [f32; 2],
565    /// x轴的网格式缩放。
566    pub x_size_grid: [u32; 2],
567    /// y轴的网格式缩放。
568    pub y_size_grid: [u32; 2],
569    /// 圆角。
570    pub rounding: f32,
571    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
572    pub x_location_grid: [u32; 2],
573    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
574    pub y_location_grid: [u32; 2],
575    /// 对齐方法。
576    pub center_display: (HorizontalAlign, VerticalAlign),
577    /// 偏移量。
578    pub offset: [f32; 2],
579    /// 颜色。
580    pub color: [u8; 4],
581    /// 边框宽度。
582    pub border_width: f32,
583    /// 边框颜色。
584    pub border_color: [u8; 4],
585    /// 原始位置。
586    pub origin_position: [f32; 2],
587    /// 允许渲染的范围。
588    pub clip_rect: Option<PositionConfig>,
589    /// 资源板名称。
590    pub panel_name: String,
591    /// 资源排版方式(如果不允许移动资源留空即可)。
592    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
593    /// 允许在资源板中滚动。
594    pub allow_scrolling: [bool; 2],
595}
596
597impl Default for CustomRectConfig {
598    fn default() -> Self {
599        Self {
600            origin_size: [100_f32, 100_f32],
601            x_size_grid: [0, 0],
602            y_size_grid: [0, 0],
603            rounding: 2_f32,
604            x_location_grid: [0, 0],
605            y_location_grid: [0, 0],
606            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
607            offset: [0_f32, 0_f32],
608            color: [255, 255, 255, 255],
609            border_width: 2_f32,
610            border_color: [0, 0, 0, 255],
611            origin_position: [0_f32, 0_f32],
612            clip_rect: None,
613            panel_name: String::new(),
614            panel_layout: None,
615            allow_scrolling: [false, false],
616        }
617    }
618}
619
620impl CustomRectConfig {
621    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
622        self.origin_position = position_config.origin_position;
623        self.origin_size = position_config.origin_size;
624        self.x_size_grid = position_config.x_size_grid;
625        self.y_size_grid = position_config.y_size_grid;
626        self.x_location_grid = position_config.x_location_grid;
627        self.y_location_grid = position_config.y_location_grid;
628        self.center_display = position_config.center_display;
629        self.offset = position_config.offset;
630        self
631    }
632
633    pub fn from_custom_rect(custom_rect: &CustomRect) -> Self {
634        Self {
635            origin_size: custom_rect.origin_size,
636            x_size_grid: custom_rect.x_size_grid,
637            y_size_grid: custom_rect.y_size_grid,
638            rounding: custom_rect.rounding,
639            x_location_grid: custom_rect.x_location_grid,
640            y_location_grid: custom_rect.y_location_grid,
641            center_display: custom_rect.center_display,
642            offset: custom_rect.offset,
643            color: custom_rect.color,
644            border_width: custom_rect.border_width,
645            border_color: custom_rect.border_color,
646            origin_position: custom_rect.origin_position,
647            clip_rect: custom_rect.clip_rect.clone(),
648            panel_name: custom_rect.panel_name.clone(),
649            panel_layout: custom_rect.panel_layout.clone(),
650            allow_scrolling: custom_rect.allow_scrolling,
651        }
652    }
653
654    #[inline]
655    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
656        self.origin_size = [width, height];
657        self
658    }
659
660    #[inline]
661    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
662        self.x_size_grid = [fetch, total];
663        self
664    }
665
666    #[inline]
667    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
668        self.y_size_grid = [fetch, total];
669        self
670    }
671
672    #[inline]
673    pub fn rounding(mut self, rounding: f32) -> Self {
674        self.rounding = rounding;
675        self
676    }
677
678    #[inline]
679    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
680        self.x_location_grid = [fetch, total];
681        self
682    }
683
684    #[inline]
685    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
686        self.y_location_grid = [fetch, total];
687        self
688    }
689
690    #[inline]
691    pub fn center_display(
692        mut self,
693        horizontal_align: HorizontalAlign,
694        vertical_align: VerticalAlign,
695    ) -> Self {
696        self.center_display = (horizontal_align, vertical_align);
697        self
698    }
699
700    #[inline]
701    pub fn offset(mut self, x: f32, y: f32) -> Self {
702        self.offset = [x, y];
703        self
704    }
705
706    #[inline]
707    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
708        self.color = [r, g, b, a];
709        self
710    }
711
712    #[inline]
713    pub fn border_width(mut self, border_width: f32) -> Self {
714        self.border_width = border_width;
715        self
716    }
717
718    #[inline]
719    pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
720        self.border_color = [r, g, b, a];
721        self
722    }
723
724    #[inline]
725    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
726        self.origin_position = [x, y];
727        self
728    }
729
730    #[inline]
731    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
732        self.clip_rect = clip_rect;
733        self
734    }
735
736    #[inline]
737    pub fn panel_name(mut self, panel_name: &str) -> Self {
738        self.panel_name = panel_name.to_string();
739        self
740    }
741
742    #[inline]
743    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
744        self.panel_layout = panel_layout;
745        self
746    }
747
748    #[inline]
749    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
750        self.allow_scrolling = [horizontal, vertical];
751        self
752    }
753}
754
755/// RC的矩形资源。
756#[derive(Debug, Clone, PartialEq, PartialOrd)]
757pub struct CustomRect {
758    pub discern_type: String,
759    pub name: String,
760    pub active: bool,
761    /// 位置。
762    pub position: [f32; 2],
763    /// 尺寸。
764    pub size: [f32; 2],
765    /// 原始尺寸。
766    pub origin_size: [f32; 2],
767    /// x轴的网格式缩放。
768    pub x_size_grid: [u32; 2],
769    /// y轴的网格式缩放。
770    pub y_size_grid: [u32; 2],
771    /// 圆角。
772    pub rounding: f32,
773    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
774    pub x_location_grid: [u32; 2],
775    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
776    pub y_location_grid: [u32; 2],
777    /// 对齐方法。
778    pub center_display: (HorizontalAlign, VerticalAlign),
779    /// 偏移量。
780    pub offset: [f32; 2],
781    /// 颜色。
782    pub color: [u8; 4],
783    /// 边框宽度。
784    pub border_width: f32,
785    /// 边框颜色。
786    pub border_color: [u8; 4],
787    /// 原始位置。
788    pub origin_position: [f32; 2],
789    /// 允许渲染的范围。
790    pub clip_rect: Option<PositionConfig>,
791    /// 资源板名称。
792    pub panel_name: String,
793    /// 资源排版方式(如果不允许移动资源留空即可)。
794    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
795    /// 允许在资源板中滚动。
796    pub allow_scrolling: [bool; 2],
797}
798
799impl RustConstructorResource for CustomRect {
800    fn name(&self) -> &str {
801        &self.name
802    }
803
804    fn expose_type(&self) -> &str {
805        &self.discern_type
806    }
807
808    fn active(&self) -> bool {
809        self.active
810    }
811
812    fn modify_active(&mut self, active: bool) {
813        self.active = active;
814    }
815
816    fn as_any(&self) -> &dyn Any {
817        self
818    }
819
820    fn as_any_mut(&mut self) -> &mut dyn Any {
821        self
822    }
823}
824
825impl BasicFrontResource for CustomRect {
826    fn display_position(&self) -> [f32; 2] {
827        self.position
828    }
829
830    fn display_size(&self) -> [f32; 2] {
831        self.size
832    }
833
834    fn display_offset(&self) -> [f32; 2] {
835        self.offset
836    }
837
838    fn display_clip_rect(&self) -> &Option<PositionConfig> {
839        &self.clip_rect
840    }
841
842    fn display_panel_name(&self) -> &str {
843        &self.panel_name
844    }
845
846    fn display_panel_layout(&self) -> &Option<(PanelLocation, PanelLayout)> {
847        &self.panel_layout
848    }
849
850    fn display_center_display(&self) -> &(HorizontalAlign, VerticalAlign) {
851        &self.center_display
852    }
853
854    fn display_allow_scrolling(&self) -> [bool; 2] {
855        self.allow_scrolling
856    }
857
858    fn modify_position(&mut self, x: f32, y: f32) {
859        self.origin_position = [x, y];
860    }
861
862    fn modify_size(&mut self, width: f32, height: f32) {
863        self.origin_size = [width, height];
864    }
865
866    fn modify_offset(&mut self, x: f32, y: f32) {
867        self.offset = [x, y];
868    }
869
870    fn modify_clip_rect(&mut self, clip_rect: &Option<PositionConfig>) {
871        self.clip_rect = clip_rect.clone();
872    }
873
874    fn modify_panel_name(&mut self, panel_name: &str) {
875        self.panel_name = panel_name.to_string();
876    }
877
878    fn modify_panel_layout(&mut self, panel_layout: &Option<(PanelLocation, PanelLayout)>) {
879        self.panel_layout = panel_layout.clone();
880    }
881
882    fn modify_center_display(
883        &mut self,
884        horizontal_align: &HorizontalAlign,
885        vertical_align: &VerticalAlign,
886    ) {
887        self.center_display = (*horizontal_align, *vertical_align);
888    }
889
890    fn modify_allow_scrolling(&mut self, horizontal: bool, vertical: bool) {
891        self.allow_scrolling = [horizontal, vertical];
892    }
893}
894
895impl Default for CustomRect {
896    fn default() -> Self {
897        Self {
898            discern_type: String::from("CustomRect"),
899            name: String::from("CustomRect"),
900            active: false,
901            position: [0_f32, 0_f32],
902            size: [100_f32, 100_f32],
903            origin_size: [100_f32, 100_f32],
904            x_size_grid: [0, 0],
905            y_size_grid: [0, 0],
906            rounding: 2_f32,
907            x_location_grid: [0, 0],
908            y_location_grid: [0, 0],
909            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
910            offset: [0_f32, 0_f32],
911            color: [255, 255, 255, 255],
912            border_width: 2_f32,
913            border_color: [0, 0, 0, 255],
914            origin_position: [0_f32, 0_f32],
915            clip_rect: None,
916            panel_name: String::new(),
917            panel_layout: None,
918            allow_scrolling: [false, false],
919        }
920    }
921}
922
923impl CustomRect {
924    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
925        self.origin_position = position_config.origin_position;
926        self.origin_size = position_config.origin_size;
927        self.x_size_grid = position_config.x_size_grid;
928        self.y_size_grid = position_config.y_size_grid;
929        self.x_location_grid = position_config.x_location_grid;
930        self.y_location_grid = position_config.y_location_grid;
931        self.center_display = position_config.center_display;
932        self.offset = position_config.offset;
933        self
934    }
935
936    pub fn from_config(mut self, config: &CustomRectConfig) -> Self {
937        self.origin_size = config.origin_size;
938        self.x_size_grid = config.x_size_grid;
939        self.y_size_grid = config.y_size_grid;
940        self.rounding = config.rounding;
941        self.x_location_grid = config.x_location_grid;
942        self.y_location_grid = config.y_location_grid;
943        self.center_display = config.center_display;
944        self.offset = config.offset;
945        self.color = config.color;
946        self.border_width = config.border_width;
947        self.border_color = config.border_color;
948        self.origin_position = config.origin_position;
949        self.clip_rect = config.clip_rect.clone();
950        self.panel_name = config.panel_name.clone();
951        self.panel_layout = config.panel_layout.clone();
952        self.allow_scrolling = config.allow_scrolling;
953        self
954    }
955
956    #[inline]
957    pub fn name(mut self, name: &str) -> Self {
958        self.name = name.to_string();
959        self
960    }
961
962    #[inline]
963    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
964        self.origin_size = [width, height];
965        self
966    }
967
968    #[inline]
969    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
970        self.x_size_grid = [fetch, total];
971        self
972    }
973
974    #[inline]
975    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
976        self.y_size_grid = [fetch, total];
977        self
978    }
979
980    #[inline]
981    pub fn rounding(mut self, rounding: f32) -> Self {
982        self.rounding = rounding;
983        self
984    }
985
986    #[inline]
987    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
988        self.x_location_grid = [fetch, total];
989        self
990    }
991
992    #[inline]
993    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
994        self.y_location_grid = [fetch, total];
995        self
996    }
997
998    #[inline]
999    pub fn center_display(
1000        mut self,
1001        horizontal_align: HorizontalAlign,
1002        vertical_align: VerticalAlign,
1003    ) -> Self {
1004        self.center_display = (horizontal_align, vertical_align);
1005        self
1006    }
1007
1008    #[inline]
1009    pub fn offset(mut self, x: f32, y: f32) -> Self {
1010        self.offset = [x, y];
1011        self
1012    }
1013
1014    #[inline]
1015    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1016        self.color = [r, g, b, a];
1017        self
1018    }
1019
1020    #[inline]
1021    pub fn border_width(mut self, border_width: f32) -> Self {
1022        self.border_width = border_width;
1023        self
1024    }
1025
1026    #[inline]
1027    pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1028        self.border_color = [r, g, b, a];
1029        self
1030    }
1031
1032    #[inline]
1033    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1034        self.origin_position = [x, y];
1035        self
1036    }
1037
1038    #[inline]
1039    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
1040        self.clip_rect = clip_rect;
1041        self
1042    }
1043
1044    #[inline]
1045    pub fn panel_name(mut self, panel_name: &str) -> Self {
1046        self.panel_name = panel_name.to_string();
1047        self
1048    }
1049
1050    #[inline]
1051    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
1052        self.panel_layout = panel_layout;
1053        self
1054    }
1055
1056    #[inline]
1057    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
1058        self.allow_scrolling = [horizontal, vertical];
1059        self
1060    }
1061}
1062
1063/// 图片的可配置项。
1064#[derive(Debug, Clone, PartialEq, PartialOrd)]
1065pub struct ImageConfig {
1066    /// 图片原始大小。
1067    pub origin_size: [f32; 2],
1068    /// x轴的网格式缩放。
1069    pub x_size_grid: [u32; 2],
1070    /// y轴的网格式缩放。
1071    pub y_size_grid: [u32; 2],
1072    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1073    pub x_location_grid: [u32; 2],
1074    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1075    pub y_location_grid: [u32; 2],
1076    /// 对齐方法。
1077    pub center_display: (HorizontalAlign, VerticalAlign),
1078    /// 偏移量。
1079    pub offset: [f32; 2],
1080    /// 不透明度。
1081    pub alpha: u8,
1082    /// 叠加颜色。
1083    pub overlay_color: [u8; 4],
1084    /// 背景颜色。
1085    pub background_color: [u8; 4],
1086    /// 旋转角度(只能顺时针,建议搭配std::f32::PI使用)。
1087    pub rotate_angle: f32,
1088    /// 旋转中心。
1089    pub rotate_center: [f32; 2],
1090    /// 原始位置。
1091    pub origin_position: [f32; 2],
1092    /// 引用纹理名。
1093    pub cite_texture: String,
1094    /// 允许渲染的范围。
1095    pub clip_rect: Option<PositionConfig>,
1096    /// 资源板名称。
1097    pub panel_name: String,
1098    /// 资源排版方式(如果不允许移动资源留空即可)。
1099    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
1100    /// 允许在资源板中滚动。
1101    pub allow_scrolling: [bool; 2],
1102}
1103
1104impl Default for ImageConfig {
1105    fn default() -> Self {
1106        Self {
1107            origin_size: [100_f32, 100_f32],
1108            x_size_grid: [0, 0],
1109            y_size_grid: [0, 0],
1110            x_location_grid: [0, 0],
1111            y_location_grid: [0, 0],
1112            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1113            offset: [0_f32, 0_f32],
1114            alpha: 255,
1115            overlay_color: [255, 255, 255, 255],
1116            background_color: [0, 0, 0, 0],
1117            rotate_angle: 0_f32,
1118            rotate_center: [0_f32, 0_f32],
1119            origin_position: [0_f32, 0_f32],
1120            cite_texture: String::from("ImageTexture"),
1121            clip_rect: None,
1122            panel_name: String::new(),
1123            panel_layout: None,
1124            allow_scrolling: [false, false],
1125        }
1126    }
1127}
1128
1129impl ImageConfig {
1130    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
1131        self.origin_position = position_config.origin_position;
1132        self.origin_size = position_config.origin_size;
1133        self.x_size_grid = position_config.x_size_grid;
1134        self.y_size_grid = position_config.y_size_grid;
1135        self.x_location_grid = position_config.x_location_grid;
1136        self.y_location_grid = position_config.y_location_grid;
1137        self.center_display = position_config.center_display;
1138        self.offset = position_config.offset;
1139        self
1140    }
1141
1142    pub fn from_image(image: &Image) -> Self {
1143        Self {
1144            origin_size: image.origin_size,
1145            x_size_grid: image.x_size_grid,
1146            y_size_grid: image.y_size_grid,
1147            x_location_grid: image.x_location_grid,
1148            y_location_grid: image.y_location_grid,
1149            center_display: image.center_display,
1150            offset: image.offset,
1151            alpha: image.alpha,
1152            overlay_color: image.overlay_color,
1153            background_color: image.background_color,
1154            rotate_angle: image.rotate_angle,
1155            rotate_center: image.rotate_center,
1156            cite_texture: image.cite_texture.clone(),
1157            origin_position: image.origin_position,
1158            clip_rect: image.clip_rect.clone(),
1159            panel_name: image.panel_name.clone(),
1160            panel_layout: image.panel_layout.clone(),
1161            allow_scrolling: image.allow_scrolling,
1162        }
1163    }
1164
1165    #[inline]
1166    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1167        self.origin_position = [x, y];
1168        self
1169    }
1170
1171    #[inline]
1172    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
1173        self.origin_size = [width, height];
1174        self
1175    }
1176
1177    #[inline]
1178    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
1179        self.x_size_grid = [fetch, total];
1180        self
1181    }
1182
1183    #[inline]
1184    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
1185        self.y_size_grid = [fetch, total];
1186        self
1187    }
1188
1189    #[inline]
1190    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
1191        self.x_location_grid = [fetch, total];
1192        self
1193    }
1194
1195    #[inline]
1196    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
1197        self.y_location_grid = [fetch, total];
1198        self
1199    }
1200
1201    #[inline]
1202    pub fn center_display(
1203        mut self,
1204        horizontal_align: HorizontalAlign,
1205        vertical_align: VerticalAlign,
1206    ) -> Self {
1207        self.center_display = (horizontal_align, vertical_align);
1208        self
1209    }
1210
1211    #[inline]
1212    pub fn offset(mut self, x: f32, y: f32) -> Self {
1213        self.offset = [x, y];
1214        self
1215    }
1216
1217    #[inline]
1218    pub fn alpha(mut self, alpha: u8) -> Self {
1219        self.alpha = alpha;
1220        self
1221    }
1222
1223    #[inline]
1224    pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1225        self.overlay_color = [r, g, b, a];
1226        self
1227    }
1228
1229    #[inline]
1230    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1231        self.background_color = [r, g, b, a];
1232        self
1233    }
1234
1235    #[inline]
1236    pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1237        self.rotate_angle = rotate_angle;
1238        self
1239    }
1240
1241    #[inline]
1242    pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1243        self.rotate_center = [x, y];
1244        self
1245    }
1246
1247    #[inline]
1248    pub fn cite_texture(mut self, cite_texture: &str) -> Self {
1249        self.cite_texture = cite_texture.to_string();
1250        self
1251    }
1252
1253    #[inline]
1254    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
1255        self.clip_rect = clip_rect;
1256        self
1257    }
1258
1259    #[inline]
1260    pub fn panel_name(mut self, panel_name: &str) -> Self {
1261        self.panel_name = panel_name.to_string();
1262        self
1263    }
1264
1265    #[inline]
1266    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
1267        self.panel_layout = panel_layout;
1268        self
1269    }
1270
1271    #[inline]
1272    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
1273        self.allow_scrolling = [horizontal, vertical];
1274        self
1275    }
1276}
1277
1278/// RC的图片资源。
1279#[derive(Debug, Clone, PartialEq)]
1280pub struct Image {
1281    pub discern_type: String,
1282    pub name: String,
1283    pub active: bool,
1284    /// 图片纹理。
1285    pub texture: Option<DebugTextureHandle>,
1286    /// 图片位置。
1287    pub position: [f32; 2],
1288    /// 图片大小。
1289    pub size: [f32; 2],
1290    /// 图片原始大小。
1291    pub origin_size: [f32; 2],
1292    /// x轴的网格式缩放。
1293    pub x_size_grid: [u32; 2],
1294    /// y轴的网格式缩放。
1295    pub y_size_grid: [u32; 2],
1296    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1297    pub x_location_grid: [u32; 2],
1298    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1299    pub y_location_grid: [u32; 2],
1300    /// 对齐方法。
1301    pub center_display: (HorizontalAlign, VerticalAlign),
1302    /// 偏移量。
1303    pub offset: [f32; 2],
1304    /// 不透明度。
1305    pub alpha: u8,
1306    /// 叠加颜色。
1307    pub overlay_color: [u8; 4],
1308    /// 背景颜色。
1309    pub background_color: [u8; 4],
1310    /// 旋转角度(只能顺时针,建议搭配std::f32::consts::PI使用)。
1311    pub rotate_angle: f32,
1312    /// 旋转中心。
1313    pub rotate_center: [f32; 2],
1314    /// 原始位置。
1315    pub origin_position: [f32; 2],
1316    /// 引用纹理名。
1317    pub cite_texture: String,
1318    /// 上一帧引用纹理名。
1319    pub last_frame_cite_texture: String,
1320    /// 允许渲染的范围。
1321    pub clip_rect: Option<PositionConfig>,
1322    /// 资源板名称。
1323    pub panel_name: String,
1324    /// 资源排版方式(如果不允许移动资源留空即可)。
1325    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
1326    /// 允许在资源板中滚动。
1327    pub allow_scrolling: [bool; 2],
1328}
1329
1330impl RustConstructorResource for Image {
1331    fn name(&self) -> &str {
1332        &self.name
1333    }
1334
1335    fn expose_type(&self) -> &str {
1336        &self.discern_type
1337    }
1338
1339    fn active(&self) -> bool {
1340        self.active
1341    }
1342
1343    fn modify_active(&mut self, active: bool) {
1344        self.active = active;
1345    }
1346
1347    fn as_any(&self) -> &dyn Any {
1348        self
1349    }
1350
1351    fn as_any_mut(&mut self) -> &mut dyn Any {
1352        self
1353    }
1354}
1355
1356impl BasicFrontResource for Image {
1357    fn display_position(&self) -> [f32; 2] {
1358        self.position
1359    }
1360
1361    fn display_size(&self) -> [f32; 2] {
1362        self.size
1363    }
1364
1365    fn display_offset(&self) -> [f32; 2] {
1366        self.offset
1367    }
1368
1369    fn display_clip_rect(&self) -> &Option<PositionConfig> {
1370        &self.clip_rect
1371    }
1372
1373    fn display_panel_name(&self) -> &str {
1374        &self.panel_name
1375    }
1376
1377    fn display_panel_layout(&self) -> &Option<(PanelLocation, PanelLayout)> {
1378        &self.panel_layout
1379    }
1380
1381    fn display_center_display(&self) -> &(HorizontalAlign, VerticalAlign) {
1382        &self.center_display
1383    }
1384
1385    fn display_allow_scrolling(&self) -> [bool; 2] {
1386        self.allow_scrolling
1387    }
1388
1389    fn modify_position(&mut self, x: f32, y: f32) {
1390        self.origin_position = [x, y];
1391    }
1392
1393    fn modify_size(&mut self, width: f32, height: f32) {
1394        self.origin_size = [width, height];
1395    }
1396
1397    fn modify_offset(&mut self, x: f32, y: f32) {
1398        self.offset = [x, y];
1399    }
1400
1401    fn modify_clip_rect(&mut self, clip_rect: &Option<PositionConfig>) {
1402        self.clip_rect = clip_rect.clone();
1403    }
1404
1405    fn modify_panel_name(&mut self, panel_name: &str) {
1406        self.panel_name = panel_name.to_string();
1407    }
1408
1409    fn modify_panel_layout(&mut self, panel_layout: &Option<(PanelLocation, PanelLayout)>) {
1410        self.panel_layout = panel_layout.clone();
1411    }
1412
1413    fn modify_center_display(
1414        &mut self,
1415        horizontal_align: &HorizontalAlign,
1416        vertical_align: &VerticalAlign,
1417    ) {
1418        self.center_display = (*horizontal_align, *vertical_align);
1419    }
1420
1421    fn modify_allow_scrolling(&mut self, horizontal: bool, vertical: bool) {
1422        self.allow_scrolling = [horizontal, vertical];
1423    }
1424}
1425
1426impl Default for Image {
1427    fn default() -> Self {
1428        Self {
1429            discern_type: String::from("Image"),
1430            name: String::from("Image"),
1431            active: false,
1432            texture: None,
1433            position: [0_f32, 0_f32],
1434            size: [100_f32, 100_f32],
1435            origin_size: [100_f32, 100_f32],
1436            x_size_grid: [0, 0],
1437            y_size_grid: [0, 0],
1438            x_location_grid: [0, 0],
1439            y_location_grid: [0, 0],
1440            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1441            offset: [0_f32, 0_f32],
1442            alpha: 255,
1443            overlay_color: [255, 255, 255, 255],
1444            background_color: [0, 0, 0, 0],
1445            rotate_angle: 0_f32,
1446            rotate_center: [0_f32, 0_f32],
1447            origin_position: [0_f32, 0_f32],
1448            cite_texture: String::from("ImageTexture"),
1449            last_frame_cite_texture: String::from("ImageTexture"),
1450            clip_rect: None,
1451            panel_name: String::new(),
1452            panel_layout: None,
1453            allow_scrolling: [false, false],
1454        }
1455    }
1456}
1457
1458impl Image {
1459    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
1460        self.origin_position = position_config.origin_position;
1461        self.origin_size = position_config.origin_size;
1462        self.x_size_grid = position_config.x_size_grid;
1463        self.y_size_grid = position_config.y_size_grid;
1464        self.x_location_grid = position_config.x_location_grid;
1465        self.y_location_grid = position_config.y_location_grid;
1466        self.center_display = position_config.center_display;
1467        self.offset = position_config.offset;
1468        self
1469    }
1470
1471    pub fn from_config(mut self, config: &ImageConfig) -> Self {
1472        self.origin_size = config.origin_size;
1473        self.x_size_grid = config.x_size_grid;
1474        self.y_size_grid = config.y_size_grid;
1475        self.x_location_grid = config.x_location_grid;
1476        self.y_location_grid = config.y_location_grid;
1477        self.center_display = config.center_display;
1478        self.offset = config.offset;
1479        self.alpha = config.alpha;
1480        self.overlay_color = config.overlay_color;
1481        self.background_color = config.background_color;
1482        self.rotate_angle = config.rotate_angle;
1483        self.rotate_center = config.rotate_center;
1484        self.origin_position = config.origin_position;
1485        self.cite_texture = config.cite_texture.clone();
1486        self.clip_rect = config.clip_rect.clone();
1487        self.panel_name = config.panel_name.clone();
1488        self.panel_layout = config.panel_layout.clone();
1489        self.allow_scrolling = config.allow_scrolling;
1490        self
1491    }
1492
1493    #[inline]
1494    pub fn name(mut self, name: &str) -> Self {
1495        self.name = name.to_string();
1496        self
1497    }
1498
1499    #[inline]
1500    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1501        self.origin_position = [x, y];
1502        self
1503    }
1504
1505    #[inline]
1506    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
1507        self.origin_size = [width, height];
1508        self
1509    }
1510
1511    #[inline]
1512    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
1513        self.x_size_grid = [fetch, total];
1514        self
1515    }
1516
1517    #[inline]
1518    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
1519        self.y_size_grid = [fetch, total];
1520        self
1521    }
1522
1523    #[inline]
1524    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
1525        self.x_location_grid = [fetch, total];
1526        self
1527    }
1528
1529    #[inline]
1530    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
1531        self.y_location_grid = [fetch, total];
1532        self
1533    }
1534
1535    #[inline]
1536    pub fn center_display(
1537        mut self,
1538        horizontal_align: HorizontalAlign,
1539        vertical_align: VerticalAlign,
1540    ) -> Self {
1541        self.center_display = (horizontal_align, vertical_align);
1542        self
1543    }
1544
1545    #[inline]
1546    pub fn offset(mut self, x: f32, y: f32) -> Self {
1547        self.offset = [x, y];
1548        self
1549    }
1550
1551    #[inline]
1552    pub fn alpha(mut self, alpha: u8) -> Self {
1553        self.alpha = alpha;
1554        self
1555    }
1556
1557    #[inline]
1558    pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1559        self.overlay_color = [r, g, b, a];
1560        self
1561    }
1562
1563    #[inline]
1564    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1565        self.background_color = [r, g, b, a];
1566        self
1567    }
1568
1569    #[inline]
1570    pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1571        self.rotate_angle = rotate_angle;
1572        self
1573    }
1574
1575    #[inline]
1576    pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1577        self.rotate_center = [x, y];
1578        self
1579    }
1580
1581    #[inline]
1582    pub fn cite_texture(mut self, cite_texture: &str) -> Self {
1583        self.cite_texture = cite_texture.to_string();
1584        self
1585    }
1586
1587    #[inline]
1588    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
1589        self.clip_rect = clip_rect;
1590        self
1591    }
1592
1593    #[inline]
1594    pub fn panel_name(mut self, panel_name: &str) -> Self {
1595        self.panel_name = panel_name.to_string();
1596        self
1597    }
1598
1599    #[inline]
1600    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
1601        self.panel_layout = panel_layout;
1602        self
1603    }
1604
1605    #[inline]
1606    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
1607        self.allow_scrolling = [horizontal, vertical];
1608        self
1609    }
1610}
1611
1612/// 控制超链接选取方法。
1613#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1614pub enum HyperlinkSelectMethod {
1615    /// 选取所有匹配项。
1616    All(String),
1617    /// 选取指定的匹配项。
1618    Segment(Vec<(usize, String)>),
1619}
1620
1621/// 文本的可配置项。
1622#[derive(Debug, Clone, PartialEq, PartialOrd)]
1623pub struct TextConfig {
1624    /// 文本内容。
1625    pub content: String,
1626    /// 字号。
1627    pub font_size: f32,
1628    /// 文本颜色。
1629    pub color: [u8; 4],
1630    /// 对齐方法。
1631    pub center_display: (HorizontalAlign, VerticalAlign),
1632    /// 偏移量。
1633    pub offset: [f32; 2],
1634    /// 背景颜色。
1635    pub background_color: [u8; 4],
1636    /// 圆角。
1637    pub background_rounding: f32,
1638    /// 原始尺寸。
1639    pub origin_size: [f32; 2],
1640    /// x轴的网格式缩放。
1641    pub x_size_grid: [u32; 2],
1642    /// y轴的网格式缩放。
1643    pub y_size_grid: [u32; 2],
1644    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1645    pub x_location_grid: [u32; 2],
1646    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1647    pub y_location_grid: [u32; 2],
1648    /// 原始位置。
1649    pub origin_position: [f32; 2],
1650    /// 字体。
1651    pub font: String,
1652    /// 是否可框选。
1653    pub selectable: bool,
1654    /// 超链接文本。
1655    pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1656    /// 是否使用截断文本功能。
1657    pub truncate: bool,
1658    /// 允许渲染的范围。
1659    pub clip_rect: Option<PositionConfig>,
1660    /// 资源板名称。
1661    pub panel_name: String,
1662    /// 资源排版方式(如果不允许移动资源留空即可)。
1663    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
1664    /// 允许在资源板中滚动。
1665    pub allow_scrolling: [bool; 2],
1666}
1667
1668impl Default for TextConfig {
1669    fn default() -> Self {
1670        Self {
1671            content: String::from("Hello world"),
1672            font_size: 16_f32,
1673            origin_size: [0_f32, 0_f32],
1674            x_size_grid: [0, 0],
1675            y_size_grid: [0, 0],
1676            color: [255, 255, 255, 255],
1677            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1678            offset: [0_f32, 0_f32],
1679            background_color: [0, 0, 0, 0],
1680            background_rounding: 2_f32,
1681            x_location_grid: [0, 0],
1682            y_location_grid: [0, 0],
1683            origin_position: [0_f32, 0_f32],
1684            font: String::new(),
1685            selectable: true,
1686            hyperlink_text: Vec::new(),
1687            truncate: false,
1688            clip_rect: None,
1689            panel_name: String::new(),
1690            panel_layout: None,
1691            allow_scrolling: [false, false],
1692        }
1693    }
1694}
1695
1696impl TextConfig {
1697    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
1698        self.origin_position = position_config.origin_position;
1699        self.origin_size = position_config.origin_size;
1700        self.x_size_grid = position_config.x_size_grid;
1701        self.y_size_grid = position_config.y_size_grid;
1702        self.x_location_grid = position_config.x_location_grid;
1703        self.y_location_grid = position_config.y_location_grid;
1704        self.center_display = position_config.center_display;
1705        self.offset = position_config.offset;
1706        self
1707    }
1708
1709    pub fn from_text(text: &Text) -> Self {
1710        Self {
1711            content: text.content.clone(),
1712            font_size: text.font_size,
1713            origin_size: text.origin_size,
1714            x_size_grid: text.x_size_grid,
1715            y_size_grid: text.y_size_grid,
1716            color: text.color,
1717            center_display: text.center_display,
1718            offset: text.offset,
1719            background_color: text.background_color,
1720            background_rounding: text.background_rounding,
1721            x_location_grid: text.x_location_grid,
1722            y_location_grid: text.y_location_grid,
1723            origin_position: text.origin_position,
1724            font: text.font.clone(),
1725            selectable: text.selectable,
1726            hyperlink_text: text.hyperlink_text.clone(),
1727            truncate: text.truncate,
1728            clip_rect: text.clip_rect.clone(),
1729            panel_name: text.panel_name.clone(),
1730            panel_layout: text.panel_layout.clone(),
1731            allow_scrolling: text.allow_scrolling,
1732        }
1733    }
1734
1735    #[inline]
1736    pub fn content(mut self, content: &str) -> Self {
1737        self.content = content.to_string();
1738        self
1739    }
1740
1741    #[inline]
1742    pub fn font_size(mut self, font_size: f32) -> Self {
1743        self.font_size = font_size;
1744        self
1745    }
1746
1747    #[inline]
1748    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
1749        self.origin_size = [width, height];
1750        self
1751    }
1752
1753    #[inline]
1754    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
1755        self.x_size_grid = [fetch, total];
1756        self
1757    }
1758
1759    #[inline]
1760    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
1761        self.y_size_grid = [fetch, total];
1762        self
1763    }
1764
1765    #[inline]
1766    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1767        self.color = [r, g, b, a];
1768        self
1769    }
1770
1771    #[inline]
1772    pub fn center_display(
1773        mut self,
1774        horizontal_align: HorizontalAlign,
1775        vertical_align: VerticalAlign,
1776    ) -> Self {
1777        self.center_display = (horizontal_align, vertical_align);
1778        self
1779    }
1780
1781    #[inline]
1782    pub fn offset(mut self, x: f32, y: f32) -> Self {
1783        self.offset = [x, y];
1784        self
1785    }
1786
1787    #[inline]
1788    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1789        self.background_color = [r, g, b, a];
1790        self
1791    }
1792
1793    #[inline]
1794    pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1795        self.background_rounding = background_rounding;
1796        self
1797    }
1798
1799    #[inline]
1800    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
1801        self.x_location_grid = [fetch, total];
1802        self
1803    }
1804
1805    #[inline]
1806    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
1807        self.y_location_grid = [fetch, total];
1808        self
1809    }
1810
1811    #[inline]
1812    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1813        self.origin_position = [x, y];
1814        self
1815    }
1816
1817    #[inline]
1818    pub fn font(mut self, font: &str) -> Self {
1819        self.font = font.to_string();
1820        self
1821    }
1822
1823    #[inline]
1824    pub fn selectable(mut self, selectable: bool) -> Self {
1825        self.selectable = selectable;
1826        self
1827    }
1828
1829    #[inline]
1830    pub fn hyperlink_text(
1831        mut self,
1832        target_text: &str,
1833        select_method: HyperlinkSelectMethod,
1834    ) -> Self {
1835        self.hyperlink_text
1836            .push((target_text.to_string(), select_method));
1837        self
1838    }
1839
1840    #[inline]
1841    pub fn truncate(mut self, truncate: bool) -> Self {
1842        self.truncate = truncate;
1843        self
1844    }
1845
1846    #[inline]
1847    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
1848        self.clip_rect = clip_rect;
1849        self
1850    }
1851
1852    #[inline]
1853    pub fn panel_name(mut self, panel_name: &str) -> Self {
1854        self.panel_name = panel_name.to_string();
1855        self
1856    }
1857
1858    #[inline]
1859    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
1860        self.panel_layout = panel_layout;
1861        self
1862    }
1863
1864    #[inline]
1865    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
1866        self.allow_scrolling = [horizontal, vertical];
1867        self
1868    }
1869}
1870
1871/// RC的文本资源。
1872#[derive(Debug, Clone, PartialEq, PartialOrd)]
1873pub struct Text {
1874    pub discern_type: String,
1875    pub name: String,
1876    pub active: bool,
1877    /// 文本内容。
1878    pub content: String,
1879    /// 字号。
1880    pub font_size: f32,
1881    /// 文本实际尺寸。
1882    pub actual_size: [f32; 2],
1883    /// 原始尺寸。
1884    pub origin_size: [f32; 2],
1885    /// x轴的网格式缩放。
1886    pub x_size_grid: [u32; 2],
1887    /// y轴的网格式缩放。
1888    pub y_size_grid: [u32; 2],
1889    /// 文本颜色。
1890    pub color: [u8; 4],
1891    /// 文本位置。
1892    pub position: [f32; 2],
1893    /// 对齐方法。
1894    pub center_display: (HorizontalAlign, VerticalAlign),
1895    /// 偏移量。
1896    pub offset: [f32; 2],
1897    /// 背景颜色。
1898    pub background_color: [u8; 4],
1899    /// 圆角。
1900    pub background_rounding: f32,
1901    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1902    pub x_location_grid: [u32; 2],
1903    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1904    pub y_location_grid: [u32; 2],
1905    /// 原始位置。
1906    pub origin_position: [f32; 2],
1907    /// 字体。
1908    pub font: String,
1909    /// 框选选中的文本。
1910    pub selection: Option<(usize, usize)>,
1911    /// 是否可框选。
1912    pub selectable: bool,
1913    /// 超链接文本。
1914    pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1915    /// 超链接选取索引值与链接。
1916    pub hyperlink_index: Vec<(usize, usize, String)>,
1917    /// 上一帧的文本内容(用于优化超链接文本选取)。
1918    pub last_frame_content: String,
1919    /// 文本大小。
1920    pub size: [f32; 2],
1921    /// 是否截断文本。
1922    pub truncate: bool,
1923    /// 允许渲染的范围。
1924    pub clip_rect: Option<PositionConfig>,
1925    /// 资源板名称。
1926    pub panel_name: String,
1927    /// 资源排版方式(如果不允许移动资源留空即可)。
1928    pub panel_layout: Option<(PanelLocation, PanelLayout)>,
1929    /// 允许在资源板中滚动。
1930    pub allow_scrolling: [bool; 2],
1931}
1932
1933impl RustConstructorResource for Text {
1934    fn name(&self) -> &str {
1935        &self.name
1936    }
1937
1938    fn expose_type(&self) -> &str {
1939        &self.discern_type
1940    }
1941
1942    fn active(&self) -> bool {
1943        self.active
1944    }
1945
1946    fn modify_active(&mut self, active: bool) {
1947        self.active = active;
1948    }
1949
1950    fn as_any(&self) -> &dyn Any {
1951        self
1952    }
1953
1954    fn as_any_mut(&mut self) -> &mut dyn Any {
1955        self
1956    }
1957}
1958
1959impl BasicFrontResource for Text {
1960    fn display_position(&self) -> [f32; 2] {
1961        self.position
1962    }
1963
1964    fn display_size(&self) -> [f32; 2] {
1965        self.actual_size
1966    }
1967
1968    fn display_offset(&self) -> [f32; 2] {
1969        self.offset
1970    }
1971
1972    fn display_clip_rect(&self) -> &Option<PositionConfig> {
1973        &self.clip_rect
1974    }
1975
1976    fn display_panel_name(&self) -> &str {
1977        &self.panel_name
1978    }
1979
1980    fn display_panel_layout(&self) -> &Option<(PanelLocation, PanelLayout)> {
1981        &self.panel_layout
1982    }
1983
1984    fn display_center_display(&self) -> &(HorizontalAlign, VerticalAlign) {
1985        &self.center_display
1986    }
1987
1988    fn display_allow_scrolling(&self) -> [bool; 2] {
1989        self.allow_scrolling
1990    }
1991
1992    fn modify_position(&mut self, x: f32, y: f32) {
1993        self.origin_position = [x, y];
1994    }
1995
1996    fn modify_size(&mut self, width: f32, height: f32) {
1997        self.origin_size = [width, height];
1998    }
1999
2000    fn modify_offset(&mut self, x: f32, y: f32) {
2001        self.offset = [x, y];
2002    }
2003
2004    fn modify_clip_rect(&mut self, clip_rect: &Option<PositionConfig>) {
2005        self.clip_rect = clip_rect.clone();
2006    }
2007
2008    fn modify_panel_name(&mut self, panel_name: &str) {
2009        self.panel_name = panel_name.to_string();
2010    }
2011
2012    fn modify_panel_layout(&mut self, panel_layout: &Option<(PanelLocation, PanelLayout)>) {
2013        self.panel_layout = panel_layout.clone();
2014    }
2015
2016    fn modify_center_display(
2017        &mut self,
2018        horizontal_align: &HorizontalAlign,
2019        vertical_align: &VerticalAlign,
2020    ) {
2021        self.center_display = (*horizontal_align, *vertical_align);
2022    }
2023
2024    fn modify_allow_scrolling(&mut self, horizontal: bool, vertical: bool) {
2025        self.allow_scrolling = [horizontal, vertical];
2026    }
2027}
2028
2029impl Default for Text {
2030    fn default() -> Self {
2031        Self {
2032            discern_type: String::from("Text"),
2033            name: String::from("Text"),
2034            active: false,
2035            content: String::from("Hello world"),
2036            font_size: 16_f32,
2037            actual_size: [0_f32, 0_f32],
2038            origin_size: [100_f32, 100_f32],
2039            x_size_grid: [0, 0],
2040            y_size_grid: [0, 0],
2041            color: [255, 255, 255, 255],
2042            position: [0_f32, 0_f32],
2043            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
2044            offset: [0_f32, 0_f32],
2045            background_color: [0, 0, 0, 0],
2046            background_rounding: 2_f32,
2047            x_location_grid: [0, 0],
2048            y_location_grid: [0, 0],
2049            origin_position: [0_f32, 0_f32],
2050            font: String::new(),
2051            selection: None,
2052            selectable: true,
2053            hyperlink_text: Vec::new(),
2054            hyperlink_index: Vec::new(),
2055            last_frame_content: String::from(""),
2056            size: [100_f32, 100_f32],
2057            truncate: false,
2058            clip_rect: None,
2059            panel_name: String::new(),
2060            panel_layout: None,
2061            allow_scrolling: [false, false],
2062        }
2063    }
2064}
2065
2066impl Text {
2067    pub fn from_position_config(mut self, position_config: &PositionConfig) -> Self {
2068        self.origin_position = position_config.origin_position;
2069        self.origin_size = position_config.origin_size;
2070        self.x_location_grid = position_config.x_location_grid;
2071        self.y_location_grid = position_config.y_location_grid;
2072        self.x_size_grid = position_config.x_size_grid;
2073        self.y_size_grid = position_config.y_size_grid;
2074        self.center_display = position_config.center_display;
2075        self.offset = position_config.offset;
2076        self
2077    }
2078
2079    pub fn from_config(mut self, config: &TextConfig) -> Self {
2080        self.content = config.content.clone();
2081        self.font_size = config.font_size;
2082        self.origin_size = config.origin_size;
2083        self.x_size_grid = config.x_size_grid;
2084        self.y_size_grid = config.y_size_grid;
2085        self.color = config.color;
2086        self.center_display = config.center_display;
2087        self.offset = config.offset;
2088        self.background_color = config.background_color;
2089        self.background_rounding = config.background_rounding;
2090        self.x_location_grid = config.x_location_grid;
2091        self.y_location_grid = config.y_location_grid;
2092        self.origin_position = config.origin_position;
2093        self.font = config.font.clone();
2094        self.selectable = config.selectable;
2095        self.hyperlink_text = config.hyperlink_text.clone();
2096        self.clip_rect = config.clip_rect.clone();
2097        self.truncate = config.truncate;
2098        self.panel_name = config.panel_name.clone();
2099        self.panel_layout = config.panel_layout.clone();
2100        self.allow_scrolling = config.allow_scrolling;
2101        self
2102    }
2103
2104    #[inline]
2105    pub fn name(mut self, name: &str) -> Self {
2106        self.name = name.to_string();
2107        self
2108    }
2109
2110    #[inline]
2111    pub fn content(mut self, content: &str) -> Self {
2112        self.content = content.to_string();
2113        self
2114    }
2115
2116    #[inline]
2117    pub fn font_size(mut self, font_size: f32) -> Self {
2118        self.font_size = font_size;
2119        self
2120    }
2121
2122    #[inline]
2123    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
2124        self.origin_size = [width, height];
2125        self
2126    }
2127
2128    #[inline]
2129    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
2130        self.x_size_grid = [fetch, total];
2131        self
2132    }
2133
2134    #[inline]
2135    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
2136        self.y_size_grid = [fetch, total];
2137        self
2138    }
2139
2140    #[inline]
2141    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
2142        self.color = [r, g, b, a];
2143        self
2144    }
2145
2146    #[inline]
2147    pub fn center_display(
2148        mut self,
2149        horizontal_align: HorizontalAlign,
2150        vertical_align: VerticalAlign,
2151    ) -> Self {
2152        self.center_display = (horizontal_align, vertical_align);
2153        self
2154    }
2155
2156    #[inline]
2157    pub fn offset(mut self, x: f32, y: f32) -> Self {
2158        self.offset = [x, y];
2159        self
2160    }
2161
2162    #[inline]
2163    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
2164        self.background_color = [r, g, b, a];
2165        self
2166    }
2167
2168    #[inline]
2169    pub fn background_rounding(mut self, background_rounding: f32) -> Self {
2170        self.background_rounding = background_rounding;
2171        self
2172    }
2173
2174    #[inline]
2175    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
2176        self.x_location_grid = [fetch, total];
2177        self
2178    }
2179
2180    #[inline]
2181    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
2182        self.y_location_grid = [fetch, total];
2183        self
2184    }
2185
2186    #[inline]
2187    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
2188        self.origin_position = [x, y];
2189        self
2190    }
2191
2192    #[inline]
2193    pub fn font(mut self, font: &str) -> Self {
2194        self.font = font.to_string();
2195        self
2196    }
2197
2198    #[inline]
2199    pub fn selectable(mut self, selectable: bool) -> Self {
2200        self.selectable = selectable;
2201        self
2202    }
2203
2204    #[inline]
2205    pub fn hyperlink_text(
2206        mut self,
2207        target_text: &str,
2208        select_method: HyperlinkSelectMethod,
2209    ) -> Self {
2210        self.hyperlink_text
2211            .push((target_text.to_string(), select_method));
2212        self
2213    }
2214
2215    #[inline]
2216    pub fn truncate(mut self, truncate: bool) -> Self {
2217        self.truncate = truncate;
2218        self
2219    }
2220
2221    #[inline]
2222    pub fn clip_rect(mut self, clip_rect: Option<PositionConfig>) -> Self {
2223        self.clip_rect = clip_rect;
2224        self
2225    }
2226
2227    #[inline]
2228    pub fn panel_name(mut self, panel_name: &str) -> Self {
2229        self.panel_name = panel_name.to_string();
2230        self
2231    }
2232
2233    #[inline]
2234    pub fn panel_layout(mut self, panel_layout: Option<(PanelLocation, PanelLayout)>) -> Self {
2235        self.panel_layout = panel_layout;
2236        self
2237    }
2238
2239    #[inline]
2240    pub fn allow_scrolling(mut self, horizontal: bool, vertical: bool) -> Self {
2241        self.allow_scrolling = [horizontal, vertical];
2242        self
2243    }
2244}
2245
2246/// RC的变量资源。
2247#[derive(Debug, Clone, PartialEq, PartialOrd)]
2248pub struct Variable<T> {
2249    pub discern_type: String,
2250    pub name: String,
2251    pub active: bool,
2252    /// 变量的值。
2253    pub value: Option<T>,
2254}
2255
2256impl<T: Debug + 'static> RustConstructorResource for Variable<T> {
2257    fn name(&self) -> &str {
2258        &self.name
2259    }
2260
2261    fn expose_type(&self) -> &str {
2262        &self.discern_type
2263    }
2264
2265    fn active(&self) -> bool {
2266        self.active
2267    }
2268
2269    fn modify_active(&mut self, active: bool) {
2270        self.active = active;
2271    }
2272
2273    fn as_any(&self) -> &dyn Any {
2274        self
2275    }
2276
2277    fn as_any_mut(&mut self) -> &mut dyn Any {
2278        self
2279    }
2280}
2281
2282impl<T> Default for Variable<T> {
2283    fn default() -> Self {
2284        Variable {
2285            discern_type: String::from("Variable"),
2286            name: String::from("Variable"),
2287            active: false,
2288            value: None,
2289        }
2290    }
2291}
2292
2293impl<T> Variable<T> {
2294    #[inline]
2295    pub fn name(mut self, name: &str) -> Self {
2296        self.name = name.to_string();
2297        self
2298    }
2299
2300    #[inline]
2301    pub fn value(mut self, value: Option<T>) -> Self {
2302        self.value = value;
2303        self
2304    }
2305}
2306
2307/// RC的字体资源。
2308#[derive(Debug, Clone, PartialEq)]
2309pub struct Font {
2310    pub name: String,
2311    pub discern_type: String,
2312    pub active: bool,
2313    /// 字体定义。
2314    pub font_definitions: FontDefinitions,
2315    /// 字体路径。
2316    pub path: String,
2317}
2318
2319impl RustConstructorResource for Font {
2320    fn name(&self) -> &str {
2321        &self.name
2322    }
2323
2324    fn expose_type(&self) -> &str {
2325        &self.discern_type
2326    }
2327
2328    fn active(&self) -> bool {
2329        self.active
2330    }
2331
2332    fn modify_active(&mut self, active: bool) {
2333        self.active = active;
2334    }
2335
2336    fn as_any(&self) -> &dyn Any {
2337        self
2338    }
2339
2340    fn as_any_mut(&mut self) -> &mut dyn Any {
2341        self
2342    }
2343}
2344
2345impl Default for Font {
2346    fn default() -> Self {
2347        Self {
2348            discern_type: String::from("Font"),
2349            name: String::from("Font"),
2350            active: false,
2351            font_definitions: FontDefinitions::default(),
2352            path: String::from(""),
2353        }
2354    }
2355}
2356
2357impl Font {
2358    #[inline]
2359    pub fn name(mut self, name: &str) -> Self {
2360        self.name = name.to_string();
2361        self
2362    }
2363
2364    #[inline]
2365    pub fn path(mut self, path: &str) -> Self {
2366        self.path = path.to_string();
2367        self
2368    }
2369}
2370
2371/// RC的时间分段资源。
2372#[derive(Debug, Clone, PartialEq, PartialOrd)]
2373pub struct SplitTime {
2374    pub discern_type: String,
2375    pub name: String,
2376    pub active: bool,
2377    /// 时间点(第一个值为页面运行时间,第二个值为总运行时间)。
2378    pub time: [f32; 2],
2379}
2380
2381impl RustConstructorResource for SplitTime {
2382    fn name(&self) -> &str {
2383        &self.name
2384    }
2385
2386    fn expose_type(&self) -> &str {
2387        &self.discern_type
2388    }
2389
2390    fn active(&self) -> bool {
2391        self.active
2392    }
2393
2394    fn modify_active(&mut self, active: bool) {
2395        self.active = active;
2396    }
2397
2398    fn as_any(&self) -> &dyn Any {
2399        self
2400    }
2401
2402    fn as_any_mut(&mut self) -> &mut dyn Any {
2403        self
2404    }
2405}
2406
2407impl Default for SplitTime {
2408    fn default() -> Self {
2409        Self {
2410            discern_type: String::from("SplitTime"),
2411            name: String::from("SplitTime"),
2412            active: false,
2413            time: [0_f32, 0_f32],
2414        }
2415    }
2416}
2417
2418impl SplitTime {
2419    #[inline]
2420    pub fn name(mut self, name: &str) -> Self {
2421        self.name = name.to_string();
2422        self
2423    }
2424}
2425
2426/// 开关的外观。
2427#[derive(Debug, Clone, PartialEq, PartialOrd)]
2428pub struct SwitchAppearance {
2429    /// 当填充资源为图片时的配置项。
2430    pub image_config: ImageConfig,
2431    /// 当填充资源为矩形时的配置项。
2432    pub custom_rect_config: CustomRectConfig,
2433    /// 当启用文本时,文本的配置项。
2434    pub text_config: TextConfig,
2435    /// 当填充资源为图片时,开关的纹理。
2436    pub texture: String,
2437    /// 开关上的提示文本。
2438    pub hint_text: String,
2439}
2440
2441/// 开关的点击方法。
2442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2443pub struct SwitchClickAction {
2444    /// 开关的点击方法。
2445    pub click_method: PointerButton,
2446    /// 点击后是否改变开关状态。
2447    pub action: bool,
2448}
2449
2450/// 用于开关资源判定的一些字段集合。
2451#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2452pub struct SwitchData {
2453    /// 是否点击切换状态。
2454    pub switched: bool,
2455    /// 点击的方法。
2456    pub last_time_clicked_index: usize,
2457    /// 开关状态。
2458    pub state: u32,
2459}
2460
2461/// RC的开关资源。
2462#[derive(Debug, Clone, PartialEq)]
2463pub struct Switch {
2464    pub discern_type: String,
2465    pub name: String,
2466    pub active: bool,
2467    /// 外观(包括各类资源配置项,数量为开启的内容数量*开关状态总数)。
2468    pub appearance: Vec<SwitchAppearance>,
2469    /// 开关使用的填充资源名称。
2470    pub fill_resource_name: String,
2471    /// 开关使用的填充资源类型。
2472    pub fill_resource_type: String,
2473    /// 是否启用鼠标悬浮和点击时的显示内容。
2474    pub enable_hover_click_fill_resource: [bool; 2],
2475    /// 开关当前状态。
2476    pub state: u32,
2477    /// 可以用于点击开关的方法(包含点击方式和是否改变开关状态两个参数)。
2478    pub click_method: Vec<SwitchClickAction>,
2479    /// 上一次渲染是否有鼠标悬浮。
2480    pub last_time_hovered: bool,
2481    /// 上一次渲染是否被鼠标点击。
2482    pub last_time_clicked: bool,
2483    /// 上一次点击对应的点击方法的索引。
2484    pub last_time_clicked_index: usize,
2485    /// 动画总数。
2486    pub animation_count: u32,
2487    /// 提示文本资源名。
2488    pub hint_text_name: String,
2489    /// 开关上的文本资源名称(不需要可留空)。
2490    pub text_name: String,
2491    /// 开关文本资源的原始位置。
2492    pub text_origin_position: [f32; 2],
2493    /// 是否切换了开关状态。
2494    pub switched: bool,
2495}
2496
2497impl RustConstructorResource for Switch {
2498    fn name(&self) -> &str {
2499        &self.name
2500    }
2501
2502    fn expose_type(&self) -> &str {
2503        &self.discern_type
2504    }
2505
2506    fn active(&self) -> bool {
2507        self.active
2508    }
2509
2510    fn modify_active(&mut self, active: bool) {
2511        self.active = active;
2512    }
2513
2514    fn as_any(&self) -> &dyn Any {
2515        self
2516    }
2517
2518    fn as_any_mut(&mut self) -> &mut dyn Any {
2519        self
2520    }
2521}
2522
2523impl Default for Switch {
2524    fn default() -> Self {
2525        Self {
2526            discern_type: String::from("Switch"),
2527            name: String::from("Switch"),
2528            active: false,
2529            appearance: vec![],
2530            fill_resource_name: String::from("FillResource"),
2531            fill_resource_type: String::from("Image"),
2532            enable_hover_click_fill_resource: [false, false],
2533            state: 0,
2534            click_method: vec![],
2535            last_time_hovered: false,
2536            last_time_clicked: false,
2537            last_time_clicked_index: 5,
2538            animation_count: 0,
2539            hint_text_name: String::new(),
2540            text_name: String::new(),
2541            text_origin_position: [0_f32, 0_f32],
2542            switched: false,
2543        }
2544    }
2545}
2546
2547impl Switch {
2548    #[inline]
2549    pub fn name(mut self, name: &str) -> Self {
2550        self.name = name.to_string();
2551        self
2552    }
2553
2554    #[inline]
2555    pub fn appearance(mut self, appearance: Vec<SwitchAppearance>) -> Self {
2556        self.appearance = appearance;
2557        self
2558    }
2559
2560    #[inline]
2561    pub fn fill_resource_name(mut self, fill_resource_name: &str) -> Self {
2562        self.fill_resource_name = fill_resource_name.to_string();
2563        self
2564    }
2565
2566    #[inline]
2567    pub fn fill_resource_type(mut self, fill_resource_type: &str) -> Self {
2568        self.fill_resource_type = fill_resource_type.to_string();
2569        self
2570    }
2571
2572    #[inline]
2573    pub fn enable_hover_click_fill_resource(
2574        mut self,
2575        enable_hover_fill_resource: bool,
2576        enable_click_fill_resource: bool,
2577    ) -> Self {
2578        self.enable_hover_click_fill_resource =
2579            [enable_hover_fill_resource, enable_click_fill_resource];
2580        self
2581    }
2582
2583    #[inline]
2584    pub fn click_method(mut self, click_method: Vec<SwitchClickAction>) -> Self {
2585        self.click_method = click_method;
2586        self
2587    }
2588
2589    #[inline]
2590    pub fn text_name(mut self, text_name: &str) -> Self {
2591        self.text_name = text_name.to_string();
2592        self
2593    }
2594}
2595
2596/// RC的消息框资源。
2597#[derive(Debug, Clone, PartialEq, PartialOrd)]
2598pub struct MessageBox {
2599    pub discern_type: String,
2600    pub name: String,
2601    pub active: bool,
2602    /// 消息框大小。
2603    pub size: [f32; 2],
2604    /// 框内内容资源名。
2605    pub content_name: String,
2606    /// 框内标题资源名。
2607    pub title_name: String,
2608    /// 框内图片资源名。
2609    pub image_name: String,
2610    /// 消息框是否持续存在。
2611    pub keep_existing: bool,
2612    /// 如果不持续存在,消息框的持续时间。
2613    pub existing_time: f32,
2614    /// 消息框是否存在(不等于是否显示)。
2615    pub exist: bool,
2616    /// 消息框移动速度。
2617    pub speed: f32,
2618    /// 消息框补位速度。
2619    pub restore_speed: f32,
2620    /// 消息框上一次渲染时的y轴偏移量(用于实现补位动画)。
2621    pub memory_offset: f32,
2622    /// 关闭按钮的填充资源名称。
2623    pub close_switch_fill_resource_name: String,
2624    /// 关闭按钮的填充资源类型。
2625    pub close_switch_fill_resource_type: String,
2626}
2627
2628impl RustConstructorResource for MessageBox {
2629    fn name(&self) -> &str {
2630        &self.name
2631    }
2632
2633    fn expose_type(&self) -> &str {
2634        &self.discern_type
2635    }
2636
2637    fn active(&self) -> bool {
2638        self.active
2639    }
2640
2641    fn modify_active(&mut self, active: bool) {
2642        self.active = active;
2643    }
2644
2645    fn as_any(&self) -> &dyn Any {
2646        self
2647    }
2648
2649    fn as_any_mut(&mut self) -> &mut dyn Any {
2650        self
2651    }
2652}
2653
2654impl Default for MessageBox {
2655    fn default() -> Self {
2656        Self {
2657            discern_type: String::from("MessageBox"),
2658            name: String::from("MessageBox"),
2659            active: false,
2660            size: [100_f32, 100_f32],
2661            content_name: String::from("Content"),
2662            title_name: String::from("Title"),
2663            image_name: String::from("Image"),
2664            keep_existing: false,
2665            existing_time: 3_f32,
2666            exist: true,
2667            speed: 30_f32,
2668            restore_speed: 10_f32,
2669            memory_offset: 0_f32,
2670            close_switch_fill_resource_name: String::from("CloseSwitch"),
2671            close_switch_fill_resource_type: String::from("Image"),
2672        }
2673    }
2674}
2675
2676impl MessageBox {
2677    #[inline]
2678    pub fn name(mut self, name: &str) -> Self {
2679        self.name = name.to_string();
2680        self
2681    }
2682
2683    #[inline]
2684    pub fn size(mut self, width: f32, height: f32) -> Self {
2685        self.size = [width, height];
2686        self
2687    }
2688
2689    #[inline]
2690    pub fn content_name(mut self, content_name: &str) -> Self {
2691        self.content_name = content_name.to_string();
2692        self
2693    }
2694
2695    #[inline]
2696    pub fn title_name(mut self, title_name: &str) -> Self {
2697        self.title_name = title_name.to_string();
2698        self
2699    }
2700
2701    #[inline]
2702    pub fn image_name(mut self, image_name: &str) -> Self {
2703        self.image_name = image_name.to_string();
2704        self
2705    }
2706
2707    #[inline]
2708    pub fn keep_existing(mut self, keep_existing: bool) -> Self {
2709        self.keep_existing = keep_existing;
2710        self
2711    }
2712
2713    #[inline]
2714    pub fn existing_time(mut self, existing_time: f32) -> Self {
2715        self.existing_time = existing_time;
2716        self
2717    }
2718
2719    #[inline]
2720    pub fn speed(mut self, speed: f32) -> Self {
2721        self.speed = speed;
2722        self
2723    }
2724
2725    #[inline]
2726    pub fn restore_speed(mut self, restore_speed: f32) -> Self {
2727        self.restore_speed = restore_speed;
2728        self
2729    }
2730
2731    #[inline]
2732    pub fn close_switch_fill_resource_name(
2733        mut self,
2734        close_switch_fill_resource_name: &str,
2735    ) -> Self {
2736        self.close_switch_fill_resource_name = close_switch_fill_resource_name.to_string();
2737        self
2738    }
2739
2740    #[inline]
2741    pub fn close_switch_fill_resource_type(
2742        mut self,
2743        close_switch_fill_resource_type: &str,
2744    ) -> Self {
2745        self.close_switch_fill_resource_type = close_switch_fill_resource_type.to_string();
2746        self
2747    }
2748}
2749
2750/// 鼠标检测器单次检测等级。
2751#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2752pub enum MouseDetectorLevel {
2753    /// 精简模式,只进行最基础的检测。
2754    Lite,
2755    /// 标准模式,检测大部分常用鼠标行为。
2756    #[default]
2757    Default,
2758    /// 完整模式,检测所有鼠标行为。
2759    Pro,
2760}
2761
2762/// 鼠标检测器检测结果。
2763#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
2764pub struct MouseDetectResult {
2765    /// 是否点击。
2766    pub clicked: bool,
2767    /// 鼠标是否在检测范围内。
2768    pub contains_pointer: bool,
2769    /// 是否点击右键。
2770    pub secondary_clicked: Option<bool>,
2771    /// 是否点击中键。
2772    pub middle_clicked: Option<bool>,
2773    /// 是否点击扩展按键。
2774    pub clicked_by_extra_button: Option<[bool; 2]>,
2775    /// 是否长时间触屏。
2776    pub long_touched: Option<bool>,
2777    /// 是否双击。
2778    pub double_clicked: Option<bool>,
2779    /// 是否三击。
2780    pub triple_clicked: Option<bool>,
2781    /// 双击的方法。
2782    pub double_clicked_by: Option<[bool; 5]>,
2783    /// 三击的方法。
2784    pub triple_clicked_by: Option<[bool; 5]>,
2785    /// 是否在检测范围外点击。
2786    pub clicked_elsewhere: Option<bool>,
2787    /// 是否悬挂在检测范围内。
2788    pub hovered: Option<bool>,
2789    /// 是否开始拖动。
2790    pub drag_started: Option<bool>,
2791    /// 开始拖动的方法。
2792    pub drag_started_by: Option<[bool; 5]>,
2793    /// 是否正在拖动。
2794    pub dragged: Option<bool>,
2795    /// 拖动方法。
2796    pub dragged_by: Option<[bool; 5]>,
2797    /// 是否结束拖动。
2798    pub drag_stopped: Option<bool>,
2799    /// 结束拖动方法。
2800    pub deag_stopped_by: Option<[bool; 5]>,
2801    /// 上一帧拖动经过了多少格像素。
2802    pub drag_delta: Option<[f32; 2]>,
2803    /// 一次拖动中总共经过了多少格像素。
2804    pub total_drag_delta: Option<Option<[f32; 2]>>,
2805    /// 鼠标上一帧拖动了多远。
2806    pub drag_motion: Option<[f32; 2]>,
2807    /// 鼠标交互的位置。
2808    pub interact_pointer_pos: Option<Option<[f32; 2]>>,
2809    /// 鼠标悬挂的位置。
2810    pub hover_pos: Option<Option<[f32; 2]>>,
2811    /// 鼠标是否按下按键。
2812    pub is_pointer_button_down_on: Option<bool>,
2813    /// 鼠标滚轮滚动幅度。
2814    pub raw_scroll_delta: Option<[f32; 2]>,
2815    /// 平滑鼠标滚轮滚动幅度。
2816    pub smooth_scroll_delta: Option<[f32; 2]>,
2817}
2818
2819/// RC的鼠标检测器资源。
2820#[derive(Debug, Clone, PartialEq, PartialOrd)]
2821pub struct MouseDetector {
2822    pub discern_type: String,
2823    pub name: String,
2824    pub active: bool,
2825    /// 位置。
2826    pub position: [f32; 2],
2827    /// 原始位置。
2828    pub origin_position: [f32; 2],
2829    /// 尺寸。
2830    pub size: [f32; 2],
2831    /// 原始尺寸。
2832    pub origin_size: [f32; 2],
2833    /// x轴的网格式缩放。
2834    pub x_size_grid: [u32; 2],
2835    /// y轴的网格式缩放。
2836    pub y_size_grid: [u32; 2],
2837    /// x轴的网格式定位。
2838    pub x_location_grid: [u32; 2],
2839    /// y轴的网格式定位。
2840    pub y_location_grid: [u32; 2],
2841    /// 对齐方法。
2842    pub center_display: (HorizontalAlign, VerticalAlign),
2843    /// 偏移量。
2844    pub offset: [f32; 2],
2845    /// 鼠标检测结果。
2846    pub detect_result: MouseDetectResult,
2847}
2848
2849impl RustConstructorResource for MouseDetector {
2850    fn name(&self) -> &str {
2851        &self.name
2852    }
2853
2854    fn expose_type(&self) -> &str {
2855        &self.discern_type
2856    }
2857
2858    fn active(&self) -> bool {
2859        self.active
2860    }
2861
2862    fn modify_active(&mut self, active: bool) {
2863        self.active = active;
2864    }
2865
2866    fn as_any(&self) -> &dyn Any {
2867        self
2868    }
2869
2870    fn as_any_mut(&mut self) -> &mut dyn Any {
2871        self
2872    }
2873}
2874
2875impl Default for MouseDetector {
2876    fn default() -> Self {
2877        Self {
2878            discern_type: String::from("MouseDetector"),
2879            name: String::from("MouseDetector"),
2880            active: false,
2881            position: [0_f32, 0_f32],
2882            origin_position: [0_f32, 0_f32],
2883            size: [100_f32, 100_f32],
2884            origin_size: [100_f32, 100_f32],
2885            x_size_grid: [0, 0],
2886            y_size_grid: [0, 0],
2887            x_location_grid: [0, 0],
2888            y_location_grid: [0, 0],
2889            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
2890            offset: [0_f32, 0_f32],
2891            detect_result: MouseDetectResult::default(),
2892        }
2893    }
2894}
2895
2896impl MouseDetector {
2897    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
2898        self.origin_position = position_config.origin_position;
2899        self.origin_size = position_config.origin_size;
2900        self.x_size_grid = position_config.x_size_grid;
2901        self.y_size_grid = position_config.y_size_grid;
2902        self.x_location_grid = position_config.x_location_grid;
2903        self.y_location_grid = position_config.y_location_grid;
2904        self.center_display = position_config.center_display;
2905        self.offset = position_config.offset;
2906        self
2907    }
2908
2909    #[inline]
2910    pub fn name(mut self, name: &str) -> Self {
2911        self.name = name.to_string();
2912        self
2913    }
2914
2915    #[inline]
2916    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
2917        self.origin_position = [x, y];
2918        self
2919    }
2920
2921    #[inline]
2922    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
2923        self.origin_size = [width, height];
2924        self
2925    }
2926
2927    #[inline]
2928    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
2929        self.x_size_grid = [fetch, total];
2930        self
2931    }
2932
2933    #[inline]
2934    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
2935        self.y_size_grid = [fetch, total];
2936        self
2937    }
2938
2939    #[inline]
2940    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
2941        self.x_location_grid = [fetch, total];
2942        self
2943    }
2944
2945    #[inline]
2946    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
2947        self.y_location_grid = [fetch, total];
2948        self
2949    }
2950
2951    #[inline]
2952    pub fn center_display(
2953        mut self,
2954        horizontal_align: HorizontalAlign,
2955        vertical_align: VerticalAlign,
2956    ) -> Self {
2957        self.center_display = (horizontal_align, vertical_align);
2958        self
2959    }
2960
2961    #[inline]
2962    pub fn offset(mut self, x: f32, y: f32) -> Self {
2963        self.offset = [x, y];
2964        self
2965    }
2966}
2967
2968/// 滚动区域滚动长度(尺寸)配置。
2969#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
2970pub enum ScrollLengthMethod {
2971    /// 固定尺寸。
2972    Fixed(f32),
2973    /// 自适应尺寸。
2974    #[default]
2975    AutoFit,
2976}
2977
2978/// 鼠标点击资源板的目的。
2979#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2980pub enum ClickAim {
2981    #[default]
2982    /// 移动资源板。
2983    Move,
2984    /// 在上方缩放。
2985    TopResize,
2986    /// 在下方缩放。
2987    BottomResize,
2988    /// 在左侧缩放。
2989    LeftResize,
2990    /// 在右侧缩放。
2991    RightResize,
2992    /// 在左上方缩放。
2993    LeftTopResize,
2994    /// 在右上方缩放。
2995    RightTopResize,
2996    /// 在左下方缩放。
2997    LeftBottomResize,
2998    /// 在右下方缩放。
2999    RightBottomResize,
3000}
3001
3002/// RC的资源板。
3003#[derive(Debug, Clone, PartialEq, PartialOrd)]
3004pub struct ResourcePanel {
3005    pub discern_type: String,
3006    pub name: String,
3007    pub active: bool,
3008    /// 尺寸。
3009    pub size: [f32; 2],
3010    /// 位置。
3011    pub position: [f32; 2],
3012    /// 原始位置。
3013    pub origin_position: [f32; 2],
3014    /// 原始尺寸。
3015    pub origin_size: [f32; 2],
3016    /// x轴的网格式定位。
3017    pub x_location_grid: [u32; 2],
3018    /// y轴的网格式定位。
3019    pub y_location_grid: [u32; 2],
3020    /// x轴的网格式缩放。
3021    pub x_size_grid: [u32; 2],
3022    /// y轴的网格式缩放。
3023    pub y_size_grid: [u32; 2],
3024    /// 居中显示方法。
3025    pub center_display: (HorizontalAlign, VerticalAlign),
3026    /// 偏移量。
3027    pub offset: [f32; 2],
3028    /// 是否可通过拖拽更改尺寸。
3029    pub resizable: [bool; 4],
3030    /// 是否在资源底部显示方框。
3031    pub display_rect: Option<CustomRectConfig>,
3032    /// 是否按下鼠标与按下后鼠标状态。
3033    pub last_frame_mouse_status: Option<([f32; 2], ClickAim, [f32; 2])>,
3034    /// 最小尺寸。
3035    pub min_size: [f32; 2],
3036    /// 最大尺寸(可选)。
3037    pub max_size: Option<[f32; 2]>,
3038    /// 允许拖动资源板。
3039    pub movable: [bool; 2],
3040    /// 滚动长度计算方法(不需要滚动留空即可)。
3041    pub scroll_length_method: [Option<ScrollLengthMethod>; 2],
3042    /// 滚动长度。
3043    pub scroll_length: [f32; 2],
3044    /// 滚动进度。
3045    pub scroll_progress: [f32; 2],
3046    /// 滚动敏感度。
3047    pub scroll_sensitivity: f32,
3048    /// 是否使用平滑滚动。
3049    pub use_smooth_scroll_delta: bool,
3050    /// 上一帧的滚动进度。
3051    pub last_frame_scroll_progress: [f32; 2],
3052}
3053
3054impl RustConstructorResource for ResourcePanel {
3055    fn name(&self) -> &str {
3056        &self.name
3057    }
3058
3059    fn expose_type(&self) -> &str {
3060        &self.discern_type
3061    }
3062
3063    fn active(&self) -> bool {
3064        self.active
3065    }
3066
3067    fn modify_active(&mut self, active: bool) {
3068        self.active = active;
3069    }
3070
3071    fn as_any(&self) -> &dyn Any {
3072        self
3073    }
3074
3075    fn as_any_mut(&mut self) -> &mut dyn Any {
3076        self
3077    }
3078}
3079
3080impl Default for ResourcePanel {
3081    fn default() -> Self {
3082        Self {
3083            discern_type: String::from("ResourcePanel"),
3084            name: String::from("ResourcePanel"),
3085            active: false,
3086            size: [100_f32, 100_f32],
3087            position: [0_f32, 0_f32],
3088            origin_position: [0_f32, 0_f32],
3089            origin_size: [100_f32, 100_f32],
3090            x_location_grid: [0, 0],
3091            y_location_grid: [0, 0],
3092            x_size_grid: [0, 0],
3093            y_size_grid: [0, 0],
3094            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
3095            offset: [0_f32, 0_f32],
3096            resizable: [true, true, true, true],
3097            display_rect: None,
3098            last_frame_mouse_status: None,
3099            min_size: [10_f32, 10_f32],
3100            max_size: None,
3101            movable: [true, true],
3102            scroll_length_method: [None, None],
3103            scroll_length: [0_f32, 0_f32],
3104            scroll_progress: [0_f32, 0_f32],
3105            scroll_sensitivity: 0_f32,
3106            use_smooth_scroll_delta: true,
3107            last_frame_scroll_progress: [0_f32, 0_f32],
3108        }
3109    }
3110}
3111
3112impl ResourcePanel {
3113    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
3114        self.center_display = position_config.center_display;
3115        self.offset = position_config.offset;
3116        self.origin_position = position_config.origin_position;
3117        self.origin_size = position_config.origin_size;
3118        self.x_size_grid = position_config.x_size_grid;
3119        self.y_size_grid = position_config.y_size_grid;
3120        self.x_location_grid = position_config.x_location_grid;
3121        self.y_location_grid = position_config.y_location_grid;
3122        self
3123    }
3124
3125    #[inline]
3126    pub fn name(mut self, name: &str) -> Self {
3127        self.name = name.to_string();
3128        self
3129    }
3130
3131    #[inline]
3132    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
3133        self.origin_position = [x, y];
3134        self
3135    }
3136
3137    #[inline]
3138    pub fn origin_size(mut self, width: f32, height: f32) -> Self {
3139        self.origin_size = [width, height];
3140        self
3141    }
3142
3143    #[inline]
3144    pub fn x_location_grid(mut self, fetch: u32, total: u32) -> Self {
3145        self.x_location_grid = [fetch, total];
3146        self
3147    }
3148
3149    #[inline]
3150    pub fn y_location_grid(mut self, fetch: u32, total: u32) -> Self {
3151        self.y_location_grid = [fetch, total];
3152        self
3153    }
3154
3155    #[inline]
3156    pub fn x_size_grid(mut self, fetch: u32, total: u32) -> Self {
3157        self.x_size_grid = [fetch, total];
3158        self
3159    }
3160
3161    #[inline]
3162    pub fn y_size_grid(mut self, fetch: u32, total: u32) -> Self {
3163        self.y_size_grid = [fetch, total];
3164        self
3165    }
3166
3167    #[inline]
3168    pub fn center_display(
3169        mut self,
3170        horizontal_align: HorizontalAlign,
3171        vertical_align: VerticalAlign,
3172    ) -> Self {
3173        self.center_display = (horizontal_align, vertical_align);
3174        self
3175    }
3176
3177    #[inline]
3178    pub fn offset(mut self, x: f32, y: f32) -> Self {
3179        self.offset = [x, y];
3180        self
3181    }
3182
3183    #[inline]
3184    pub fn resizable(mut self, top: bool, bottom: bool, left: bool, right: bool) -> Self {
3185        self.resizable = [top, bottom, left, right];
3186        self
3187    }
3188
3189    #[inline]
3190    pub fn display_rect(mut self, display_rect: Option<CustomRectConfig>) -> Self {
3191        self.display_rect = display_rect;
3192        self
3193    }
3194
3195    #[inline]
3196    pub fn min_size(mut self, width: f32, height: f32) -> Self {
3197        self.min_size = [width, height];
3198        self
3199    }
3200
3201    #[inline]
3202    pub fn max_size(mut self, max_size: Option<[f32; 2]>) -> Self {
3203        self.max_size = max_size;
3204        self
3205    }
3206
3207    #[inline]
3208    pub fn movable(mut self, horizontal: bool, vertical: bool) -> Self {
3209        self.movable = [horizontal, vertical];
3210        self
3211    }
3212
3213    #[inline]
3214    pub fn scroll_length_method(
3215        mut self,
3216        horizontal: Option<ScrollLengthMethod>,
3217        vertical: Option<ScrollLengthMethod>,
3218    ) -> Self {
3219        self.scroll_length_method = [horizontal, vertical];
3220        self
3221    }
3222
3223    #[inline]
3224    pub fn scroll_sensitivity(mut self, scroll_sensitivity: f32) -> Self {
3225        self.scroll_sensitivity = scroll_sensitivity;
3226        self
3227    }
3228
3229    #[inline]
3230    pub fn use_smooth_scroll_delta(mut self, use_smooth_scroll_delta: bool) -> Self {
3231        self.use_smooth_scroll_delta = use_smooth_scroll_delta;
3232        self
3233    }
3234}
3235
3236/// RC资源最基本的错误处理。
3237#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3238pub enum RustConstructorError {
3239    /// 资源名重复。
3240    ResourceNameRepetition {
3241        resource_name: String,
3242        resource_type: String,
3243    },
3244    /// 图片获取失败。
3245    ImageGetFailed { image_path: String },
3246    /// 图片未找到。
3247    ImageNotFound { image_name: String },
3248    /// 图片纹理未找到。
3249    ImageTextureNotFound { image_texture_name: String },
3250    /// 文本未找到。
3251    TextNotFound { text_name: String },
3252    /// 变量未找到。
3253    VariableNotFound { variable_name: String },
3254    /// 由于输入类型错误,变量值无法匹配。
3255    VariableTypeMismatch { variable_name: String },
3256    /// 分段时间未找到。
3257    SplitTimeNotFound { split_time_name: String },
3258    /// 开关外观数量不匹配。
3259    SwitchAppearanceMismatch { switch_name: String, differ: u32 },
3260    /// 开关填充资源类型不匹配。
3261    SwitchFillResourceMismatch {
3262        switch_name: String,
3263        fill_resource_name: String,
3264        fill_resource_type: String,
3265    },
3266    /// 开关未找到。
3267    SwitchNotFound { switch_name: String },
3268    /// 消息框已存在。
3269    MessageBoxAlreadyExists { message_box_name: String },
3270    /// 鼠标检测器未找到。
3271    MouseDetectorNotFound { mouse_detector_name: String },
3272    /// 获取字体失败。
3273    FontGetFailed { font_path: String },
3274    /// 字体未找到。
3275    FontNotFound { font_name: String },
3276    /// 矩形未找到。
3277    RectNotFound { rect_name: String },
3278    /// 资源板未找到。
3279    ResourcePanelNotFound { resource_panel_name: String },
3280    /// 资源未找到。
3281    ResourceNotFound {
3282        resource_name: String,
3283        resource_type: String,
3284    },
3285    /// 资源未命名。
3286    ResourceUntitled { resource_type: String },
3287    /// 页面未找到。
3288    PageNotFound { page_name: String },
3289    /// 自定义错误。
3290    CustomError {
3291        error_name: String,
3292        error_message: String,
3293        error_annotation: String,
3294    },
3295}
3296
3297impl Display for RustConstructorError {
3298    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3299        Debug::fmt(self, f)
3300    }
3301}
3302
3303impl Error for RustConstructorError {}
3304
3305impl Default for RustConstructorError {
3306    fn default() -> Self {
3307        RustConstructorError::ImageGetFailed {
3308            image_path: "".to_string(),
3309        }
3310    }
3311}
3312
3313/// 水平对齐方法。
3314#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
3315pub enum HorizontalAlign {
3316    /// 左对齐。
3317    #[default]
3318    Left,
3319    /// 居中对齐。
3320    Center,
3321    /// 右对齐。
3322    Right,
3323}
3324
3325/// 垂直对齐方法。
3326#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
3327pub enum VerticalAlign {
3328    /// 顶部对齐。
3329    #[default]
3330    Top,
3331    /// 居中对齐。
3332    Center,
3333    /// 底部对齐。
3334    Bottom,
3335}
3336
3337/// 程序主体。
3338#[derive(Debug)]
3339pub struct App {
3340    /// 配置项,用于控制出现问题时是否panic。
3341    pub strict_mode: bool,
3342    /// 配置项,用于全局控制是否在调用资源时检查资源是否存在。
3343    pub safe_mode: bool,
3344    /// RC资源。
3345    pub rust_constructor_resource: Vec<Box<dyn RustConstructorResource>>,
3346    /// 问题列表。
3347    pub problem_list: Vec<Problem>,
3348    /// RC资源刷新率。
3349    pub tick_interval: f32,
3350    /// 当前页面。
3351    pub current_page: String,
3352    /// 计时器。
3353    pub timer: Timer,
3354    /// 帧时间。
3355    pub frame_times: Vec<f32>,
3356    /// 上一帧时间。
3357    pub last_frame_time: Option<f64>,
3358    /// 标记哪些资源属于基本前端资源。
3359    pub basic_front_resource_list: Vec<String>,
3360}
3361
3362impl Default for App {
3363    fn default() -> Self {
3364        App {
3365            strict_mode: false,
3366            safe_mode: true,
3367            rust_constructor_resource: Vec::new(),
3368            problem_list: Vec::new(),
3369            tick_interval: 0.05,
3370            current_page: String::new(),
3371            timer: Timer::default(),
3372            frame_times: Vec::new(),
3373            last_frame_time: None,
3374            basic_front_resource_list: vec![
3375                String::from("Image"),
3376                String::from("Text"),
3377                String::from("CustomRect"),
3378            ],
3379        }
3380    }
3381}
3382
3383impl App {
3384    #[inline]
3385    pub fn strict_mode(mut self, strict_mode: bool) -> Self {
3386        self.strict_mode = strict_mode;
3387        self
3388    }
3389
3390    #[inline]
3391    pub fn safe_mode(mut self, safe_mode: bool) -> Self {
3392        self.safe_mode = safe_mode;
3393        self
3394    }
3395
3396    #[inline]
3397    pub fn tick_interval(mut self, tick_interval: f32) -> Self {
3398        self.tick_interval = tick_interval;
3399        self
3400    }
3401
3402    #[inline]
3403    pub fn current_page(mut self, current_page: &str) -> Self {
3404        self.current_page = current_page.to_string();
3405        self
3406    }
3407
3408    /// 打印资源活跃情况。
3409    pub fn print_resource_active_info(&self, display_complex_info: bool, format: bool) -> String {
3410        let mut text = String::from("Resource Active Info:\n");
3411        for rcr in &self.rust_constructor_resource {
3412            if rcr.active() {
3413                if display_complex_info {
3414                    text += &if format {
3415                        format!(
3416                            "\nName: {:?}\nType: {:?}\nDetail: {:#?}\n",
3417                            rcr.name(),
3418                            rcr.expose_type(),
3419                            rcr
3420                        )
3421                    } else {
3422                        format!(
3423                            "\nName: {:?}\nType: {:?}\nDetail: {:?}\n",
3424                            rcr.name(),
3425                            rcr.expose_type(),
3426                            rcr
3427                        )
3428                    };
3429                } else {
3430                    text += &format!("\nName: {:?}\nType: {:?}\n", rcr.name(), rcr.expose_type());
3431                };
3432            };
3433        }
3434        text
3435    }
3436
3437    /// 添加资源。
3438    pub fn add_resource<T: RustConstructorResource + 'static>(
3439        &mut self,
3440        mut resource: T,
3441        safe_mode: Option<bool>,
3442    ) -> Result<(), RustConstructorError> {
3443        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
3444            if self.check_resource_exists(resource.name(), resource.expose_type()) {
3445                self.problem_report_custom(
3446                    RustConstructorError::ResourceNameRepetition {
3447                        resource_name: resource.name().to_string(),
3448                        resource_type: resource.expose_type().to_string(),
3449                    },
3450                    SeverityLevel::SevereWarning,
3451                    self.problem_list.clone(),
3452                );
3453                return Err(RustConstructorError::ResourceNameRepetition {
3454                    resource_name: resource.name().to_string(),
3455                    resource_type: resource.expose_type().to_string(),
3456                });
3457            };
3458            if resource.name().is_empty() {
3459                self.problem_report_custom(
3460                    RustConstructorError::ResourceUntitled {
3461                        resource_type: resource.expose_type().to_string(),
3462                    },
3463                    SeverityLevel::SevereWarning,
3464                    self.problem_list.clone(),
3465                );
3466                return Err(RustConstructorError::ResourceUntitled {
3467                    resource_type: resource.expose_type().to_string(),
3468                });
3469            };
3470        };
3471        match resource.expose_type() {
3472            "PageData" => {}
3473            "CustomRect" => {}
3474            "Text" => {}
3475            "Variable" => {}
3476            "MouseDetector" => {}
3477            "SplitTime" => {
3478                let split_time = resource.as_any_mut().downcast_mut::<SplitTime>().unwrap();
3479                split_time.time = [self.timer.now_time, self.timer.total_time];
3480            }
3481            "ResourcePanel" => {
3482                let resource_panel = resource
3483                    .as_any_mut()
3484                    .downcast_mut::<ResourcePanel>()
3485                    .unwrap();
3486                if resource_panel.display_rect.is_some() {
3487                    self.add_resource(
3488                        CustomRect::default().name(&format!("{}DisplayRect", resource_panel.name)),
3489                        safe_mode,
3490                    )
3491                    .unwrap();
3492                };
3493            }
3494            "ImageTexture" => {
3495                let image_texture = resource
3496                    .as_any_mut()
3497                    .downcast_mut::<ImageTexture>()
3498                    .unwrap();
3499                if let Ok(mut file) = File::open(image_texture.cite_path.clone()) {
3500                    let mut buffer = Vec::new();
3501                    file.read_to_end(&mut buffer).unwrap();
3502                    let img_bytes = buffer;
3503                    let img = image::load_from_memory(&img_bytes).unwrap();
3504                    let color_data = match image_texture.flip {
3505                        [true, true] => img.fliph().flipv().into_rgba8(),
3506                        [true, false] => img.fliph().into_rgba8(),
3507                        [false, true] => img.flipv().into_rgba8(),
3508                        _ => img.into_rgba8(),
3509                    };
3510                    let (w, h) = (color_data.width(), color_data.height());
3511                    let raw_data: Vec<u8> = color_data.into_raw();
3512
3513                    let color_image =
3514                        ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3515                    let loaded_image_texture = image_texture.ctx.load_texture(
3516                        image_texture.name.clone(),
3517                        color_image,
3518                        TextureOptions::LINEAR,
3519                    );
3520                    image_texture.texture = Some(DebugTextureHandle::new(loaded_image_texture));
3521                    image_texture.cite_path = image_texture.cite_path.to_string();
3522                } else {
3523                    self.problem_report_custom(
3524                        RustConstructorError::ImageGetFailed {
3525                            image_path: image_texture.cite_path.to_string(),
3526                        },
3527                        SeverityLevel::SevereWarning,
3528                        self.problem_list.clone(),
3529                    );
3530                };
3531            }
3532            "Image" => {
3533                let image = resource.as_any_mut().downcast_mut::<Image>().unwrap();
3534                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3535                    && !self.check_resource_exists(&image.cite_texture, "ImageTexture")
3536                {
3537                    self.problem_report_custom(
3538                        RustConstructorError::ImageTextureNotFound {
3539                            image_texture_name: image.cite_texture.clone(),
3540                        },
3541                        SeverityLevel::SevereWarning,
3542                        self.problem_list.clone(),
3543                    );
3544                    return Err(RustConstructorError::ImageTextureNotFound {
3545                        image_texture_name: image.cite_texture.clone(),
3546                    });
3547                };
3548                let image_texture = self
3549                    .get_resource::<ImageTexture>(&image.cite_texture, "ImageTexture")
3550                    .unwrap()
3551                    .unwrap();
3552                image.texture = image_texture.texture.clone();
3553                image.last_frame_cite_texture = image_texture.name.clone();
3554            }
3555            "Font" => {
3556                let font = resource.as_any_mut().downcast_mut::<Font>().unwrap();
3557                let mut fonts = FontDefinitions::default();
3558                if let Ok(font_read_data) = read(font.path.clone()) {
3559                    let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3560                    fonts.font_data.insert(
3561                        font.name.to_owned(),
3562                        Arc::new(FontData::from_owned(
3563                            Arc::try_unwrap(font_data).ok().unwrap(),
3564                        )),
3565                    );
3566
3567                    // 将字体添加到字体列表中
3568                    fonts
3569                        .families
3570                        .entry(FontFamily::Proportional)
3571                        .or_default()
3572                        .insert(0, font.name.to_owned());
3573
3574                    fonts
3575                        .families
3576                        .entry(FontFamily::Monospace)
3577                        .or_default()
3578                        .insert(0, font.name.to_owned());
3579
3580                    font.font_definitions = fonts;
3581                } else {
3582                    self.problem_report_custom(
3583                        RustConstructorError::FontGetFailed {
3584                            font_path: font.path.to_string(),
3585                        },
3586                        SeverityLevel::SevereWarning,
3587                        self.problem_list.clone(),
3588                    );
3589                    return Err(RustConstructorError::FontGetFailed {
3590                        font_path: font.path.to_string(),
3591                    });
3592                }
3593            }
3594            "Switch" => {
3595                let switch = resource.as_any_mut().downcast_mut::<Switch>().unwrap();
3596                let mut count = 1;
3597                if switch.enable_hover_click_fill_resource[0] {
3598                    count += 1;
3599                };
3600                if switch.enable_hover_click_fill_resource[1] {
3601                    count += 1;
3602                };
3603                if switch.appearance.len() < count {
3604                    self.problem_report_custom(
3605                        RustConstructorError::SwitchAppearanceMismatch {
3606                            switch_name: switch.name.clone(),
3607                            differ: count as u32 - switch.appearance.len() as u32,
3608                        },
3609                        SeverityLevel::SevereWarning,
3610                        self.problem_list.clone(),
3611                    );
3612                    return Err(RustConstructorError::SwitchAppearanceMismatch {
3613                        switch_name: switch.name.clone(),
3614                        differ: count as u32 - switch.appearance.len() as u32,
3615                    });
3616                };
3617                for _ in 0..switch.appearance.len() % count {
3618                    switch.appearance.pop();
3619                }
3620                if self.check_resource_exists(&switch.text_name, "Text") {
3621                    let t = self
3622                        .get_resource_mut::<Text>(&switch.text_name, "Text")
3623                        .unwrap()
3624                        .unwrap();
3625                    switch.text_origin_position = t.origin_position;
3626                    t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
3627                    t.x_location_grid = [0, 0];
3628                    t.y_location_grid = [0, 0];
3629                } else if !switch.text_name.is_empty() {
3630                    switch.text_name = String::new();
3631                    self.problem_report_custom(
3632                        RustConstructorError::TextNotFound {
3633                            text_name: switch.text_name.clone(),
3634                        },
3635                        SeverityLevel::SevereWarning,
3636                        self.problem_list.clone(),
3637                    );
3638                };
3639                if self
3640                    .check_resource_exists(&switch.fill_resource_name, &switch.fill_resource_type)
3641                {
3642                    match switch.fill_resource_type.as_str() {
3643                        "Image" | "CustomRect" => {
3644                            switch.fill_resource_name = switch.fill_resource_name.clone();
3645                            switch.fill_resource_type = switch.fill_resource_type.clone();
3646                        }
3647                        _ => {
3648                            self.problem_report_custom(
3649                                RustConstructorError::SwitchFillResourceMismatch {
3650                                    switch_name: switch.name.clone(),
3651                                    fill_resource_name: switch.fill_resource_name.clone(),
3652                                    fill_resource_type: switch.fill_resource_type.clone(),
3653                                },
3654                                SeverityLevel::SevereWarning,
3655                                self.problem_list.clone(),
3656                            );
3657                            return Err(RustConstructorError::SwitchFillResourceMismatch {
3658                                switch_name: switch.name.clone(),
3659                                fill_resource_name: switch.fill_resource_name.clone(),
3660                                fill_resource_type: switch.fill_resource_type.clone(),
3661                            });
3662                        }
3663                    };
3664                } else {
3665                    self.problem_report_custom(
3666                        RustConstructorError::ResourceNotFound {
3667                            resource_name: switch.fill_resource_name.clone(),
3668                            resource_type: switch.fill_resource_type.clone(),
3669                        },
3670                        SeverityLevel::SevereWarning,
3671                        self.problem_list.clone(),
3672                    );
3673                    return Err(RustConstructorError::ResourceNotFound {
3674                        resource_name: switch.fill_resource_name.clone(),
3675                        resource_type: switch.fill_resource_type.clone(),
3676                    });
3677                };
3678                if switch
3679                    .appearance
3680                    .iter()
3681                    .filter(|x| !x.hint_text.is_empty())
3682                    .count()
3683                    > 0
3684                {
3685                    switch.hint_text_name = format!("{}Hint", switch.name);
3686                    self.add_resource(
3687                        Text::default()
3688                            .name(&format!("{}Hint", switch.name))
3689                            .content("")
3690                            .origin_position(0_f32, 0_f32)
3691                            .font_size(25_f32)
3692                            .origin_size(300_f32, 0_f32)
3693                            .background_rounding(10_f32)
3694                            .color(255, 255, 255, 0)
3695                            .background_color(0, 0, 0, 255)
3696                            .center_display(HorizontalAlign::Left, VerticalAlign::Top)
3697                            .selectable(false),
3698                        safe_mode,
3699                    )
3700                    .unwrap();
3701                    self.add_resource(
3702                        SplitTime::default().name(&format!("{}StartHoverTime", switch.name)),
3703                        safe_mode,
3704                    )
3705                    .unwrap();
3706                    self.add_resource(
3707                        SplitTime::default().name(&format!("{}HintFadeAnimation", switch.name)),
3708                        safe_mode,
3709                    )
3710                    .unwrap();
3711                };
3712                switch.animation_count = count as u32;
3713            }
3714            "MessageBox" => {
3715                let message_box = resource.as_any_mut().downcast_mut::<MessageBox>().unwrap();
3716                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3717                    && self.check_resource_exists(&message_box.name, "MessageBox")
3718                {
3719                    self.problem_report_custom(
3720                        RustConstructorError::MessageBoxAlreadyExists {
3721                            message_box_name: message_box.name.clone(),
3722                        },
3723                        SeverityLevel::SevereWarning,
3724                        self.problem_list.clone(),
3725                    );
3726                    return Err(RustConstructorError::MessageBoxAlreadyExists {
3727                        message_box_name: message_box.name.clone(),
3728                    });
3729                };
3730                message_box.exist = true;
3731                message_box.memory_offset = 0_f32;
3732
3733                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3734                    && !self.check_resource_exists(&message_box.image_name, "Image")
3735                {
3736                    self.problem_report_custom(
3737                        RustConstructorError::ImageNotFound {
3738                            image_name: message_box.image_name.clone(),
3739                        },
3740                        SeverityLevel::SevereWarning,
3741                        self.problem_list.clone(),
3742                    );
3743                    return Err(RustConstructorError::ImageNotFound {
3744                        image_name: message_box.image_name.clone(),
3745                    });
3746                };
3747                let im = self
3748                    .get_resource_mut::<Image>(&message_box.image_name, "Image")
3749                    .unwrap()
3750                    .unwrap();
3751                im.origin_size = [message_box.size[1] - 15_f32, message_box.size[1] - 15_f32];
3752                im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
3753                im.x_location_grid = [1, 1];
3754                im.y_location_grid = [0, 1];
3755                im.x_size_grid = [0, 0];
3756                im.y_size_grid = [0, 0];
3757                im.name = format!("MessageBox{}", im.name);
3758                message_box.image_name = im.name.to_string();
3759
3760                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3761                    && !self.check_resource_exists(&message_box.title_name, "Text")
3762                {
3763                    self.problem_report_custom(
3764                        RustConstructorError::TextNotFound {
3765                            text_name: message_box.title_name.clone(),
3766                        },
3767                        SeverityLevel::SevereWarning,
3768                        self.problem_list.clone(),
3769                    );
3770                    return Err(RustConstructorError::TextNotFound {
3771                        text_name: message_box.title_name.clone(),
3772                    });
3773                };
3774                let t = self
3775                    .get_resource_mut::<Text>(&message_box.title_name, "Text")
3776                    .unwrap()
3777                    .unwrap();
3778                t.x_location_grid = [1, 1];
3779                t.y_location_grid = [0, 1];
3780                t.x_size_grid = [0, 0];
3781                t.y_size_grid = [0, 0];
3782                t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3783                t.origin_size[0] = message_box.size[0] - message_box.size[1] + 5_f32;
3784                t.name = format!("MessageBox{}", t.name);
3785                message_box.title_name = t.name.to_string();
3786
3787                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3788                    && !self.check_resource_exists(&message_box.content_name, "Text")
3789                {
3790                    self.problem_report_custom(
3791                        RustConstructorError::TextNotFound {
3792                            text_name: message_box.content_name.clone(),
3793                        },
3794                        SeverityLevel::SevereWarning,
3795                        self.problem_list.clone(),
3796                    );
3797                    return Err(RustConstructorError::TextNotFound {
3798                        text_name: message_box.content_name.clone(),
3799                    });
3800                };
3801                let t = self
3802                    .get_resource_mut::<Text>(&message_box.content_name, "Text")
3803                    .unwrap()
3804                    .unwrap();
3805                t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3806                t.x_location_grid = [1, 1];
3807                t.y_location_grid = [0, 1];
3808                t.x_size_grid = [0, 0];
3809                t.y_size_grid = [0, 0];
3810                t.origin_size[0] = message_box.size[0] - message_box.size[1] + 5_f32;
3811                t.name = format!("MessageBox{}", t.name);
3812                message_box.content_name = t.name.to_string();
3813
3814                if !message_box.keep_existing {
3815                    self.add_resource(
3816                        SplitTime::default().name(&format!("MessageBox{}", message_box.name)),
3817                        safe_mode,
3818                    )
3819                    .unwrap();
3820                };
3821
3822                self.add_resource(
3823                    SplitTime::default().name(&format!("MessageBox{}Animation", message_box.name)),
3824                    safe_mode,
3825                )
3826                .unwrap();
3827
3828                self.add_resource(
3829                    CustomRect::default()
3830                        .name(&format!("MessageBox{}", message_box.name))
3831                        .origin_position(0_f32, 0_f32)
3832                        .origin_size(message_box.size[0], message_box.size[1])
3833                        .rounding(20_f32)
3834                        .x_location_grid(1, 1)
3835                        .y_location_grid(0, 1)
3836                        .center_display(HorizontalAlign::Left, VerticalAlign::Top)
3837                        .color(100, 100, 100, 125)
3838                        .border_width(0_f32),
3839                    safe_mode,
3840                )
3841                .unwrap();
3842
3843                if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
3844                    match message_box.close_switch_fill_resource_type.as_str() {
3845                        "Image" | "CustomRect" => {}
3846                        _ => {
3847                            self.problem_report_custom(
3848                                RustConstructorError::SwitchFillResourceMismatch {
3849                                    switch_name: format!("MessageBox{}Close", message_box.name),
3850                                    fill_resource_name: message_box
3851                                        .close_switch_fill_resource_name
3852                                        .clone(),
3853                                    fill_resource_type: message_box
3854                                        .close_switch_fill_resource_type
3855                                        .clone(),
3856                                },
3857                                SeverityLevel::SevereWarning,
3858                                self.problem_list.clone(),
3859                            );
3860                            return Err(RustConstructorError::SwitchFillResourceMismatch {
3861                                switch_name: format!("MessageBox{}Close", message_box.name),
3862                                fill_resource_name: message_box
3863                                    .close_switch_fill_resource_name
3864                                    .clone(),
3865                                fill_resource_type: message_box
3866                                    .close_switch_fill_resource_type
3867                                    .clone(),
3868                            });
3869                        }
3870                    };
3871                };
3872
3873                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3874                    && !self.check_resource_exists(
3875                        &message_box.close_switch_fill_resource_name,
3876                        &message_box.close_switch_fill_resource_type,
3877                    )
3878                {
3879                    self.problem_report_custom(
3880                        RustConstructorError::ResourceNotFound {
3881                            resource_name: message_box.close_switch_fill_resource_name.clone(),
3882                            resource_type: message_box.close_switch_fill_resource_type.clone(),
3883                        },
3884                        SeverityLevel::SevereWarning,
3885                        self.problem_list.clone(),
3886                    );
3887                    return Err(RustConstructorError::ResourceNotFound {
3888                        resource_name: message_box.close_switch_fill_resource_name.clone(),
3889                        resource_type: message_box.close_switch_fill_resource_type.clone(),
3890                    });
3891                };
3892
3893                let (texture, image_config, custom_rect_config, color, border_color) =
3894                    match message_box.close_switch_fill_resource_type.as_str() {
3895                        "Image" => {
3896                            let im = self
3897                                .get_resource_mut::<Image>(
3898                                    &message_box.close_switch_fill_resource_name,
3899                                    "Image",
3900                                )
3901                                .unwrap()
3902                                .unwrap();
3903                            im.name = format!(
3904                                "MessageBox{}Close",
3905                                message_box.close_switch_fill_resource_name
3906                            );
3907                            (
3908                                im.cite_texture.clone(),
3909                                ImageConfig::from_image(im)
3910                                    .origin_size(30_f32, 30_f32)
3911                                    .center_display(HorizontalAlign::Center, VerticalAlign::Center),
3912                                CustomRectConfig::default(),
3913                                im.overlay_color,
3914                                [0, 0, 0, 0],
3915                            )
3916                        }
3917                        "CustomRect" => {
3918                            let cr = self
3919                                .get_resource_mut::<CustomRect>(
3920                                    &message_box.close_switch_fill_resource_name,
3921                                    "CustomRect",
3922                                )
3923                                .unwrap()
3924                                .unwrap();
3925                            cr.name = format!(
3926                                "MessageBox{}Close",
3927                                message_box.close_switch_fill_resource_name
3928                            );
3929                            (
3930                                String::new(),
3931                                ImageConfig::default(),
3932                                CustomRectConfig::from_custom_rect(cr)
3933                                    .origin_size(30_f32, 30_f32)
3934                                    .center_display(HorizontalAlign::Center, VerticalAlign::Center),
3935                                cr.color,
3936                                cr.border_color,
3937                            )
3938                        }
3939                        _ => {
3940                            self.problem_report_custom(
3941                                RustConstructorError::SwitchFillResourceMismatch {
3942                                    switch_name: format!("MessageBox{}Close", message_box.name),
3943                                    fill_resource_name: message_box
3944                                        .close_switch_fill_resource_name
3945                                        .clone(),
3946                                    fill_resource_type: message_box
3947                                        .close_switch_fill_resource_type
3948                                        .clone(),
3949                                },
3950                                SeverityLevel::SevereWarning,
3951                                self.problem_list.clone(),
3952                            );
3953                            return Err(RustConstructorError::SwitchFillResourceMismatch {
3954                                switch_name: format!("MessageBox{}Close", message_box.name),
3955                                fill_resource_name: message_box
3956                                    .close_switch_fill_resource_name
3957                                    .clone(),
3958                                fill_resource_type: message_box
3959                                    .close_switch_fill_resource_type
3960                                    .clone(),
3961                            });
3962                        }
3963                    };
3964
3965                self.add_resource(
3966                    Switch::default()
3967                        .name(&format!("MessageBox{}Close", message_box.name))
3968                        .appearance(vec![
3969                            SwitchAppearance {
3970                                image_config: image_config
3971                                    .clone()
3972                                    .overlay_color(color[0], color[1], color[2], 0),
3973                                custom_rect_config: custom_rect_config
3974                                    .clone()
3975                                    .color(color[0], color[1], color[2], 0)
3976                                    .border_color(
3977                                        border_color[0],
3978                                        border_color[1],
3979                                        border_color[2],
3980                                        0,
3981                                    ),
3982                                text_config: TextConfig::default(),
3983                                texture: texture.clone(),
3984                                hint_text: String::new(),
3985                            },
3986                            SwitchAppearance {
3987                                image_config: image_config.clone().overlay_color(
3988                                    (color[0] as u32 * 180 / 255) as u8,
3989                                    (color[1] as u32 * 180 / 255) as u8,
3990                                    (color[2] as u32 * 180 / 255) as u8,
3991                                    255,
3992                                ),
3993                                custom_rect_config: custom_rect_config
3994                                    .clone()
3995                                    .color(
3996                                        (color[0] as u32 * 180 / 255) as u8,
3997                                        (color[1] as u32 * 180 / 255) as u8,
3998                                        (color[2] as u32 * 180 / 255) as u8,
3999                                        255,
4000                                    )
4001                                    .border_color(
4002                                        (border_color[0] as u32 * 180 / 255) as u8,
4003                                        (border_color[1] as u32 * 180 / 255) as u8,
4004                                        (border_color[2] as u32 * 180 / 255) as u8,
4005                                        255,
4006                                    ),
4007                                text_config: TextConfig::default(),
4008                                texture: texture.clone(),
4009                                hint_text: String::new(),
4010                            },
4011                            SwitchAppearance {
4012                                image_config: image_config.clone().overlay_color(0, 0, 0, 0),
4013                                custom_rect_config: custom_rect_config
4014                                    .clone()
4015                                    .color(0, 0, 0, 0)
4016                                    .border_color(0, 0, 0, 0),
4017                                text_config: TextConfig::default(),
4018                                texture: texture.clone(),
4019                                hint_text: String::new(),
4020                            },
4021                            SwitchAppearance {
4022                                image_config: image_config.overlay_color(0, 0, 0, 0),
4023                                custom_rect_config: custom_rect_config
4024                                    .color(0, 0, 0, 0)
4025                                    .border_color(0, 0, 0, 0),
4026                                text_config: TextConfig::default(),
4027                                texture,
4028                                hint_text: String::new(),
4029                            },
4030                        ])
4031                        .enable_hover_click_fill_resource(false, true)
4032                        .click_method(vec![SwitchClickAction {
4033                            click_method: PointerButton::Primary,
4034                            action: true,
4035                        }])
4036                        .fill_resource_name(&format!(
4037                            "MessageBox{}Close",
4038                            message_box.close_switch_fill_resource_name
4039                        ))
4040                        .fill_resource_type(&message_box.close_switch_fill_resource_type)
4041                        .text_name(""),
4042                    safe_mode,
4043                )
4044                .unwrap();
4045            }
4046            _ => {}
4047        };
4048        self.rust_constructor_resource.push(Box::new(resource));
4049        Ok(())
4050    }
4051
4052    /// 整合所有页面需要一次性处理的功能。
4053    pub fn page_data(
4054        &mut self,
4055        ctx: &Context,
4056        safe_mode: Option<bool>,
4057    ) -> Result<(), RustConstructorError> {
4058        // 更新帧数
4059        self.update_frame_stats(ctx);
4060        // 更新资源活跃状态。
4061        for rcr in &mut self.rust_constructor_resource {
4062            rcr.modify_active(false);
4063        }
4064        // 更新计时器
4065        self.update_timer();
4066        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4067            && !self.check_resource_exists(&self.current_page, "PageData")
4068        {
4069            self.problem_report_custom(
4070                RustConstructorError::PageNotFound {
4071                    page_name: self.current_page.clone(),
4072                },
4073                SeverityLevel::MildWarning,
4074                self.problem_list.clone(),
4075            );
4076            return Err(RustConstructorError::PageNotFound {
4077                page_name: self.current_page.clone(),
4078            });
4079        };
4080        let page_data = self
4081            .get_resource_mut::<PageData>(&self.current_page.clone(), "PageData")
4082            .unwrap()
4083            .unwrap();
4084        page_data.modify_active(true);
4085        if page_data.forced_update {
4086            ctx.request_repaint();
4087        };
4088        Ok(())
4089    }
4090
4091    /// 切换页面。
4092    pub fn switch_page(
4093        &mut self,
4094        name: &str,
4095        safe_mode: Option<bool>,
4096    ) -> Result<(), RustConstructorError> {
4097        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4098            && !self.check_resource_exists(name, "PageData")
4099        {
4100            self.problem_report_custom(
4101                RustConstructorError::PageNotFound {
4102                    page_name: name.to_string(),
4103                },
4104                SeverityLevel::SevereWarning,
4105                self.problem_list.clone(),
4106            );
4107            return Err(RustConstructorError::PageNotFound {
4108                page_name: name.to_string(),
4109            });
4110        };
4111        self.current_page = name.to_string();
4112        let pd = self
4113            .get_resource_mut::<PageData>(name, "PageData")
4114            .unwrap()
4115            .unwrap();
4116        pd.enter_page_updated = false;
4117        self.timer.start_time = self.timer.total_time;
4118        self.update_timer();
4119        Ok(())
4120    }
4121
4122    /// 从列表中替换资源。
4123    pub fn replace_resource<T>(
4124        &mut self,
4125        name: &str,
4126        discern_type: &str,
4127        resource: T,
4128    ) -> Result<(), RustConstructorError>
4129    where
4130        T: RustConstructorResource + 'static,
4131    {
4132        if let Some(index) = self
4133            .rust_constructor_resource
4134            .iter()
4135            .position(|x| x.name() == name && x.expose_type() == discern_type)
4136        {
4137            self.rust_constructor_resource[index] = Box::new(resource);
4138            Ok(())
4139        } else {
4140            self.problem_report_custom(
4141                RustConstructorError::ResourceNotFound {
4142                    resource_name: name.to_string(),
4143                    resource_type: discern_type.to_string(),
4144                },
4145                SeverityLevel::SevereWarning,
4146                self.problem_list.clone(),
4147            );
4148            Err(RustConstructorError::ResourceNotFound {
4149                resource_name: name.to_string(),
4150                resource_type: discern_type.to_string(),
4151            })
4152        }
4153    }
4154
4155    /// 从列表中获取不可变资源。
4156    pub fn get_resource<T>(
4157        &self,
4158        name: &str,
4159        discern_type: &str,
4160    ) -> Result<Option<&T>, RustConstructorError>
4161    where
4162        T: RustConstructorResource + 'static,
4163    {
4164        if self.check_resource_exists(name, discern_type) {
4165            Ok(self
4166                .rust_constructor_resource
4167                .iter()
4168                .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
4169                .and_then(|resource| resource.as_any().downcast_ref::<T>()))
4170        } else {
4171            self.problem_report_custom(
4172                RustConstructorError::ResourceNotFound {
4173                    resource_name: name.to_string(),
4174                    resource_type: discern_type.to_string(),
4175                },
4176                SeverityLevel::SevereWarning,
4177                self.problem_list.clone(),
4178            );
4179            Err(RustConstructorError::ResourceNotFound {
4180                resource_name: name.to_string(),
4181                resource_type: discern_type.to_string(),
4182            })
4183        }
4184    }
4185
4186    /// 从列表中获取可变资源。
4187    pub fn get_resource_mut<T>(
4188        &mut self,
4189        name: &str,
4190        discern_type: &str,
4191    ) -> Result<Option<&mut T>, RustConstructorError>
4192    where
4193        T: RustConstructorResource + 'static,
4194    {
4195        if self.check_resource_exists(name, discern_type) {
4196            Ok(self
4197                .rust_constructor_resource
4198                .iter_mut()
4199                .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
4200                .and_then(|resource| resource.as_any_mut().downcast_mut::<T>()))
4201        } else {
4202            self.problem_report_custom(
4203                RustConstructorError::ResourceNotFound {
4204                    resource_name: name.to_string(),
4205                    resource_type: discern_type.to_string(),
4206                },
4207                SeverityLevel::SevereWarning,
4208                self.problem_list.clone(),
4209            );
4210            Err(RustConstructorError::ResourceNotFound {
4211                resource_name: name.to_string(),
4212                resource_type: discern_type.to_string(),
4213            })
4214        }
4215    }
4216
4217    /// 检查是否存在特定资源。
4218    pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> bool {
4219        self.rust_constructor_resource
4220            .iter()
4221            .any(|x| x.name() == name && x.expose_type() == discern_type)
4222    }
4223
4224    /// 输出字体资源。
4225    pub fn font(
4226        &mut self,
4227        name: &str,
4228        safe_mode: Option<bool>,
4229    ) -> Result<FontDefinitions, RustConstructorError> {
4230        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4231            && !self.check_resource_exists(name, "Font")
4232        {
4233            self.problem_report_custom(
4234                RustConstructorError::FontNotFound {
4235                    font_name: name.to_string(),
4236                },
4237                SeverityLevel::SevereWarning,
4238                self.problem_list.clone(),
4239            );
4240            return Err(RustConstructorError::FontNotFound {
4241                font_name: name.to_string(),
4242            });
4243        };
4244        let f = self
4245            .get_resource_mut::<Font>(name, "Font")
4246            .unwrap()
4247            .unwrap();
4248        f.modify_active(true);
4249        Ok(f.font_definitions.clone())
4250    }
4251
4252    /// 将所有已添加到RC的字体资源添加到egui中。
4253    pub fn register_all_fonts(&mut self, ctx: &Context, safe_mode: Option<bool>) {
4254        let mut font_definitions = FontDefinitions::default();
4255        let mut font_resources = Vec::new();
4256        for i in 0..self.rust_constructor_resource.len() {
4257            if let Some(f) = self.rust_constructor_resource[i]
4258                .as_any()
4259                .downcast_ref::<Font>()
4260            {
4261                font_resources.push(f.clone());
4262            };
4263        }
4264        for i in &font_resources {
4265            let font_name = i.name.clone();
4266            // 获取字体数据(返回 FontDefinitions)
4267            if let Ok(font_def) = self.font(&font_name, safe_mode) {
4268                // 从 font_def 中提取对应字体的 Arc<FontData>
4269                if let Some(font_data) = font_def.font_data.get(&font_name) {
4270                    font_definitions
4271                        .font_data
4272                        .insert(font_name.clone(), Arc::clone(font_data));
4273                    font_definitions
4274                        .families
4275                        .entry(FontFamily::Name(font_name.clone().into()))
4276                        .or_default()
4277                        .push(font_name.clone());
4278                };
4279
4280                // 将字体添加到字体列表中
4281                font_definitions
4282                    .families
4283                    .entry(FontFamily::Proportional)
4284                    .or_default()
4285                    .insert(0, font_name.to_owned());
4286
4287                font_definitions
4288                    .families
4289                    .entry(FontFamily::Monospace)
4290                    .or_default()
4291                    .insert(0, font_name.to_owned());
4292            };
4293        }
4294        ctx.set_fonts(font_definitions);
4295    }
4296
4297    /// 处理错误。
4298    pub fn problem_processor(
4299        &self,
4300        problem_type: RustConstructorError,
4301        severity_level: SeverityLevel,
4302    ) -> (String, String) {
4303        let (problem, annotation) = match problem_type.clone() {
4304            RustConstructorError::ResourceNameRepetition { resource_name, resource_type } => (
4305                format!(
4306                    "Resource name repetition({:?}): {}({})",
4307                    severity_level, resource_name, resource_type
4308                ),
4309                "Please check whether the resource name is repeated.".to_string(),
4310            ),
4311
4312            RustConstructorError::FontGetFailed { font_path } => (
4313                format!("Font get failed({:?}): {}", severity_level, font_path,),
4314                "Please check if the font file exists and the path is correct.".to_string(),
4315            ),
4316            RustConstructorError::FontNotFound { font_name } => (
4317                format!("Font not found({:?}): {}", severity_level, font_name,),
4318                "Please check whether the font has been added.".to_string(),
4319            ),
4320            RustConstructorError::ImageGetFailed { image_path } => (
4321                format!("Image get failed({:?}): {}", severity_level, image_path,),
4322                "Please check whether the image path is correct and whether the image has been added.".to_string(),
4323            ),
4324            RustConstructorError::ImageNotFound { image_name } => (
4325                format!("Image not found({:?}): {}", severity_level, image_name,),
4326                "Please check whether the image has been added.".to_string(),
4327            ),
4328            RustConstructorError::ImageTextureNotFound { image_texture_name } => (
4329                format!("Image texture not found({:?}): {}", severity_level, image_texture_name,),
4330                "Please check whether the image texture has been added.".to_string(),
4331            ),
4332            RustConstructorError::TextNotFound { text_name } => (
4333                format!("Text not found({:?}): {}", severity_level, text_name,),
4334                "Please check whether the text has been added.".to_string(),
4335            ),
4336            RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
4337                format!("Message box already exists({:?}): {}", severity_level, message_box_name,),
4338                "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
4339            ),
4340            RustConstructorError::MouseDetectorNotFound { mouse_detector_name } => (
4341                format!("Mouse detector not found({:?}): {}", severity_level, mouse_detector_name,),
4342                "Please check whether the mouse detector has been added.".to_string(),
4343            ),
4344            RustConstructorError::SplitTimeNotFound { split_time_name } => (
4345                format!("Split time not found({:?}): {}", severity_level, split_time_name,),
4346                "Please check whether the split time has been added.".to_string(),
4347            ),
4348            RustConstructorError::SwitchAppearanceMismatch {
4349                switch_name,
4350                differ,
4351            } => (
4352                format!(
4353                    "Switch appearance list's number of items is large / small {} more({:?}): {}",
4354                    differ, severity_level, switch_name
4355                ),
4356                "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
4357            ),
4358            RustConstructorError::SwitchNotFound { switch_name } => (
4359                format!("Switch not found({:?}): {}", severity_level, switch_name,),
4360                "Please check whether the switch has been added.".to_string(),
4361            ),
4362            RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
4363                format!("Switch fill resource mismatch({:?}): Resource {} of switch {} is not of type {}", severity_level, fill_resource_name, switch_name, fill_resource_type,),
4364                "Please check whether the imported fill resource is correctly typed.".to_string(),
4365            ),
4366            RustConstructorError::PageNotFound { page_name } => (
4367                format!("Page not found({:?}): {}", severity_level, page_name,),
4368                "Please check whether the page has been added.".to_string(),
4369            ),
4370            RustConstructorError::VariableNotFound { variable_name } => (
4371                format!("Variable not found({:?}): {}", severity_level, variable_name,),
4372                "Please check whether the variable has been added.".to_string(),
4373            ),
4374            RustConstructorError::VariableTypeMismatch { variable_name } => (
4375                format!("Variable type mismatch({:?}): {}", severity_level, variable_name,),
4376                "Please check whether the generics used for matching are filled correctly.".to_string(),
4377            ),
4378            RustConstructorError::RectNotFound { rect_name } => (
4379                format!("Rect not found({:?}): {}", severity_level, rect_name,),
4380                "Please check whether the rect has been added.".to_string(),
4381            ),
4382            RustConstructorError::ResourcePanelNotFound { resource_panel_name } => (
4383                format!("Resource panel not found({:?}): {}", severity_level, resource_panel_name,),
4384                "Please check whether the resource panel has been added.".to_string(),
4385            ),
4386            RustConstructorError::ResourceNotFound {
4387                resource_name,
4388                resource_type,
4389            } => (
4390                format!(
4391                    "Resource not found({:?}): {}(\"{}\")",
4392                    severity_level, resource_type, resource_name,
4393                ),
4394                "Please check whether the resource has been added.".to_string(),
4395            ),
4396            RustConstructorError::ResourceUntitled { resource_type } => (
4397                format!("Resource untitled({:?}): {}", severity_level, resource_type,),
4398                "Resources must have names.".to_string(),
4399            ),
4400            RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
4401                format!("Custom error({}, {:?}): {}", error_name, severity_level, error_message),
4402                error_annotation
4403            )
4404        };
4405        // 如果处于严格模式下,则直接崩溃!
4406        if self.strict_mode {
4407            panic!(
4408                "Rust Constructor Error({:?}): {}\nnote: {}",
4409                problem_type, problem, annotation
4410            );
4411        };
4412        (problem, annotation)
4413    }
4414
4415    /// 发生问题时推送报告。
4416    pub fn problem_report(
4417        &mut self,
4418        problem_type: RustConstructorError,
4419        severity_level: SeverityLevel,
4420    ) {
4421        let (problem, annotation) = self.problem_processor(problem_type.clone(), severity_level);
4422        self.problem_list.push(Problem {
4423            severity_level,
4424            problem,
4425            annotation,
4426            report_state: ReportState {
4427                current_page: self.current_page.clone(),
4428                current_total_runtime: self.timer.total_time,
4429                current_page_runtime: self.timer.now_time,
4430            },
4431            problem_type: problem_type.clone(),
4432        });
4433    }
4434
4435    /// 发生问题时向指定列表推送报告。
4436    pub fn problem_report_custom(
4437        &self,
4438        problem_type: RustConstructorError,
4439        severity_level: SeverityLevel,
4440        mut problem_storage: Vec<Problem>,
4441    ) {
4442        let (problem, annotation) = self.problem_processor(problem_type.clone(), severity_level);
4443        problem_storage.push(Problem {
4444            severity_level,
4445            problem,
4446            annotation,
4447            report_state: ReportState {
4448                current_page: self.current_page.clone(),
4449                current_total_runtime: self.timer.total_time,
4450                current_page_runtime: self.timer.now_time,
4451            },
4452            problem_type: problem_type.clone(),
4453        });
4454    }
4455
4456    /// 处理最基本的位置计算。
4457    pub fn position_size_processor(
4458        &self,
4459        position_config: PositionConfig,
4460        ctx: &Context,
4461    ) -> [[f32; 2]; 2] {
4462        let mut position = [0_f32, 0_f32];
4463        let mut size = [0_f32, 0_f32];
4464        size[0] = match position_config.x_size_grid[0] {
4465            0 => position_config.origin_size[0],
4466            _ => {
4467                (ctx.available_rect().width() as f64 / position_config.x_size_grid[1] as f64
4468                    * position_config.x_size_grid[0] as f64) as f32
4469                    + position_config.origin_size[0]
4470            }
4471        };
4472        size[1] = match position_config.y_size_grid[0] {
4473            0 => position_config.origin_size[1],
4474            _ => {
4475                (ctx.available_rect().height() as f64 / position_config.y_size_grid[1] as f64
4476                    * position_config.y_size_grid[0] as f64) as f32
4477                    + position_config.origin_size[1]
4478            }
4479        };
4480        position[0] = match position_config.x_location_grid[1] {
4481            0 => position_config.origin_position[0],
4482            _ => {
4483                (ctx.available_rect().width() as f64 / position_config.x_location_grid[1] as f64
4484                    * position_config.x_location_grid[0] as f64) as f32
4485                    + position_config.origin_position[0]
4486            }
4487        };
4488        position[1] = match position_config.y_location_grid[1] {
4489            0 => position_config.origin_position[1],
4490            _ => {
4491                (ctx.available_rect().height() as f64 / position_config.y_location_grid[1] as f64
4492                    * position_config.y_location_grid[0] as f64) as f32
4493                    + position_config.origin_position[1]
4494            }
4495        };
4496        match position_config.center_display.0 {
4497            HorizontalAlign::Left => {}
4498            HorizontalAlign::Center => position[0] -= size[0] / 2.0,
4499            HorizontalAlign::Right => position[0] -= size[0],
4500        };
4501        match position_config.center_display.1 {
4502            VerticalAlign::Top => {}
4503            VerticalAlign::Center => position[1] -= size[1] / 2.0,
4504            VerticalAlign::Bottom => position[1] -= size[1],
4505        };
4506        position[0] += position_config.offset[0];
4507        position[1] += position_config.offset[1];
4508        [position, size]
4509    }
4510
4511    /// 检查页面是否已完成首次加载。
4512    pub fn check_updated(
4513        &mut self,
4514        name: &str,
4515        safe_mode: Option<bool>,
4516    ) -> Result<bool, RustConstructorError> {
4517        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4518            && !self.check_resource_exists(name, "PageData")
4519        {
4520            self.problem_report_custom(
4521                RustConstructorError::PageNotFound {
4522                    page_name: name.to_string(),
4523                },
4524                SeverityLevel::SevereWarning,
4525                self.problem_list.clone(),
4526            );
4527            return Err(RustConstructorError::PageNotFound {
4528                page_name: name.to_string(),
4529            });
4530        };
4531        let pd = self
4532            .get_resource::<PageData>(name, "PageData")
4533            .unwrap()
4534            .unwrap()
4535            .clone();
4536        if !pd.change_page_updated {
4537            self.new_page_update(name, safe_mode).unwrap();
4538        };
4539        Ok(pd.change_page_updated)
4540    }
4541
4542    /// 检查页面是否已完成加载。
4543    pub fn check_enter_updated(
4544        &mut self,
4545        name: &str,
4546        safe_mode: Option<bool>,
4547    ) -> Result<bool, RustConstructorError> {
4548        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4549            && !self.check_resource_exists(name, "PageData")
4550        {
4551            self.problem_report_custom(
4552                RustConstructorError::PageNotFound {
4553                    page_name: name.to_string(),
4554                },
4555                SeverityLevel::SevereWarning,
4556                self.problem_list.clone(),
4557            );
4558            return Err(RustConstructorError::PageNotFound {
4559                page_name: name.to_string(),
4560            });
4561        };
4562        let pd = self
4563            .get_resource_mut::<PageData>(name, "PageData")
4564            .unwrap()
4565            .unwrap();
4566        let return_value = pd.enter_page_updated;
4567        pd.enter_page_updated = true;
4568        Ok(return_value)
4569    }
4570
4571    /// 进入新页面时的更新。
4572    pub fn new_page_update(
4573        &mut self,
4574        name: &str,
4575        safe_mode: Option<bool>,
4576    ) -> Result<(), RustConstructorError> {
4577        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4578            && !self.check_resource_exists(name, "PageData")
4579        {
4580            self.problem_report_custom(
4581                RustConstructorError::PageNotFound {
4582                    page_name: name.to_string(),
4583                },
4584                SeverityLevel::SevereWarning,
4585                self.problem_list.clone(),
4586            );
4587            return Err(RustConstructorError::PageNotFound {
4588                page_name: name.to_string(),
4589            });
4590        }
4591        self.timer.start_time = self.timer.total_time;
4592        self.update_timer();
4593        let pd = self
4594            .get_resource_mut::<PageData>(name, "PageData")
4595            .unwrap()
4596            .unwrap();
4597        pd.change_page_updated = true;
4598        Ok(())
4599    }
4600
4601    /// 更新帧数。
4602    pub fn update_frame_stats(&mut self, ctx: &Context) {
4603        let current_time = ctx.input(|i| i.time);
4604        if let Some(last) = self.last_frame_time {
4605            let delta = (current_time - last) as f32;
4606            self.frame_times.push(delta);
4607            const MAX_SAMPLES: usize = 120;
4608            if self.frame_times.len() > MAX_SAMPLES {
4609                let remove_count = self.frame_times.len() - MAX_SAMPLES;
4610                self.frame_times.drain(0..remove_count);
4611            }
4612        }
4613        self.last_frame_time = Some(current_time);
4614    }
4615
4616    /// 更新帧数显示。
4617    pub fn current_fps(&self) -> f32 {
4618        if self.frame_times.is_empty() {
4619            0.0
4620        } else {
4621            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
4622        }
4623    }
4624
4625    /// 重置分段时间。
4626    pub fn reset_split_time(
4627        &mut self,
4628        name: &str,
4629        safe_mode: Option<bool>,
4630    ) -> Result<(), RustConstructorError> {
4631        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4632            && !self.check_resource_exists(name, "SplitTime")
4633        {
4634            self.problem_report_custom(
4635                RustConstructorError::SplitTimeNotFound {
4636                    split_time_name: name.to_string(),
4637                },
4638                SeverityLevel::SevereWarning,
4639                self.problem_list.clone(),
4640            );
4641            return Err(RustConstructorError::SplitTimeNotFound {
4642                split_time_name: name.to_string(),
4643            });
4644        };
4645        let new_time = [self.timer.now_time, self.timer.total_time];
4646        let split_time = self
4647            .get_resource_mut::<SplitTime>(name, "SplitTime")
4648            .unwrap()
4649            .unwrap();
4650        split_time.time = new_time;
4651        Ok(())
4652    }
4653
4654    /// 输出分段时间。
4655    pub fn split_time(
4656        &mut self,
4657        name: &str,
4658        safe_mode: Option<bool>,
4659    ) -> Result<[f32; 2], RustConstructorError> {
4660        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4661            && !self.check_resource_exists(name, "SplitTime")
4662        {
4663            self.problem_report_custom(
4664                RustConstructorError::SplitTimeNotFound {
4665                    split_time_name: name.to_string(),
4666                },
4667                SeverityLevel::SevereWarning,
4668                self.problem_list.clone(),
4669            );
4670            return Err(RustConstructorError::SplitTimeNotFound {
4671                split_time_name: name.to_string(),
4672            });
4673        };
4674        let split_time = self
4675            .get_resource_mut::<SplitTime>(name, "SplitTime")
4676            .unwrap()
4677            .unwrap();
4678        split_time.modify_active(true);
4679        Ok(split_time.time)
4680    }
4681
4682    /// 更新计时器。
4683    pub fn update_timer(&mut self) {
4684        let elapsed = self.timer.timer.elapsed();
4685        let seconds = elapsed.as_secs();
4686        let milliseconds = elapsed.subsec_millis();
4687        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
4688        self.timer.now_time = self.timer.total_time - self.timer.start_time
4689    }
4690
4691    /// 显示矩形资源。
4692    pub fn custom_rect(
4693        &mut self,
4694        name: &str,
4695        ui: &mut Ui,
4696        ctx: &Context,
4697        safe_mode: Option<bool>,
4698    ) -> Result<(), RustConstructorError> {
4699        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4700            && !self.check_resource_exists(name, "CustomRect")
4701        {
4702            self.problem_report_custom(
4703                RustConstructorError::RectNotFound {
4704                    rect_name: name.to_string(),
4705                },
4706                SeverityLevel::SevereWarning,
4707                self.problem_list.clone(),
4708            );
4709            return Err(RustConstructorError::RectNotFound {
4710                rect_name: name.to_string(),
4711            });
4712        };
4713        let mut custom_rect = self
4714            .get_resource_mut::<CustomRect>(name, "CustomRect")
4715            .unwrap()
4716            .unwrap()
4717            .clone();
4718        custom_rect.modify_active(true);
4719        [custom_rect.position, custom_rect.size] =
4720            self.position_size_processor(PositionConfig::from_custom_rect(&custom_rect), ctx);
4721        if custom_rect.clip_rect.is_some() {
4722            let [min, size] =
4723                self.position_size_processor(custom_rect.clip_rect.clone().unwrap(), ctx);
4724            ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
4725        };
4726        ui.painter().rect(
4727            Rect::from_min_max(
4728                Pos2::new(custom_rect.position[0], custom_rect.position[1]),
4729                Pos2::new(
4730                    custom_rect.position[0] + custom_rect.size[0],
4731                    custom_rect.position[1] + custom_rect.size[1],
4732                ),
4733            ),
4734            custom_rect.rounding,
4735            Color32::from_rgba_unmultiplied(
4736                custom_rect.color[0],
4737                custom_rect.color[1],
4738                custom_rect.color[2],
4739                custom_rect.color[3],
4740            ),
4741            Stroke {
4742                width: custom_rect.border_width,
4743                color: Color32::from_rgba_unmultiplied(
4744                    custom_rect.border_color[0],
4745                    custom_rect.border_color[1],
4746                    custom_rect.border_color[2],
4747                    custom_rect.border_color[3],
4748                ),
4749            },
4750            StrokeKind::Inside,
4751        );
4752        if custom_rect.clip_rect.is_some() {
4753            ui.set_clip_rect(Rect::from_min_size(
4754                [0_f32, 0_f32].into(),
4755                [ctx.available_rect().width(), ctx.available_rect().height()].into(),
4756            ));
4757        };
4758        self.replace_resource(name, "CustomRect", custom_rect)
4759            .unwrap();
4760        Ok(())
4761    }
4762
4763    /// 显示文本资源。
4764    pub fn text(
4765        &mut self,
4766        name: &str,
4767        ui: &mut Ui,
4768        ctx: &Context,
4769        safe_mode: Option<bool>,
4770    ) -> Result<(), RustConstructorError> {
4771        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4772            && !self.check_resource_exists(name, "Text")
4773        {
4774            self.problem_report_custom(
4775                RustConstructorError::TextNotFound {
4776                    text_name: name.to_string(),
4777                },
4778                SeverityLevel::SevereWarning,
4779                self.problem_list.clone(),
4780            );
4781            return Err(RustConstructorError::TextNotFound {
4782                text_name: name.to_string(),
4783            });
4784        };
4785        let mut text = self
4786            .get_resource::<Text>(name, "Text")
4787            .unwrap()
4788            .unwrap()
4789            .clone();
4790        text.modify_active(true);
4791        [text.position, text.size] =
4792            self.position_size_processor(PositionConfig::from_text(&text), ctx);
4793        let display_content = if text.truncate {
4794            let original_galley = ui.fonts_mut(|f| {
4795                f.layout(
4796                    text.content.to_string(),
4797                    FontId::proportional(text.font_size),
4798                    Color32::default(),
4799                    text.size[0],
4800                )
4801            });
4802
4803            let mut truncated = text.content.to_string();
4804            let mut ellipsis = "";
4805            if original_galley.size().y > text.size[1] {
4806                // 如果超出,逐步缩短文本直到加上省略号后能放下
4807                ellipsis = "...";
4808
4809                while !truncated.is_empty() {
4810                    let test_text = format!("{}{}", truncated, ellipsis);
4811                    let test_galley = ui.fonts_mut(|f| {
4812                        f.layout(
4813                            test_text.clone(),
4814                            FontId::proportional(text.font_size),
4815                            Color32::default(),
4816                            text.size[0],
4817                        )
4818                    });
4819
4820                    if test_galley.size().y <= text.size[1] {
4821                        break;
4822                    }
4823
4824                    // 移除最后一个字符
4825                    truncated.pop();
4826                }
4827            };
4828            format!("{}{}", truncated, ellipsis)
4829        } else {
4830            text.content.to_string()
4831        };
4832        // 计算文本大小
4833        let galley: Arc<Galley> = ui.fonts_mut(|f| {
4834            f.layout(
4835                display_content.to_string(),
4836                if !text.font.is_empty() {
4837                    if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4838                        && !self.check_resource_exists(&text.font.clone(), "Font")
4839                    {
4840                        self.problem_report_custom(
4841                            RustConstructorError::FontNotFound {
4842                                font_name: text.font.clone(),
4843                            },
4844                            SeverityLevel::MildWarning,
4845                            self.problem_list.clone(),
4846                        );
4847                        FontId::new(text.font_size, FontFamily::Name(text.font.clone().into()))
4848                    } else {
4849                        FontId::proportional(text.font_size)
4850                    }
4851                } else {
4852                    FontId::proportional(text.font_size)
4853                },
4854                Color32::from_rgba_unmultiplied(
4855                    text.color[0],
4856                    text.color[1],
4857                    text.color[2],
4858                    text.color[3],
4859                ),
4860                text.size[0],
4861            )
4862        });
4863        text.actual_size = [galley.size().x, galley.size().y];
4864        // 使用绝对定位放置文本
4865        let rect = Rect::from_min_size(text.position.into(), text.actual_size.into());
4866        // 绘制背景颜色
4867        ui.painter().rect_filled(
4868            rect,
4869            text.background_rounding,
4870            Color32::from_rgba_unmultiplied(
4871                text.background_color[0],
4872                text.background_color[1],
4873                text.background_color[2],
4874                text.background_color[3],
4875            ),
4876        );
4877
4878        if text.clip_rect.is_some() {
4879            let [min, size] = self.position_size_processor(text.clip_rect.clone().unwrap(), ctx);
4880            ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
4881        };
4882
4883        // 绘制文本
4884        ui.painter().galley(
4885            text.position.into(),
4886            galley.clone(),
4887            Color32::from_rgba_unmultiplied(
4888                text.color[0],
4889                text.color[1],
4890                text.color[2],
4891                text.color[3], // 应用透明度
4892            ),
4893        );
4894
4895        // 查找超链接索引值
4896        if text.last_frame_content != display_content {
4897            text.hyperlink_index.clear();
4898
4899            // 创建字节索引到字符索引的映射
4900            let byte_to_char_map: std::collections::HashMap<usize, usize> = display_content
4901                .char_indices()
4902                .enumerate()
4903                .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
4904                .collect();
4905
4906            for (hyperlink_text, method) in &text.hyperlink_text {
4907                let matches: Vec<(usize, &str)> =
4908                    display_content.match_indices(hyperlink_text).collect();
4909                let text_char_count = hyperlink_text.chars().count();
4910
4911                if let HyperlinkSelectMethod::All(url) = method {
4912                    for (byte_index, _) in matches {
4913                        if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
4914                            text.hyperlink_index.push((
4915                                start_char_index,
4916                                start_char_index + text_char_count,
4917                                url.clone(),
4918                            ));
4919                        };
4920                    }
4921                } else if let HyperlinkSelectMethod::Segment(list) = method {
4922                    for (index, url) in list {
4923                        if *index >= matches.len() {
4924                            continue;
4925                        };
4926                        let (byte_index, _) = matches[*index];
4927                        if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
4928                            text.hyperlink_index.push((
4929                                start_char_index,
4930                                start_char_index + text_char_count,
4931                                url.clone(),
4932                            ));
4933                        };
4934                    }
4935                };
4936            }
4937        };
4938
4939        // 绘制超链接
4940        for (start, end, _) in &text.hyperlink_index {
4941            // 获取超链接文本的范围
4942            let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
4943            let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
4944
4945            let start_pos = start_cursor.left_top();
4946            let end_pos = end_cursor.right_top();
4947            // 绘制超链接下划线
4948            // 检查超链接是否跨行
4949            if start_cursor.min.y == end_cursor.min.y {
4950                // 单行超链接
4951                let underline_y = text.position[1]
4952                    + start_pos.y
4953                    + galley.rows.first().map_or(14.0, |row| row.height())
4954                    - 2.0;
4955
4956                // 绘制下划线
4957                let color = Color32::from_rgba_unmultiplied(
4958                    text.color[0],
4959                    text.color[1],
4960                    text.color[2],
4961                    text.color[3],
4962                );
4963
4964                ui.painter().line_segment(
4965                    [
4966                        Pos2::new(text.position[0] + start_pos.x, underline_y),
4967                        Pos2::new(text.position[0] + end_pos.x, underline_y),
4968                    ],
4969                    Stroke::new(text.font_size / 10_f32, color),
4970                );
4971            } else {
4972                // 多行超链接
4973                let row_height = galley.rows.first().map_or(14.0, |row| row.height()); // 默认行高14.0
4974
4975                // 计算起始行和结束行的索引
4976                let start_row = (start_pos.y / row_height).round() as usize;
4977                let end_row = (end_pos.y / row_height).round() as usize;
4978
4979                for row in start_row..=end_row {
4980                    let row_y = text.position[1] + row as f32 * row_height + row_height - 2.0; // 行底部稍微上移一点绘制下划线
4981
4982                    // 获取当前行的矩形范围
4983                    if let Some(current_row) = galley.rows.get(row) {
4984                        let row_rect = current_row.rect();
4985
4986                        let color = Color32::from_rgba_unmultiplied(
4987                            text.color[0],
4988                            text.color[1],
4989                            text.color[2],
4990                            text.color[3],
4991                        );
4992
4993                        if row == start_row {
4994                            // 第一行从文本开始位置到行尾
4995                            ui.painter().line_segment(
4996                                [
4997                                    Pos2::new(text.position[0] + start_pos.x, row_y),
4998                                    Pos2::new(text.position[0] + row_rect.max.x, row_y),
4999                                ],
5000                                Stroke::new(text.font_size / 10_f32, color),
5001                            );
5002                        } else if row == end_row {
5003                            // 最后一行从行首到文本结束位置
5004                            ui.painter().line_segment(
5005                                [
5006                                    Pos2::new(text.position[0] + row_rect.min.x, row_y),
5007                                    Pos2::new(text.position[0] + end_pos.x, row_y),
5008                                ],
5009                                Stroke::new(text.font_size / 10_f32, color),
5010                            );
5011                        } else {
5012                            // 中间整行下划线
5013                            ui.painter().line_segment(
5014                                [
5015                                    Pos2::new(text.position[0] + row_rect.min.x, row_y),
5016                                    Pos2::new(text.position[0] + row_rect.max.x, row_y),
5017                                ],
5018                                Stroke::new(text.font_size / 10_f32, color),
5019                            );
5020                        };
5021                    };
5022                }
5023            };
5024        }
5025
5026        if text.selectable {
5027            if !self.check_resource_exists(&text.name, "MouseDetector") {
5028                self.add_resource(
5029                    MouseDetector::default()
5030                        .name(&text.name)
5031                        .from_position_config(PositionConfig::from_text(&text))
5032                        .offset(-20_f32, -5_f32)
5033                        .origin_size(text.actual_size[0] + 40_f32, text.actual_size[1] + 10_f32),
5034                    safe_mode,
5035                )
5036                .unwrap();
5037            } else {
5038                self.replace_resource(
5039                    &text.name,
5040                    "MouseDetector",
5041                    MouseDetector::default()
5042                        .name(&text.name)
5043                        .from_position_config(PositionConfig::from_text(&text))
5044                        .offset(-20_f32, -5_f32)
5045                        .origin_size(text.actual_size[0] + 40_f32, text.actual_size[1] + 10_f32),
5046                )
5047                .unwrap();
5048            };
5049
5050            // 处理选择逻辑
5051            let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
5052                let relative_pos = pointer_pos - text.position.into();
5053                let cursor = galley.cursor_from_pos(relative_pos);
5054                cursor.index
5055            };
5056
5057            self.mouse_detector(&text.name, ui, ctx, MouseDetectorLevel::Default, safe_mode)
5058                .unwrap();
5059            let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
5060            let detect_result = self
5061                .check_mouse_detect_result(&text.name, safe_mode)
5062                .unwrap();
5063            if !detect_result.clicked
5064                && (fullscreen_detect_result.any_click() || fullscreen_detect_result.any_pressed())
5065            {
5066                text.selection = None;
5067            };
5068
5069            if (detect_result.clicked || detect_result.drag_started.unwrap())
5070                && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
5071            {
5072                let cursor = cursor_at_pointer(pointer_pos.to_vec2());
5073                text.selection = Some((cursor, cursor));
5074            };
5075
5076            if detect_result.dragged.unwrap()
5077                && text.selection.is_some()
5078                && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
5079            {
5080                let cursor = cursor_at_pointer(pointer_pos.to_vec2());
5081                if let Some((start, _)) = text.selection {
5082                    text.selection = Some((start, cursor));
5083                };
5084            };
5085
5086            if text.selection.is_some()
5087                && ui.input(|input| input.key_released(Key::A) && input.modifiers.command)
5088            {
5089                text.selection = Some((0, display_content.chars().count()));
5090            };
5091
5092            // 处理复制操作
5093            let copy_triggered = ui.input(|input| {
5094                let c_released = input.key_released(Key::C);
5095                let cmd_pressed = input.modifiers.command;
5096                c_released && cmd_pressed
5097            });
5098            if copy_triggered && let Some((start, end)) = text.selection {
5099                let (start, end) = (start.min(end), start.max(end));
5100                let chars: Vec<char> = display_content.chars().collect();
5101                if start <= chars.len() && end <= chars.len() && start < end {
5102                    let selected_text: String = chars[start..end].iter().collect();
5103                    ui.ctx().copy_text(selected_text);
5104                };
5105            };
5106
5107            // 绘制选择区域背景
5108            if let Some((start, end)) = text.selection {
5109                let (start, end) = (start.min(end), start.max(end));
5110                if start != end {
5111                    // 获取选择区域的范围
5112                    let start_cursor = galley.pos_from_cursor(CCursor::new(start));
5113                    let end_cursor = galley.pos_from_cursor(CCursor::new(end));
5114
5115                    let start_pos = start_cursor.left_top();
5116                    let end_pos = end_cursor.right_top();
5117                    // 选择框绘制
5118                    if start_pos.y == end_pos.y {
5119                        // 单行选择
5120                        let rows = &galley.rows;
5121                        let row_height = if !rows.is_empty() {
5122                            // 获取实际行的高度
5123                            if let Some(row) = rows.first() {
5124                                row.height()
5125                            } else {
5126                                text.actual_size[1] / display_content.lines().count() as f32
5127                            }
5128                        } else {
5129                            text.actual_size[1] / display_content.lines().count() as f32
5130                        };
5131
5132                        let selection_rect = Rect::from_min_max(
5133                            Pos2::new(
5134                                text.position[0] + start_pos.x,
5135                                text.position[1] + start_pos.y,
5136                            ),
5137                            Pos2::new(
5138                                text.position[0] + end_pos.x,
5139                                text.position[1] + start_pos.y + row_height,
5140                            ),
5141                        );
5142                        ui.painter().rect_filled(
5143                            selection_rect,
5144                            0.0,
5145                            Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5146                        );
5147                    } else {
5148                        // 多行选择 - 为每行创建精确的矩形
5149                        let rows = &galley.rows;
5150                        let row_height = if !rows.is_empty() {
5151                            rows[0].height()
5152                        } else {
5153                            text.actual_size[1] / display_content.lines().count() as f32
5154                        };
5155
5156                        // 计算选择的上下边界
5157                        let selection_top = text.position[1] + start_pos.y.min(end_pos.y);
5158                        let selection_bottom = text.position[1] + start_pos.y.max(end_pos.y);
5159
5160                        // 确定起始行和结束行的索引
5161                        let start_row_index = (start_pos.y / row_height).floor() as usize;
5162                        let end_row_index = (end_pos.y / row_height).floor() as usize;
5163                        let (first_row_index, last_row_index) = if start_row_index <= end_row_index
5164                        {
5165                            (start_row_index, end_row_index)
5166                        } else {
5167                            (end_row_index, start_row_index)
5168                        };
5169
5170                        for (i, row) in rows.iter().enumerate() {
5171                            let row_y = text.position[1] + row_height * i as f32;
5172                            let row_bottom = row_y + row_height;
5173                            // 检查当前行是否与选择区域相交
5174                            if row_bottom > selection_top && row_y <= selection_bottom {
5175                                let left = if i == first_row_index {
5176                                    // 首行 - 从选择开始位置开始
5177                                    text.position[0] + start_pos.x
5178                                } else {
5179                                    // 非首行 - 从行首开始
5180                                    text.position[0] + row.rect().min.x
5181                                };
5182
5183                                let right = if i == last_row_index {
5184                                    // 尾行 - 到选择结束位置结束
5185                                    text.position[0] + end_pos.x
5186                                } else {
5187                                    // 非尾行 - 到行尾结束
5188                                    text.position[0] + row.rect().max.x
5189                                };
5190
5191                                let selection_rect = Rect::from_min_max(
5192                                    Pos2::new(left, row_y),
5193                                    Pos2::new(right, row_bottom),
5194                                );
5195
5196                                // 确保矩形有效
5197                                if selection_rect.width() > 0.0 && selection_rect.height() > 0.0 {
5198                                    ui.painter().rect_filled(
5199                                        selection_rect,
5200                                        0.0,
5201                                        Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5202                                    );
5203                                };
5204                            };
5205                        }
5206                    };
5207                };
5208            };
5209        };
5210
5211        // 处理超链接操作
5212        for (start, end, url) in &text.hyperlink_index {
5213            // 获取超链接文本的范围
5214            let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
5215            let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
5216
5217            let start_pos = start_cursor.left_top();
5218            let end_pos = end_cursor.right_top();
5219
5220            let row_height = galley.rows.first().map_or(14.0, |row| row.height());
5221
5222            // 为超链接创建交互响应对象
5223            let link_responses = if start_cursor.min.y == end_cursor.min.y {
5224                // 单行超链接
5225                let link_rect = Rect::from_min_max(
5226                    Pos2::new(
5227                        text.position[0] + start_pos.x,
5228                        text.position[1] + start_pos.y,
5229                    ),
5230                    Pos2::new(
5231                        text.position[0] + end_pos.x,
5232                        text.position[1] + start_pos.y + row_height,
5233                    ),
5234                );
5235                vec![ui.interact(
5236                    link_rect,
5237                    egui::Id::new(format!("link_{}_{}_{}", text.name, start, end)),
5238                    egui::Sense::click(),
5239                )]
5240            } else {
5241                // 多行超链接
5242                let start_row = (start_pos.y / row_height).round() as usize;
5243                let end_row = (end_pos.y / row_height).round() as usize;
5244                let mut responses = Vec::new();
5245
5246                for row in start_row..=end_row {
5247                    if let Some(current_row) = galley.rows.get(row) {
5248                        let row_rect = current_row.rect();
5249                        let row_y = text.position[1] + row as f32 * row_height;
5250
5251                        let link_rect = if row == start_row {
5252                            // 第一行从文本开始位置到行尾
5253                            Rect::from_min_max(
5254                                Pos2::new(text.position[0] + start_pos.x, row_y),
5255                                Pos2::new(text.position[0] + row_rect.max.x, row_y + row_height),
5256                            )
5257                        } else if row == end_row {
5258                            // 最后一行从行首到文本结束位置
5259                            Rect::from_min_max(
5260                                Pos2::new(text.position[0] + row_rect.min.x, row_y),
5261                                Pos2::new(text.position[0] + end_pos.x, row_y + row_height),
5262                            )
5263                        } else {
5264                            // 中间整行
5265                            Rect::from_min_max(
5266                                Pos2::new(text.position[0] + row_rect.min.x, row_y),
5267                                Pos2::new(text.position[0] + row_rect.max.x, row_y + row_height),
5268                            )
5269                        };
5270
5271                        responses.push(ui.interact(
5272                            link_rect,
5273                            Id::new(format!("link_{}_{}_{}_row_{}", text.name, start, end, row)),
5274                            Sense::click(),
5275                        ));
5276                    };
5277                }
5278                responses
5279            };
5280
5281            // 检查是否正在点击这个超链接
5282            let mut is_pressing_link = false;
5283            for link_response in &link_responses {
5284                if link_response.is_pointer_button_down_on() && !link_response.drag_started() {
5285                    text.selection = None;
5286                    if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
5287                        let relative_pos =
5288                            pointer_pos - <[f32; 2] as Into<Pos2>>::into(text.position);
5289                        let cursor = galley.cursor_from_pos(relative_pos);
5290                        if cursor.index >= *start && cursor.index <= *end {
5291                            is_pressing_link = true;
5292                            break;
5293                        };
5294                    };
5295                };
5296            }
5297
5298            // 检查是否释放了鼠标(点击完成)
5299            let mut clicked_on_link = false;
5300            for link_response in &link_responses {
5301                if link_response.clicked()
5302                    && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
5303                {
5304                    let relative_pos = pointer_pos - <[f32; 2] as Into<Pos2>>::into(text.position);
5305                    let cursor = galley.cursor_from_pos(relative_pos);
5306                    if cursor.index >= *start && cursor.index <= *end {
5307                        clicked_on_link = true;
5308                        break;
5309                    };
5310                };
5311            }
5312
5313            if clicked_on_link {
5314                // 执行超链接跳转
5315                if !url.is_empty() {
5316                    ui.ctx().open_url(OpenUrl::new_tab(url));
5317                };
5318            };
5319
5320            // 绘制超链接高亮(如果正在点击或悬停)
5321            if is_pressing_link {
5322                if start_cursor.min.y == end_cursor.min.y {
5323                    // 单行超链接高亮
5324                    let selection_rect = Rect::from_min_max(
5325                        Pos2::new(
5326                            text.position[0] + start_pos.x,
5327                            text.position[1] + start_pos.y,
5328                        ),
5329                        Pos2::new(
5330                            text.position[0] + end_pos.x,
5331                            text.position[1]
5332                                + start_pos.y
5333                                + galley.rows.first().map_or(14.0, |row| row.height()),
5334                        ),
5335                    );
5336                    ui.painter().rect_filled(
5337                        selection_rect,
5338                        0.0,
5339                        Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5340                    );
5341                } else {
5342                    // 多行超链接高亮
5343                    let row_height = galley.rows.first().map_or(14.0, |row| row.height());
5344                    let start_row = (start_pos.y / row_height).round() as usize;
5345                    let end_row = (end_pos.y / row_height).round() as usize;
5346
5347                    for row in start_row..=end_row {
5348                        if let Some(current_row) = galley.rows.get(row) {
5349                            let row_rect = current_row.rect();
5350
5351                            if row == start_row {
5352                                // 第一行从文本开始位置到行尾
5353                                let selection_rect = Rect::from_min_max(
5354                                    Pos2::new(
5355                                        text.position[0] + start_pos.x,
5356                                        text.position[1] + row as f32 * row_height,
5357                                    ),
5358                                    Pos2::new(
5359                                        text.position[0] + row_rect.max.x,
5360                                        text.position[1] + row as f32 * row_height + row_height,
5361                                    ),
5362                                );
5363                                ui.painter().rect_filled(
5364                                    selection_rect,
5365                                    0.0,
5366                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5367                                );
5368                            } else if row == end_row {
5369                                // 最后一行从行首到文本结束位置
5370                                let selection_rect = Rect::from_min_max(
5371                                    Pos2::new(
5372                                        text.position[0] + row_rect.min.x,
5373                                        text.position[1] + row as f32 * row_height,
5374                                    ),
5375                                    Pos2::new(
5376                                        text.position[0] + end_pos.x,
5377                                        text.position[1] + row as f32 * row_height + row_height,
5378                                    ),
5379                                );
5380                                ui.painter().rect_filled(
5381                                    selection_rect,
5382                                    0.0,
5383                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5384                                );
5385                            } else {
5386                                // 中间整行高亮
5387                                let selection_rect = Rect::from_min_max(
5388                                    Pos2::new(
5389                                        text.position[0] + row_rect.min.x,
5390                                        text.position[1] + row as f32 * row_height,
5391                                    ),
5392                                    Pos2::new(
5393                                        text.position[0] + row_rect.max.x,
5394                                        text.position[1] + row as f32 * row_height + row_height,
5395                                    ),
5396                                );
5397                                ui.painter().rect_filled(
5398                                    selection_rect,
5399                                    0.0,
5400                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
5401                                );
5402                            };
5403                        };
5404                    }
5405                };
5406            };
5407        }
5408        text.last_frame_content = display_content.clone();
5409        if text.clip_rect.is_some() {
5410            ui.set_clip_rect(Rect::from_min_size(
5411                [0_f32, 0_f32].into(),
5412                [ctx.available_rect().width(), ctx.available_rect().height()].into(),
5413            ));
5414        };
5415        self.replace_resource(name, "Text", text).unwrap();
5416        Ok(())
5417    }
5418
5419    /// 修改变量资源。
5420    pub fn modify_var<T: Debug + 'static>(
5421        &mut self,
5422        name: &str,
5423        value: Option<T>,
5424        safe_mode: Option<bool>,
5425    ) -> Result<(), RustConstructorError> {
5426        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5427            && !self.check_resource_exists(name, "Variable")
5428        {
5429            self.problem_report_custom(
5430                RustConstructorError::VariableNotFound {
5431                    variable_name: name.to_string(),
5432                },
5433                SeverityLevel::SevereWarning,
5434                self.problem_list.clone(),
5435            );
5436            return Err(RustConstructorError::VariableNotFound {
5437                variable_name: name.to_string(),
5438            });
5439        };
5440        let v = self
5441            .get_resource_mut::<Variable<T>>(name, "Variable")
5442            .unwrap()
5443            .unwrap();
5444        v.value = value;
5445        Ok(())
5446    }
5447
5448    /// 取出变量。
5449    pub fn var<T: Debug + 'static>(
5450        &mut self,
5451        name: &str,
5452        safe_mode: Option<bool>,
5453    ) -> Result<Option<&T>, RustConstructorError> {
5454        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
5455            if !self.check_resource_exists(name, "Variable") {
5456                self.problem_report_custom(
5457                    RustConstructorError::VariableNotFound {
5458                        variable_name: name.to_string(),
5459                    },
5460                    SeverityLevel::SevereWarning,
5461                    self.problem_list.clone(),
5462                );
5463                return Err(RustConstructorError::VariableNotFound {
5464                    variable_name: name.to_string(),
5465                });
5466            };
5467            if self
5468                .get_resource::<Variable<T>>(name, "Variable")
5469                .unwrap()
5470                .is_none()
5471            {
5472                self.problem_report_custom(
5473                    RustConstructorError::VariableTypeMismatch {
5474                        variable_name: name.to_string(),
5475                    },
5476                    SeverityLevel::SevereWarning,
5477                    self.problem_list.clone(),
5478                );
5479                return Err(RustConstructorError::VariableTypeMismatch {
5480                    variable_name: name.to_string(),
5481                });
5482            };
5483        };
5484        let v = self
5485            .get_resource_mut::<Variable<T>>(name, "Variable")
5486            .unwrap()
5487            .unwrap();
5488        v.modify_active(true);
5489        Ok(v.value.as_ref())
5490    }
5491
5492    /// 输出图片纹理。
5493    pub fn image_texture(
5494        &mut self,
5495        name: &str,
5496        safe_mode: Option<bool>,
5497    ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
5498        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5499            && !self.check_resource_exists(name, "ImageTexture")
5500        {
5501            self.problem_report_custom(
5502                RustConstructorError::ImageNotFound {
5503                    image_name: name.to_string(),
5504                },
5505                SeverityLevel::SevereWarning,
5506                self.problem_list.clone(),
5507            );
5508            return Err(RustConstructorError::ImageNotFound {
5509                image_name: name.to_string(),
5510            });
5511        };
5512        let image_texture = self
5513            .get_resource_mut::<ImageTexture>(name, "ImageTexture")
5514            .unwrap()
5515            .unwrap();
5516        image_texture.modify_active(true);
5517        Ok(image_texture.texture.clone())
5518    }
5519
5520    /// 重置图片纹理。
5521    pub fn reset_image_texture(
5522        &mut self,
5523        name: &str,
5524        path: &str,
5525        flip: [bool; 2],
5526        ctx: &Context,
5527        safe_mode: Option<bool>,
5528    ) -> Result<(), RustConstructorError> {
5529        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5530            && !self.check_resource_exists(name, "ImageTexture")
5531        {
5532            self.problem_report_custom(
5533                RustConstructorError::ImageTextureNotFound {
5534                    image_texture_name: name.to_string(),
5535                },
5536                SeverityLevel::SevereWarning,
5537                self.problem_list.clone(),
5538            );
5539            return Err(RustConstructorError::ImageTextureNotFound {
5540                image_texture_name: name.to_string(),
5541            });
5542        };
5543        let image_texture = self
5544            .get_resource_mut::<ImageTexture>(name, "ImageTexture")
5545            .unwrap()
5546            .unwrap();
5547        if let Ok(mut file) = File::open(path) {
5548            let mut buffer = Vec::new();
5549            file.read_to_end(&mut buffer).unwrap();
5550            let img_bytes = buffer;
5551            let img = image::load_from_memory(&img_bytes).unwrap();
5552            let color_data = match flip {
5553                [true, true] => img.fliph().flipv().into_rgba8(),
5554                [true, false] => img.fliph().into_rgba8(),
5555                [false, true] => img.flipv().into_rgba8(),
5556                _ => img.into_rgba8(),
5557            };
5558            let (w, h) = (color_data.width(), color_data.height());
5559            let raw_data: Vec<u8> = color_data.into_raw();
5560
5561            let color_image =
5562                ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
5563            let texture = ctx.load_texture(
5564                image_texture.name.clone(),
5565                color_image,
5566                TextureOptions::LINEAR,
5567            );
5568            image_texture.texture = Some(DebugTextureHandle::new(texture));
5569            image_texture.cite_path = path.to_string();
5570        } else {
5571            self.problem_report_custom(
5572                RustConstructorError::ImageGetFailed {
5573                    image_path: path.to_string(),
5574                },
5575                SeverityLevel::SevereWarning,
5576                self.problem_list.clone(),
5577            );
5578        };
5579        Ok(())
5580    }
5581
5582    /// 显示图片资源。
5583    pub fn image(
5584        &mut self,
5585        name: &str,
5586        ui: &mut Ui,
5587        ctx: &Context,
5588        safe_mode: Option<bool>,
5589    ) -> Result<(), RustConstructorError> {
5590        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5591            && !self.check_resource_exists(name, "Image")
5592        {
5593            self.problem_report_custom(
5594                RustConstructorError::ImageNotFound {
5595                    image_name: name.to_string(),
5596                },
5597                SeverityLevel::SevereWarning,
5598                self.problem_list.clone(),
5599            );
5600            return Err(RustConstructorError::ImageNotFound {
5601                image_name: name.to_string(),
5602            });
5603        };
5604        let mut image = self
5605            .get_resource_mut::<Image>(name, "Image")
5606            .unwrap()
5607            .unwrap()
5608            .clone();
5609        if image.cite_texture != image.last_frame_cite_texture {
5610            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5611                && !self.check_resource_exists(&image.cite_texture, "ImageTexture")
5612            {
5613                self.problem_report_custom(
5614                    RustConstructorError::ImageTextureNotFound {
5615                        image_texture_name: image.cite_texture.clone(),
5616                    },
5617                    SeverityLevel::MildWarning,
5618                    self.problem_list.clone(),
5619                );
5620            } else {
5621                let it = self
5622                    .get_resource::<ImageTexture>(&image.cite_texture, "ImageTexture")
5623                    .unwrap()
5624                    .unwrap();
5625                image.texture = it.texture.clone();
5626            };
5627        };
5628        image.modify_active(true);
5629        [image.position, image.size] =
5630            self.position_size_processor(PositionConfig::from_image(&image), ctx);
5631        if image.clip_rect.is_some() {
5632            let [min, size] = self.position_size_processor(image.clip_rect.clone().unwrap(), ctx);
5633            ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
5634        };
5635        if let Some(texture) = &image.texture {
5636            let rect = Rect::from_min_size(
5637                Pos2::new(image.position[0], image.position[1]),
5638                Vec2::new(image.size[0], image.size[1]),
5639            );
5640
5641            // 直接绘制图片
5642            egui::Image::new(ImageSource::Texture((&texture.0).into()))
5643                .tint(Color32::from_rgba_unmultiplied(
5644                    image.overlay_color[0],
5645                    image.overlay_color[1],
5646                    image.overlay_color[2],
5647                    // 将图片透明度与覆盖颜色透明度相乘
5648                    (image.alpha as f32 * image.overlay_color[3] as f32 / 255.0) as u8,
5649                ))
5650                .bg_fill(Color32::from_rgba_unmultiplied(
5651                    image.background_color[0],
5652                    image.background_color[1],
5653                    image.background_color[2],
5654                    image.background_color[3],
5655                ))
5656                .rotate(
5657                    image.rotate_angle,
5658                    [
5659                        image.rotate_center[0] / image.size[0],
5660                        image.rotate_center[1] / image.size[1],
5661                    ]
5662                    .into(),
5663                )
5664                .paint_at(ui, rect)
5665        };
5666        image.last_frame_cite_texture = image.cite_texture.clone();
5667        if image.clip_rect.is_some() {
5668            ui.set_clip_rect(Rect::from_min_size(
5669                [0_f32, 0_f32].into(),
5670                [ctx.available_rect().width(), ctx.available_rect().height()].into(),
5671            ));
5672        };
5673        self.replace_resource(name, "Image", image).unwrap();
5674        Ok(())
5675    }
5676
5677    /// 处理所有已添加的消息框资源。
5678    pub fn message_box(&mut self, ctx: &Context, ui: &mut Ui, safe_mode: Option<bool>) {
5679        let mut offset = 0_f32;
5680        let mut delete_count = 0;
5681        let mut index_list = Vec::new();
5682        for i in 0..self.rust_constructor_resource.len() {
5683            if self.rust_constructor_resource[i]
5684                .as_any()
5685                .downcast_ref::<MessageBox>()
5686                .is_some()
5687            {
5688                index_list.push(i);
5689            };
5690        }
5691        for u in 0..index_list.len() {
5692            let mut deleted = false;
5693            let i = u - delete_count;
5694            let mut mb = self.rust_constructor_resource[index_list[i]]
5695                .as_any()
5696                .downcast_ref::<MessageBox>()
5697                .unwrap()
5698                .clone();
5699            if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
5700                if !self.check_resource_exists(&mb.image_name, "Image") {
5701                    self.problem_report_custom(
5702                        RustConstructorError::ImageNotFound {
5703                            image_name: mb.image_name,
5704                        },
5705                        SeverityLevel::SevereWarning,
5706                        self.problem_list.clone(),
5707                    );
5708                    continue;
5709                };
5710                if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "CustomRect") {
5711                    self.problem_report_custom(
5712                        RustConstructorError::RectNotFound {
5713                            rect_name: format!("MessageBox{}", mb.name),
5714                        },
5715                        SeverityLevel::SevereWarning,
5716                        self.problem_list.clone(),
5717                    );
5718                    continue;
5719                };
5720                if !self.check_resource_exists(&mb.title_name, "Text") {
5721                    self.problem_report_custom(
5722                        RustConstructorError::TextNotFound {
5723                            text_name: mb.title_name,
5724                        },
5725                        SeverityLevel::SevereWarning,
5726                        self.problem_list.clone(),
5727                    );
5728                    continue;
5729                };
5730                if !self.check_resource_exists(&mb.content_name, "Text") {
5731                    self.problem_report_custom(
5732                        RustConstructorError::TextNotFound {
5733                            text_name: mb.content_name,
5734                        },
5735                        SeverityLevel::SevereWarning,
5736                        self.problem_list.clone(),
5737                    );
5738                    continue;
5739                };
5740                if !self.check_resource_exists(&format!("MessageBox{}Close", mb.name), "Switch") {
5741                    self.problem_report_custom(
5742                        RustConstructorError::SwitchNotFound {
5743                            switch_name: format!("MessageBox{}Close", mb.name),
5744                        },
5745                        SeverityLevel::SevereWarning,
5746                        self.problem_list.clone(),
5747                    );
5748                    continue;
5749                };
5750                if !self
5751                    .check_resource_exists(&format!("MessageBox{}Animation", mb.name), "SplitTime")
5752                {
5753                    self.problem_report_custom(
5754                        RustConstructorError::SplitTimeNotFound {
5755                            split_time_name: format!("MessageBox{}Animation", mb.name),
5756                        },
5757                        SeverityLevel::SevereWarning,
5758                        self.problem_list.clone(),
5759                    );
5760                    continue;
5761                };
5762                if !mb.keep_existing
5763                    && !self.check_resource_exists(&format!("MessageBox{}", mb.name), "SplitTime")
5764                {
5765                    self.problem_report_custom(
5766                        RustConstructorError::SplitTimeNotFound {
5767                            split_time_name: format!("MessageBox{}", mb.name),
5768                        },
5769                        SeverityLevel::SevereWarning,
5770                        self.problem_list.clone(),
5771                    );
5772                    continue;
5773                };
5774            };
5775            let mut im1 = self
5776                .get_resource::<Image>(&mb.image_name, "Image")
5777                .unwrap()
5778                .unwrap()
5779                .clone();
5780            let mut cr = self
5781                .get_resource::<CustomRect>(&format!("MessageBox{}", mb.name), "CustomRect")
5782                .unwrap()
5783                .unwrap()
5784                .clone();
5785            let mut t1 = self
5786                .get_resource::<Text>(&mb.title_name, "Text")
5787                .unwrap()
5788                .unwrap()
5789                .clone();
5790            let mut t2 = self
5791                .get_resource::<Text>(&mb.content_name, "Text")
5792                .unwrap()
5793                .unwrap()
5794                .clone();
5795            let mut s = self
5796                .get_resource::<Switch>(&format!("MessageBox{}Close", mb.name), "Switch")
5797                .unwrap()
5798                .unwrap()
5799                .clone();
5800            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5801                && !self.check_resource_exists(&s.fill_resource_name, &s.fill_resource_type)
5802            {
5803                self.problem_report_custom(
5804                    RustConstructorError::ResourceNotFound {
5805                        resource_name: s.fill_resource_name,
5806                        resource_type: s.fill_resource_type,
5807                    },
5808                    SeverityLevel::SevereWarning,
5809                    self.problem_list.clone(),
5810                );
5811                continue;
5812            };
5813            let fr: Box<dyn BasicFrontResource> = match s.fill_resource_type.as_str() {
5814                "Image" => Box::new(
5815                    self.get_resource::<Image>(&s.fill_resource_name, "Image")
5816                        .unwrap()
5817                        .unwrap()
5818                        .clone(),
5819                ),
5820                "CustomRect" => Box::new(
5821                    self.get_resource::<CustomRect>(&s.fill_resource_name, "CustomRect")
5822                        .unwrap()
5823                        .unwrap()
5824                        .clone(),
5825                ),
5826                _ => {
5827                    self.problem_report_custom(
5828                        RustConstructorError::SwitchFillResourceMismatch {
5829                            switch_name: s.name,
5830                            fill_resource_name: s.fill_resource_name,
5831                            fill_resource_type: s.fill_resource_type,
5832                        },
5833                        SeverityLevel::SevereWarning,
5834                        self.problem_list.clone(),
5835                    );
5836                    continue;
5837                }
5838            };
5839            mb.modify_active(true);
5840            if mb.size[1] < t1.actual_size[1] + t2.actual_size[1] + 10_f32 {
5841                mb.size[1] = t1.actual_size[1] + t2.actual_size[1] + 10_f32;
5842                cr.origin_size[1] = mb.size[1];
5843                im1.origin_size = [mb.size[1] - 15_f32, mb.size[1] - 15_f32];
5844                t1.origin_size[0] = mb.size[0] - mb.size[1] + 5_f32;
5845                t2.origin_size[0] = mb.size[0] - mb.size[1] + 5_f32;
5846            };
5847            if self.timer.total_time
5848                - self
5849                    .split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
5850                    .unwrap()[1]
5851                >= self.tick_interval
5852            {
5853                self.reset_split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
5854                    .unwrap();
5855                if offset != mb.memory_offset {
5856                    if mb.memory_offset < offset {
5857                        if mb.memory_offset + mb.restore_speed >= offset {
5858                            mb.memory_offset = offset;
5859                        } else {
5860                            mb.memory_offset += mb.restore_speed;
5861                        };
5862                    } else if mb.memory_offset - mb.restore_speed <= offset {
5863                        mb.memory_offset = offset;
5864                    } else {
5865                        mb.memory_offset -= mb.restore_speed;
5866                    };
5867                };
5868                if cr.origin_position[0] != -mb.size[0] - 5_f32 {
5869                    if mb.exist {
5870                        if cr.origin_position[0] - mb.speed <= -mb.size[0] - 5_f32 {
5871                            cr.origin_position[0] = -mb.size[0] - 5_f32;
5872                            if self.check_resource_exists(
5873                                &format!("MessageBox{}", mb.name),
5874                                "SplitTime",
5875                            ) {
5876                                self.reset_split_time(&format!("MessageBox{}", mb.name), safe_mode)
5877                                    .unwrap();
5878                            };
5879                        } else {
5880                            cr.origin_position[0] -= mb.speed;
5881                        };
5882                    } else if cr.origin_position[0] + mb.speed >= 15_f32 {
5883                        cr.origin_position[0] = 15_f32;
5884                        delete_count += 1;
5885                        deleted = true;
5886                    } else {
5887                        cr.origin_position[0] += mb.speed;
5888                    };
5889                };
5890            };
5891            cr.origin_position[1] = mb.memory_offset + 20_f32;
5892            im1.origin_position = [
5893                cr.origin_position[0] + 5_f32,
5894                cr.origin_position[1] + mb.size[1] / 2_f32,
5895            ];
5896            t1.origin_position = [
5897                im1.origin_position[0] + im1.origin_size[0] + 5_f32,
5898                cr.origin_position[1] + 5_f32,
5899            ];
5900            t2.origin_position = [
5901                im1.origin_position[0] + im1.origin_size[0] + 5_f32,
5902                t1.origin_position[1] + t1.actual_size[1] + 5_f32,
5903            ];
5904            for sd in &mut s.appearance {
5905                sd.image_config.origin_position = cr.position;
5906                sd.custom_rect_config.origin_position = cr.position;
5907            }
5908            if !mb.keep_existing
5909                && self.timer.total_time
5910                    - self
5911                        .split_time(&format!("MessageBox{}", mb.name), safe_mode)
5912                        .unwrap()[1]
5913                    >= mb.existing_time
5914                && cr.origin_position[0] == -mb.size[0] - 5_f32
5915            {
5916                mb.exist = false;
5917                if cr.origin_position[0] + mb.speed >= 15_f32 {
5918                    cr.origin_position[0] = 15_f32;
5919                } else {
5920                    cr.origin_position[0] += mb.speed;
5921                };
5922            };
5923            if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
5924                let rect = Rect::from_min_size(
5925                    Pos2 {
5926                        x: fr.display_position()[0],
5927                        y: fr.display_position()[1],
5928                    },
5929                    Vec2 {
5930                        x: cr.origin_size[0] + 15_f32,
5931                        y: cr.size[1] + 15_f32,
5932                    },
5933                );
5934                if rect.contains(mouse_pos) {
5935                    s.appearance[0].image_config.overlay_color[3] = 255;
5936                    s.appearance[0].custom_rect_config.color[3] = 255;
5937                    s.appearance[0].custom_rect_config.border_color[3] = 255;
5938                } else {
5939                    s.appearance[0].image_config.overlay_color[3] = 0;
5940                    s.appearance[0].custom_rect_config.color[3] = 0;
5941                    s.appearance[0].custom_rect_config.border_color[3] = 0;
5942                };
5943            };
5944            self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
5945            self.replace_resource(&mb.image_name, "Image", im1.clone())
5946                .unwrap();
5947            self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
5948                .unwrap();
5949            self.replace_resource(&mb.title_name, "Text", t1.clone())
5950                .unwrap();
5951            self.replace_resource(&mb.content_name, "Text", t2.clone())
5952                .unwrap();
5953            self.replace_resource(&format!("MessageBox{}Close", mb.name), "Switch", s.clone())
5954                .unwrap();
5955            match s.fill_resource_type.as_str() {
5956                "Image" => {
5957                    self.replace_resource(
5958                        &s.fill_resource_name,
5959                        &s.fill_resource_type,
5960                        fr.as_any().downcast_ref::<Image>().unwrap().clone(),
5961                    )
5962                    .unwrap();
5963                }
5964                "CustomRect" => {
5965                    self.replace_resource(
5966                        &s.fill_resource_name,
5967                        &s.fill_resource_type,
5968                        fr.as_any().downcast_ref::<CustomRect>().unwrap().clone(),
5969                    )
5970                    .unwrap();
5971                }
5972                _ => {
5973                    self.problem_report_custom(
5974                        RustConstructorError::SwitchFillResourceMismatch {
5975                            switch_name: s.name,
5976                            fill_resource_name: s.fill_resource_name,
5977                            fill_resource_type: s.fill_resource_type,
5978                        },
5979                        SeverityLevel::SevereWarning,
5980                        self.problem_list.clone(),
5981                    );
5982                    continue;
5983                }
5984            };
5985            self.custom_rect(&format!("MessageBox{}", mb.name), ui, ctx, safe_mode)
5986                .unwrap();
5987            self.image(&mb.image_name.clone(), ui, ctx, safe_mode)
5988                .unwrap();
5989            self.text(&t1.name.clone(), ui, ctx, safe_mode).unwrap();
5990            self.text(&t2.name.clone(), ui, ctx, safe_mode).unwrap();
5991            self.switch(
5992                &format!("MessageBox{}Close", mb.name),
5993                ui,
5994                ctx,
5995                s.state == 0 && mb.exist,
5996                safe_mode,
5997            )
5998            .unwrap();
5999            let switch_data = self
6000                .check_switch_data(&format!("MessageBox{}Close", mb.name), safe_mode)
6001                .unwrap();
6002            if switch_data.last_time_clicked_index == 0
6003                && switch_data.state == 1
6004                && switch_data.switched
6005            {
6006                mb.exist = false;
6007                if cr.origin_position[0] + mb.speed >= 15_f32 {
6008                    cr.origin_position[0] = 15_f32;
6009                } else {
6010                    cr.origin_position[0] += mb.speed;
6011                };
6012                self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
6013                self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
6014                    .unwrap();
6015            };
6016            if deleted {
6017                self.rust_constructor_resource.remove(
6018                    self.rust_constructor_resource
6019                        .iter()
6020                        .position(|x| x.expose_type() == "Image" && x.name() == mb.image_name)
6021                        .unwrap(),
6022                );
6023                self.rust_constructor_resource.remove(
6024                    self.rust_constructor_resource
6025                        .iter()
6026                        .position(|x| {
6027                            x.expose_type() == "CustomRect"
6028                                && x.name() == format!("MessageBox{}", mb.name)
6029                        })
6030                        .unwrap(),
6031                );
6032                self.rust_constructor_resource.remove(
6033                    self.rust_constructor_resource
6034                        .iter()
6035                        .position(|x| x.expose_type() == "Text" && x.name() == mb.title_name)
6036                        .unwrap(),
6037                );
6038                self.rust_constructor_resource.remove(
6039                    self.rust_constructor_resource
6040                        .iter()
6041                        .position(|x| x.expose_type() == "Text" && x.name() == mb.content_name)
6042                        .unwrap(),
6043                );
6044                self.rust_constructor_resource.remove(
6045                    self.rust_constructor_resource
6046                        .iter()
6047                        .position(|x| {
6048                            x.expose_type() == "Switch"
6049                                && x.name() == format!("MessageBox{}Close", mb.name)
6050                        })
6051                        .unwrap(),
6052                );
6053                self.rust_constructor_resource.remove(
6054                    self.rust_constructor_resource
6055                        .iter()
6056                        .position(|x| {
6057                            x.expose_type() == s.fill_resource_type
6058                                && x.name() == s.fill_resource_name
6059                        })
6060                        .unwrap(),
6061                );
6062                self.rust_constructor_resource.remove(
6063                    self.rust_constructor_resource
6064                        .iter()
6065                        .position(|x| {
6066                            x.expose_type() == "SplitTime"
6067                                && x.name() == format!("MessageBox{}Animation", mb.name)
6068                        })
6069                        .unwrap(),
6070                );
6071                if !mb.keep_existing {
6072                    self.rust_constructor_resource.remove(
6073                        self.rust_constructor_resource
6074                            .iter()
6075                            .position(|x| {
6076                                x.expose_type() == "SplitTime"
6077                                    && x.name() == format!("MessageBox{}", mb.name)
6078                            })
6079                            .unwrap(),
6080                    );
6081                };
6082                self.rust_constructor_resource.remove(
6083                    self.rust_constructor_resource
6084                        .iter()
6085                        .position(|x| x.expose_type() == "MessageBox" && x.name() == mb.name)
6086                        .unwrap(),
6087                );
6088                self.rust_constructor_resource.remove(
6089                    self.rust_constructor_resource
6090                        .iter()
6091                        .position(|x| x.expose_type() == "MouseDetector" && x.name() == t1.name)
6092                        .unwrap(),
6093                );
6094                self.rust_constructor_resource.remove(
6095                    self.rust_constructor_resource
6096                        .iter()
6097                        .position(|x| x.expose_type() == "MouseDetector" && x.name() == t2.name)
6098                        .unwrap(),
6099                );
6100            } else {
6101                offset += mb.size[1] + 15_f32;
6102            };
6103        }
6104    }
6105
6106    /// 显示开关资源。
6107    pub fn switch(
6108        &mut self,
6109        name: &str,
6110        ui: &mut Ui,
6111        ctx: &Context,
6112        enable: bool,
6113        safe_mode: Option<bool>,
6114    ) -> Result<(), RustConstructorError> {
6115        let mut appearance_count = 0;
6116        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6117            && !self.check_resource_exists(name, "Switch")
6118        {
6119            self.problem_report_custom(
6120                RustConstructorError::SwitchNotFound {
6121                    switch_name: name.to_string(),
6122                },
6123                SeverityLevel::SevereWarning,
6124                self.problem_list.clone(),
6125            );
6126            return Err(RustConstructorError::SwitchNotFound {
6127                switch_name: name.to_string(),
6128            });
6129        };
6130        let mut s = self
6131            .get_resource::<Switch>(name, "Switch")
6132            .unwrap()
6133            .unwrap()
6134            .clone();
6135        s.switched = false;
6136        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
6137            if !self.check_resource_exists(&s.fill_resource_name.clone(), &s.fill_resource_type) {
6138                self.problem_report_custom(
6139                    RustConstructorError::ResourceNotFound {
6140                        resource_name: s.fill_resource_name.clone(),
6141                        resource_type: s.fill_resource_type.clone(),
6142                    },
6143                    SeverityLevel::SevereWarning,
6144                    self.problem_list.clone(),
6145                );
6146                return Err(RustConstructorError::ResourceNotFound {
6147                    resource_name: s.fill_resource_name,
6148                    resource_type: s.fill_resource_type,
6149                });
6150            };
6151            if !s.hint_text_name.is_empty() {
6152                if !self.check_resource_exists(&format!("{}StartHoverTime", s.name), "SplitTime") {
6153                    self.problem_report_custom(
6154                        RustConstructorError::SplitTimeNotFound {
6155                            split_time_name: format!("{}StartHoverTime", s.name),
6156                        },
6157                        SeverityLevel::MildWarning,
6158                        self.problem_list.clone(),
6159                    );
6160                    self.add_resource(
6161                        SplitTime::default().name(&format!("{}StartHoverTime", s.name)),
6162                        safe_mode,
6163                    )
6164                    .unwrap();
6165                };
6166                if !self.check_resource_exists(&format!("{}HintFadeAnimation", s.name), "SplitTime")
6167                {
6168                    self.problem_report_custom(
6169                        RustConstructorError::SplitTimeNotFound {
6170                            split_time_name: format!("{}HintFadeAnimation", s.name),
6171                        },
6172                        SeverityLevel::MildWarning,
6173                        self.problem_list.clone(),
6174                    );
6175                    self.add_resource(
6176                        SplitTime::default().name(&format!("{}HintFadeAnimation", s.name)),
6177                        safe_mode,
6178                    )
6179                    .unwrap();
6180                };
6181                if !self.check_resource_exists(&s.hint_text_name, "Text") {
6182                    self.problem_report_custom(
6183                        RustConstructorError::TextNotFound {
6184                            text_name: s.hint_text_name.clone(),
6185                        },
6186                        SeverityLevel::MildWarning,
6187                        self.problem_list.clone(),
6188                    );
6189                    self.add_resource(
6190                        Text::default()
6191                            .name(&s.hint_text_name)
6192                            .content("")
6193                            .origin_position(0_f32, 0_f32)
6194                            .font_size(25_f32)
6195                            .origin_size(300_f32, 0_f32)
6196                            .background_rounding(10_f32)
6197                            .color(255, 255, 255, 0)
6198                            .background_color(0, 0, 0, 255)
6199                            .center_display(HorizontalAlign::Left, VerticalAlign::Top)
6200                            .selectable(false),
6201                        safe_mode,
6202                    )
6203                    .unwrap();
6204                };
6205            };
6206        };
6207        let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
6208            "Image" => Box::new(
6209                self.get_resource::<Image>(&s.fill_resource_name.clone(), &s.fill_resource_type)
6210                    .unwrap()
6211                    .unwrap()
6212                    .clone(),
6213            ),
6214            "CustomRect" => Box::new(
6215                self.get_resource::<CustomRect>(
6216                    &s.fill_resource_name.clone(),
6217                    &s.fill_resource_type,
6218                )
6219                .unwrap()
6220                .unwrap()
6221                .clone(),
6222            ),
6223            _ => {
6224                self.problem_report_custom(
6225                    RustConstructorError::SwitchFillResourceMismatch {
6226                        switch_name: name.to_string(),
6227                        fill_resource_name: s.fill_resource_name.clone(),
6228                        fill_resource_type: s.fill_resource_type.clone(),
6229                    },
6230                    SeverityLevel::SevereWarning,
6231                    self.problem_list.clone(),
6232                );
6233                return Err(RustConstructorError::SwitchFillResourceMismatch {
6234                    switch_name: name.to_string(),
6235                    fill_resource_name: s.fill_resource_name,
6236                    fill_resource_type: s.fill_resource_type,
6237                });
6238            }
6239        };
6240        s.modify_active(true);
6241        let rect = Rect::from_min_size(
6242            Pos2::new(fr.display_position()[0], fr.display_position()[1]),
6243            Vec2::new(fr.display_size()[0], fr.display_size()[1]),
6244        );
6245        let mut hovered = false;
6246        if enable {
6247            if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
6248                // 判断是否在矩形内
6249                if rect.contains(mouse_pos) {
6250                    if !s.hint_text_name.is_empty() {
6251                        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6252                            && !self.check_resource_exists(&s.hint_text_name, "Text")
6253                        {
6254                            self.problem_report_custom(
6255                                RustConstructorError::TextNotFound {
6256                                    text_name: s.hint_text_name.clone(),
6257                                },
6258                                SeverityLevel::SevereWarning,
6259                                self.problem_list.clone(),
6260                            );
6261                            return Err(RustConstructorError::TextNotFound {
6262                                text_name: s.hint_text_name.clone(),
6263                            });
6264                        };
6265                        let mut t = self
6266                            .get_resource::<Text>(&s.hint_text_name, "Text")
6267                            .unwrap()
6268                            .unwrap()
6269                            .clone();
6270                        if !s.last_time_hovered {
6271                            self.reset_split_time(&format!("{}StartHoverTime", s.name), safe_mode)
6272                                .unwrap();
6273                        } else if self.timer.total_time
6274                            - self
6275                                .split_time(&format!("{}StartHoverTime", s.name), safe_mode)
6276                                .unwrap()[1]
6277                            >= 2_f32
6278                            || t.color[3] != 0
6279                        {
6280                            t.color[3] = 255;
6281                            t.origin_position = [mouse_pos.x, mouse_pos.y];
6282                        };
6283                        t.center_display.0 =
6284                            if mouse_pos.x + t.actual_size[0] <= ctx.available_rect().width() {
6285                                HorizontalAlign::Left
6286                            } else {
6287                                HorizontalAlign::Right
6288                            };
6289                        t.center_display.1 =
6290                            if mouse_pos.y + t.actual_size[1] <= ctx.available_rect().height() {
6291                                VerticalAlign::Top
6292                            } else {
6293                                VerticalAlign::Bottom
6294                            };
6295                        self.replace_resource(&s.hint_text_name, "Text", t.clone())
6296                            .unwrap();
6297                    };
6298                    hovered = true;
6299                    let mut clicked = vec![];
6300                    for u in 0..s.click_method.len() as u32 {
6301                        clicked.push(ui.input(|i| {
6302                            i.pointer
6303                                .button_down(s.click_method[u as usize].click_method)
6304                        }));
6305                        if clicked[u as usize] {
6306                            s.last_time_clicked_index = u as usize;
6307                            break;
6308                        };
6309                    }
6310                    if clicked.iter().any(|x| *x) {
6311                        s.last_time_clicked = true;
6312                        if s.enable_hover_click_fill_resource[1] {
6313                            if s.enable_hover_click_fill_resource[0] {
6314                                appearance_count = 2;
6315                            } else {
6316                                appearance_count = 1;
6317                            };
6318                        } else if !s.enable_hover_click_fill_resource[0] {
6319                            appearance_count = 0;
6320                        };
6321                    } else {
6322                        if s.last_time_clicked {
6323                            s.switched = true;
6324                            if s.click_method[s.last_time_clicked_index].action {
6325                                if s.state
6326                                    < (s.appearance.len() / s.animation_count as usize - 1) as u32
6327                                {
6328                                    s.state += 1;
6329                                } else {
6330                                    s.state = 0;
6331                                };
6332                            };
6333                            s.last_time_clicked = false;
6334                        };
6335                        if s.enable_hover_click_fill_resource[0] {
6336                            appearance_count = 1;
6337                        } else {
6338                            appearance_count = 0;
6339                        };
6340                    };
6341                } else {
6342                    s.last_time_clicked = false;
6343                    appearance_count = 0;
6344                };
6345            } else {
6346                s.last_time_clicked = false;
6347                appearance_count = 0;
6348            };
6349        } else {
6350            s.last_time_clicked = false;
6351            appearance_count = 0;
6352        };
6353        if !hovered && !s.hint_text_name.is_empty() {
6354            if s.last_time_hovered {
6355                self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
6356                    .unwrap();
6357            };
6358            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6359                && !self.check_resource_exists(&s.hint_text_name, "Text")
6360            {
6361                self.problem_report_custom(
6362                    RustConstructorError::TextNotFound {
6363                        text_name: s.hint_text_name.clone(),
6364                    },
6365                    SeverityLevel::SevereWarning,
6366                    self.problem_list.clone(),
6367                );
6368                return Err(RustConstructorError::TextNotFound {
6369                    text_name: s.hint_text_name.clone(),
6370                });
6371            };
6372            let mut t = self
6373                .get_resource::<Text>(&s.hint_text_name, "Text")
6374                .unwrap()
6375                .unwrap()
6376                .clone();
6377            if self.timer.total_time
6378                - self
6379                    .split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
6380                    .unwrap()[1]
6381                >= self.tick_interval
6382            {
6383                self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
6384                    .unwrap();
6385                t.color[3] = t.color[3].saturating_sub(10);
6386            };
6387            self.replace_resource(&s.hint_text_name, "Text", t.clone())
6388                .unwrap();
6389        };
6390        let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
6391            "Image" => {
6392                let mut im = Box::new(
6393                    fr.as_any()
6394                        .downcast_ref::<Image>()
6395                        .unwrap()
6396                        .clone()
6397                        .from_config(
6398                            &s.appearance
6399                                [(s.state * s.animation_count + appearance_count) as usize]
6400                                .image_config
6401                                .clone(),
6402                        ),
6403                );
6404                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6405                    && !self.check_resource_exists(
6406                        &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
6407                            .texture
6408                            .clone(),
6409                        "ImageTexture",
6410                    )
6411                {
6412                    self.problem_report_custom(
6413                        RustConstructorError::ImageTextureNotFound {
6414                            image_texture_name: s.appearance
6415                                [(s.state * s.animation_count + appearance_count) as usize]
6416                                .texture
6417                                .clone(),
6418                        },
6419                        SeverityLevel::SevereWarning,
6420                        self.problem_list.clone(),
6421                    );
6422                    return Err(RustConstructorError::ImageTextureNotFound {
6423                        image_texture_name: s.appearance
6424                            [(s.state * s.animation_count + appearance_count) as usize]
6425                            .texture
6426                            .clone(),
6427                    });
6428                };
6429                im.cite_texture = s.appearance
6430                    [(s.state * s.animation_count + appearance_count) as usize]
6431                    .texture
6432                    .clone();
6433                im
6434            }
6435            "CustomRect" => Box::new(
6436                fr.as_any()
6437                    .downcast_ref::<CustomRect>()
6438                    .unwrap()
6439                    .clone()
6440                    .name(&s.fill_resource_name)
6441                    .from_config(
6442                        &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
6443                            .custom_rect_config
6444                            .clone(),
6445                    ),
6446            ),
6447            _ => {
6448                self.problem_report_custom(
6449                    RustConstructorError::SwitchFillResourceMismatch {
6450                        switch_name: name.to_string(),
6451                        fill_resource_name: s.fill_resource_name.clone(),
6452                        fill_resource_type: s.fill_resource_type.clone(),
6453                    },
6454                    SeverityLevel::SevereWarning,
6455                    self.problem_list.clone(),
6456                );
6457                return Err(RustConstructorError::SwitchFillResourceMismatch {
6458                    switch_name: name.to_string(),
6459                    fill_resource_name: s.fill_resource_name,
6460                    fill_resource_type: s.fill_resource_type,
6461                });
6462            }
6463        };
6464        if !s.hint_text_name.is_empty() {
6465            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6466                && !self.check_resource_exists(&s.hint_text_name, "Text")
6467            {
6468                self.problem_report_custom(
6469                    RustConstructorError::TextNotFound {
6470                        text_name: s.hint_text_name.clone(),
6471                    },
6472                    SeverityLevel::SevereWarning,
6473                    self.problem_list.clone(),
6474                );
6475                return Err(RustConstructorError::TextNotFound {
6476                    text_name: s.hint_text_name,
6477                });
6478            };
6479            let mut t = self
6480                .get_resource::<Text>(&s.hint_text_name, "Text")
6481                .unwrap()
6482                .unwrap()
6483                .clone();
6484            t.background_color[3] = t.color[3];
6485            t.content = s.appearance[(s.state * s.animation_count + appearance_count) as usize]
6486                .hint_text
6487                .clone();
6488            self.replace_resource(&s.hint_text_name, "Text", t.clone())
6489                .unwrap();
6490        };
6491        s.last_time_hovered = hovered;
6492        self.replace_resource(name, "Switch", s.clone()).unwrap();
6493        match s.fill_resource_type.as_str() {
6494            "Image" => {
6495                let im = fr.as_any().downcast_ref::<Image>().unwrap().clone();
6496                self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, im)
6497                    .unwrap();
6498                self.image(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
6499                    .unwrap();
6500            }
6501            "CustomRect" => {
6502                let cr = fr.as_any().downcast_ref::<CustomRect>().unwrap().clone();
6503                self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, cr)
6504                    .unwrap();
6505                self.custom_rect(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
6506                    .unwrap();
6507            }
6508            _ => {}
6509        };
6510        s.text_origin_position = s.appearance
6511            [(s.state * s.animation_count + appearance_count) as usize]
6512            .text_config
6513            .origin_position;
6514        if !s.text_name.is_empty() {
6515            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6516                && !self.check_resource_exists(&s.text_name, "Text")
6517            {
6518                self.problem_report_custom(
6519                    RustConstructorError::TextNotFound {
6520                        text_name: s.text_name.clone(),
6521                    },
6522                    SeverityLevel::SevereWarning,
6523                    self.problem_list.clone(),
6524                );
6525                return Err(RustConstructorError::TextNotFound {
6526                    text_name: s.text_name,
6527                });
6528            };
6529            let mut t = self
6530                .get_resource::<Text>(&s.text_name, "Text")
6531                .unwrap()
6532                .unwrap()
6533                .clone();
6534            t.origin_position = [
6535                fr.display_position()[0] + s.text_origin_position[0],
6536                fr.display_position()[1] + s.text_origin_position[1],
6537            ];
6538            t = t.from_config(
6539                &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
6540                    .text_config
6541                    .clone(),
6542            );
6543            self.replace_resource(&s.text_name, "Text", t.clone())
6544                .unwrap();
6545            self.text(&s.text_name, ui, ctx, safe_mode).unwrap();
6546        };
6547        if !s.hint_text_name.is_empty() {
6548            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6549                && !self.check_resource_exists(&s.hint_text_name, "Text")
6550            {
6551                self.problem_report_custom(
6552                    RustConstructorError::TextNotFound {
6553                        text_name: s.hint_text_name.clone(),
6554                    },
6555                    SeverityLevel::SevereWarning,
6556                    self.problem_list.clone(),
6557                );
6558                return Err(RustConstructorError::TextNotFound {
6559                    text_name: s.hint_text_name,
6560                });
6561            };
6562            self.text(&s.hint_text_name, ui, ctx, safe_mode).unwrap();
6563        };
6564        Ok(())
6565    }
6566
6567    /// 查找指定开关的常用判定字段集合。
6568    pub fn check_switch_data(
6569        &self,
6570        name: &str,
6571        safe_mode: Option<bool>,
6572    ) -> Result<SwitchData, RustConstructorError> {
6573        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6574            && !self.check_resource_exists(name, "Switch")
6575        {
6576            self.problem_report_custom(
6577                RustConstructorError::SwitchNotFound {
6578                    switch_name: name.to_string(),
6579                },
6580                SeverityLevel::SevereWarning,
6581                self.problem_list.clone(),
6582            );
6583            return Err(RustConstructorError::SwitchNotFound {
6584                switch_name: name.to_string(),
6585            });
6586        };
6587        let s = self
6588            .get_resource::<Switch>(name, "Switch")
6589            .unwrap()
6590            .unwrap();
6591        Ok(SwitchData {
6592            switched: s.switched,
6593            last_time_clicked_index: s.last_time_clicked_index,
6594            state: s.state,
6595        })
6596    }
6597
6598    pub fn mouse_detector(
6599        &mut self,
6600        name: &str,
6601        ui: &Ui,
6602        ctx: &Context,
6603        mouse_detector_level: MouseDetectorLevel,
6604        safe_mode: Option<bool>,
6605    ) -> Result<(), RustConstructorError> {
6606        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6607            && !self.check_resource_exists(name, "MouseDetector")
6608        {
6609            self.problem_report_custom(
6610                RustConstructorError::MouseDetectorNotFound {
6611                    mouse_detector_name: name.to_string(),
6612                },
6613                SeverityLevel::SevereWarning,
6614                self.problem_list.clone(),
6615            );
6616            return Err(RustConstructorError::MouseDetectorNotFound {
6617                mouse_detector_name: name.to_string(),
6618            });
6619        };
6620        let mut mouse_detector = self
6621            .get_resource_mut::<MouseDetector>(name, "MouseDetector")
6622            .unwrap()
6623            .unwrap()
6624            .clone();
6625        mouse_detector.modify_active(true);
6626        [mouse_detector.position, mouse_detector.size] =
6627            self.position_size_processor(PositionConfig::from_mouse_detector(&mouse_detector), ctx);
6628        let rect = Rect::from_min_size(mouse_detector.position.into(), mouse_detector.size.into());
6629        let response = ui.interact(rect, Id::new(name), Sense::click_and_drag());
6630        mouse_detector.detect_result = match mouse_detector_level {
6631            MouseDetectorLevel::Lite => MouseDetectResult {
6632                clicked: response.clicked(),
6633                contains_pointer: response.contains_pointer(),
6634                secondary_clicked: None,
6635                middle_clicked: None,
6636                clicked_by_extra_button: None,
6637                long_touched: None,
6638                double_clicked: None,
6639                triple_clicked: None,
6640                double_clicked_by: None,
6641                triple_clicked_by: None,
6642                clicked_elsewhere: None,
6643                hovered: None,
6644                drag_started: None,
6645                drag_started_by: None,
6646                dragged: None,
6647                dragged_by: None,
6648                drag_stopped: None,
6649                deag_stopped_by: None,
6650                drag_delta: None,
6651                total_drag_delta: None,
6652                drag_motion: None,
6653                interact_pointer_pos: None,
6654                hover_pos: None,
6655                is_pointer_button_down_on: None,
6656                raw_scroll_delta: None,
6657                smooth_scroll_delta: None,
6658            },
6659            MouseDetectorLevel::Default => {
6660                let interact_hover_pos = response.interact_pointer_pos();
6661                let hover_pos = response.hover_pos();
6662                MouseDetectResult {
6663                    clicked: response.clicked(),
6664                    contains_pointer: response.contains_pointer(),
6665                    secondary_clicked: Some(response.secondary_clicked()),
6666                    middle_clicked: Some(response.middle_clicked()),
6667                    clicked_by_extra_button: None,
6668                    long_touched: None,
6669                    double_clicked: Some(response.double_clicked()),
6670                    triple_clicked: Some(response.triple_clicked()),
6671                    double_clicked_by: None,
6672                    triple_clicked_by: None,
6673                    clicked_elsewhere: Some(response.clicked_elsewhere()),
6674                    hovered: Some(response.hovered()),
6675                    drag_started: Some(response.drag_started()),
6676                    drag_started_by: None,
6677                    dragged: Some(response.dragged()),
6678                    dragged_by: None,
6679                    drag_stopped: Some(response.drag_stopped()),
6680                    deag_stopped_by: None,
6681                    drag_delta: None,
6682                    total_drag_delta: None,
6683                    drag_motion: None,
6684                    interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
6685                        Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
6686                    } else {
6687                        Some(None)
6688                    },
6689                    hover_pos: if let Some(hover_pos) = hover_pos {
6690                        Some(Some([hover_pos.x, hover_pos.y]))
6691                    } else {
6692                        Some(None)
6693                    },
6694                    is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
6695                    raw_scroll_delta: Some(ui.input(|i| i.raw_scroll_delta).into()),
6696                    smooth_scroll_delta: Some(ui.input(|i| i.smooth_scroll_delta).into()),
6697                }
6698            }
6699            MouseDetectorLevel::Pro => {
6700                let interact_hover_pos = response.interact_pointer_pos();
6701                let hover_pos = response.hover_pos();
6702                let total_drag_delta = response.total_drag_delta();
6703                MouseDetectResult {
6704                    clicked: response.clicked(),
6705                    contains_pointer: response.contains_pointer(),
6706                    secondary_clicked: Some(response.secondary_clicked()),
6707                    middle_clicked: Some(response.middle_clicked()),
6708                    clicked_by_extra_button: Some([
6709                        response.clicked_by(PointerButton::Extra1),
6710                        response.clicked_by(PointerButton::Extra2),
6711                    ]),
6712                    long_touched: Some(response.long_touched()),
6713                    double_clicked: Some(response.double_clicked()),
6714                    triple_clicked: Some(response.triple_clicked()),
6715                    double_clicked_by: Some([
6716                        response.double_clicked_by(PointerButton::Primary),
6717                        response.double_clicked_by(PointerButton::Secondary),
6718                        response.double_clicked_by(PointerButton::Middle),
6719                        response.double_clicked_by(PointerButton::Extra1),
6720                        response.double_clicked_by(PointerButton::Extra2),
6721                    ]),
6722                    triple_clicked_by: Some([
6723                        response.triple_clicked_by(PointerButton::Primary),
6724                        response.triple_clicked_by(PointerButton::Secondary),
6725                        response.triple_clicked_by(PointerButton::Middle),
6726                        response.triple_clicked_by(PointerButton::Extra1),
6727                        response.triple_clicked_by(PointerButton::Extra2),
6728                    ]),
6729                    clicked_elsewhere: Some(response.clicked_elsewhere()),
6730                    hovered: Some(response.hovered()),
6731                    drag_started: Some(response.drag_started()),
6732                    drag_started_by: Some([
6733                        response.drag_started_by(PointerButton::Primary),
6734                        response.drag_started_by(PointerButton::Secondary),
6735                        response.drag_started_by(PointerButton::Middle),
6736                        response.drag_started_by(PointerButton::Extra1),
6737                        response.drag_started_by(PointerButton::Extra2),
6738                    ]),
6739                    dragged: Some(response.dragged()),
6740                    dragged_by: Some([
6741                        response.dragged_by(PointerButton::Primary),
6742                        response.dragged_by(PointerButton::Secondary),
6743                        response.dragged_by(PointerButton::Middle),
6744                        response.dragged_by(PointerButton::Extra1),
6745                        response.dragged_by(PointerButton::Extra2),
6746                    ]),
6747                    drag_stopped: Some(response.drag_stopped()),
6748                    deag_stopped_by: Some([
6749                        response.drag_stopped_by(PointerButton::Primary),
6750                        response.drag_stopped_by(PointerButton::Secondary),
6751                        response.drag_stopped_by(PointerButton::Middle),
6752                        response.drag_stopped_by(PointerButton::Extra1),
6753                        response.drag_stopped_by(PointerButton::Extra2),
6754                    ]),
6755                    drag_delta: Some([response.drag_delta().x, response.drag_delta().y]),
6756                    total_drag_delta: if let Some(total_drag_delta) = total_drag_delta {
6757                        Some(Some([total_drag_delta.x, total_drag_delta.y]))
6758                    } else {
6759                        Some(None)
6760                    },
6761                    drag_motion: Some([response.drag_motion().x, response.drag_motion().y]),
6762                    interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
6763                        Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
6764                    } else {
6765                        Some(None)
6766                    },
6767                    hover_pos: if let Some(hover_pos) = hover_pos {
6768                        Some(Some([hover_pos.x, hover_pos.y]))
6769                    } else {
6770                        Some(None)
6771                    },
6772                    is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
6773                    raw_scroll_delta: Some(ui.input(|i| i.raw_scroll_delta).into()),
6774                    smooth_scroll_delta: Some(ui.input(|i| i.smooth_scroll_delta).into()),
6775                }
6776            }
6777        };
6778        self.replace_resource(name, "MouseDetector", mouse_detector)
6779            .unwrap();
6780        Ok(())
6781    }
6782
6783    pub fn check_mouse_detect_result(
6784        &self,
6785        name: &str,
6786        safe_mode: Option<bool>,
6787    ) -> Result<MouseDetectResult, RustConstructorError> {
6788        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6789            && !self.check_resource_exists(name, "MouseDetector")
6790        {
6791            self.problem_report_custom(
6792                RustConstructorError::MouseDetectorNotFound {
6793                    mouse_detector_name: name.to_string(),
6794                },
6795                SeverityLevel::SevereWarning,
6796                self.problem_list.clone(),
6797            );
6798            return Err(RustConstructorError::MouseDetectorNotFound {
6799                mouse_detector_name: name.to_string(),
6800            });
6801        };
6802        let md = self
6803            .get_resource::<MouseDetector>(name, "MouseDetector")
6804            .unwrap()
6805            .unwrap();
6806        Ok(md.detect_result.clone())
6807    }
6808
6809    pub fn resource_panel(
6810        &mut self,
6811        name: &str,
6812        ui: &mut Ui,
6813        ctx: &Context,
6814        safe_mode: Option<bool>,
6815    ) -> Result<(), RustConstructorError> {
6816        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6817            && !self.check_resource_exists(name, "ResourcePanel")
6818        {
6819            self.problem_report_custom(
6820                RustConstructorError::ResourcePanelNotFound {
6821                    resource_panel_name: name.to_string(),
6822                },
6823                SeverityLevel::SevereWarning,
6824                self.problem_list.clone(),
6825            );
6826            return Err(RustConstructorError::ResourcePanelNotFound {
6827                resource_panel_name: name.to_string(),
6828            });
6829        };
6830        let mut resource_panel = self
6831            .get_resource_mut::<ResourcePanel>(name, "ResourcePanel")
6832            .unwrap()
6833            .unwrap()
6834            .clone();
6835        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
6836            && resource_panel.display_rect.is_some()
6837            && !self
6838                .check_resource_exists(&format!("{}DisplayRect", resource_panel.name), "CustomRect")
6839        {
6840            self.problem_report_custom(
6841                RustConstructorError::RectNotFound {
6842                    rect_name: format!("{}DisplayRect", resource_panel.name),
6843                },
6844                SeverityLevel::MildWarning,
6845                self.problem_list.clone(),
6846            );
6847            self.add_resource(
6848                CustomRect::default().name(&format!("{}DisplayRect", resource_panel.name)),
6849                safe_mode,
6850            )
6851            .unwrap();
6852        };
6853        resource_panel.modify_active(true);
6854        let rect = Rect::from_min_size(resource_panel.position.into(), resource_panel.size.into());
6855        if resource_panel.resizable.contains(&true) {
6856            resource_panel.x_location_grid = [0, 0];
6857            resource_panel.y_location_grid = [0, 0];
6858            resource_panel.x_size_grid = [0, 0];
6859            resource_panel.y_size_grid = [0, 0];
6860        };
6861        if resource_panel.min_size[0] < 10_f32 {
6862            resource_panel.min_size[0] = 10_f32;
6863        };
6864        if resource_panel.min_size[1] < 10_f32 {
6865            resource_panel.min_size[1] = 10_f32;
6866        };
6867        if resource_panel.origin_size[0] < resource_panel.min_size[0] {
6868            resource_panel.origin_size[0] = resource_panel.min_size[0];
6869        };
6870        if resource_panel.origin_size[1] < resource_panel.min_size[1] {
6871            resource_panel.origin_size[1] = resource_panel.min_size[1];
6872        };
6873        [resource_panel.position, resource_panel.size] =
6874            self.position_size_processor(PositionConfig::from_resource_panel(&resource_panel), ctx);
6875        if let Some(custom_rect_config) = &mut resource_panel.display_rect.clone() {
6876            *custom_rect_config = custom_rect_config
6877                .clone()
6878                .from_position_config(&PositionConfig::from_resource_panel(&resource_panel));
6879        };
6880        if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
6881            let top_rect = Rect::from_min_size(
6882                [
6883                    resource_panel.position[0] - 3_f32,
6884                    resource_panel.position[1] - 3_f32,
6885                ]
6886                .into(),
6887                [resource_panel.size[0] + 6_f32, 6_f32].into(),
6888            );
6889            let bottom_rect = Rect::from_min_size(
6890                [
6891                    resource_panel.position[0] - 3_f32,
6892                    resource_panel.position[1] + resource_panel.size[1] - 3_f32,
6893                ]
6894                .into(),
6895                [resource_panel.size[0] + 6_f32, 6_f32].into(),
6896            );
6897            let left_rect = Rect::from_min_size(
6898                [
6899                    resource_panel.position[0] - 3_f32,
6900                    resource_panel.position[1] - 3_f32,
6901                ]
6902                .into(),
6903                [6_f32, resource_panel.size[1] + 6_f32].into(),
6904            );
6905            let right_rect = Rect::from_min_size(
6906                [
6907                    resource_panel.position[0] + resource_panel.size[0] - 3_f32,
6908                    resource_panel.position[1] - 3_f32,
6909                ]
6910                .into(),
6911                [6_f32, resource_panel.size[1] + 6_f32].into(),
6912            );
6913            match [
6914                top_rect.contains(mouse_pos),
6915                bottom_rect.contains(mouse_pos),
6916                left_rect.contains(mouse_pos),
6917                right_rect.contains(mouse_pos),
6918            ] {
6919                [true, false, false, false] => {
6920                    if resource_panel.resizable[0] {
6921                        if resource_panel.last_frame_mouse_status.is_none()
6922                            && ui.input(|i| i.pointer.primary_pressed())
6923                        {
6924                            resource_panel.last_frame_mouse_status = Some((
6925                                mouse_pos.into(),
6926                                ClickAim::TopResize,
6927                                [
6928                                    mouse_pos.x - resource_panel.position[0],
6929                                    mouse_pos.y - resource_panel.position[1],
6930                                ],
6931                            ))
6932                        };
6933                        if resource_panel.size[1] > resource_panel.min_size[1]
6934                            && (resource_panel.max_size.is_none()
6935                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
6936                        {
6937                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
6938                        } else if resource_panel.max_size.is_some()
6939                            && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
6940                        {
6941                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
6942                        } else {
6943                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
6944                        };
6945                    };
6946                }
6947                [false, true, false, false] => {
6948                    if resource_panel.resizable[1] {
6949                        if resource_panel.last_frame_mouse_status.is_none()
6950                            && ui.input(|i| i.pointer.primary_pressed())
6951                        {
6952                            resource_panel.last_frame_mouse_status = Some((
6953                                mouse_pos.into(),
6954                                ClickAim::BottomResize,
6955                                [
6956                                    mouse_pos.x - resource_panel.position[0],
6957                                    mouse_pos.y - resource_panel.position[1],
6958                                ],
6959                            ))
6960                        };
6961                        if resource_panel.size[1] > resource_panel.min_size[1]
6962                            && (resource_panel.max_size.is_none()
6963                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
6964                        {
6965                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
6966                        } else if resource_panel.max_size.is_some()
6967                            && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
6968                        {
6969                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
6970                        } else {
6971                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
6972                        };
6973                    };
6974                }
6975                [false, false, true, false] => {
6976                    if resource_panel.resizable[2] {
6977                        if resource_panel.last_frame_mouse_status.is_none()
6978                            && ui.input(|i| i.pointer.primary_pressed())
6979                        {
6980                            resource_panel.last_frame_mouse_status = Some((
6981                                mouse_pos.into(),
6982                                ClickAim::LeftResize,
6983                                [
6984                                    mouse_pos.x - resource_panel.position[0],
6985                                    mouse_pos.y - resource_panel.position[1],
6986                                ],
6987                            ))
6988                        };
6989                        if resource_panel.size[0] > resource_panel.min_size[0]
6990                            && (resource_panel.max_size.is_none()
6991                                || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
6992                        {
6993                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
6994                        } else if resource_panel.max_size.is_some()
6995                            && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
6996                        {
6997                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
6998                        } else {
6999                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
7000                        };
7001                    };
7002                }
7003                [false, false, false, true] => {
7004                    if resource_panel.resizable[3] {
7005                        if resource_panel.last_frame_mouse_status.is_none()
7006                            && ui.input(|i| i.pointer.primary_pressed())
7007                        {
7008                            resource_panel.last_frame_mouse_status = Some((
7009                                mouse_pos.into(),
7010                                ClickAim::RightResize,
7011                                [
7012                                    mouse_pos.x - resource_panel.position[0],
7013                                    mouse_pos.y - resource_panel.position[1],
7014                                ],
7015                            ))
7016                        };
7017                        if resource_panel.size[0] > resource_panel.min_size[0]
7018                            && (resource_panel.max_size.is_none()
7019                                || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7020                        {
7021                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7022                        } else if resource_panel.max_size.is_some()
7023                            && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7024                        {
7025                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
7026                        } else {
7027                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
7028                        };
7029                    };
7030                }
7031                [true, false, true, false] => {
7032                    match [resource_panel.resizable[0], resource_panel.resizable[2]] {
7033                        [true, true] => {
7034                            if resource_panel.last_frame_mouse_status.is_none()
7035                                && ui.input(|i| i.pointer.primary_pressed())
7036                            {
7037                                resource_panel.last_frame_mouse_status = Some((
7038                                    mouse_pos.into(),
7039                                    ClickAim::LeftTopResize,
7040                                    [
7041                                        mouse_pos.x - resource_panel.position[0],
7042                                        mouse_pos.y - resource_panel.position[1],
7043                                    ],
7044                                ))
7045                            };
7046                            if resource_panel.size[0] > resource_panel.min_size[0]
7047                                && (resource_panel.max_size.is_none()
7048                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7049                                || resource_panel.size[1] > resource_panel.min_size[1]
7050                                    && (resource_panel.max_size.is_none()
7051                                        || resource_panel.size[1]
7052                                            < resource_panel.max_size.unwrap()[1])
7053                            {
7054                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
7055                            } else if resource_panel.max_size.is_some()
7056                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7057                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7058                            {
7059                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
7060                            } else {
7061                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
7062                            };
7063                        }
7064                        [false, true] => {
7065                            if resource_panel.last_frame_mouse_status.is_none()
7066                                && ui.input(|i| i.pointer.primary_pressed())
7067                            {
7068                                resource_panel.last_frame_mouse_status = Some((
7069                                    mouse_pos.into(),
7070                                    ClickAim::LeftResize,
7071                                    [
7072                                        mouse_pos.x - resource_panel.position[0],
7073                                        mouse_pos.y - resource_panel.position[1],
7074                                    ],
7075                                ))
7076                            };
7077                            if resource_panel.size[0] > resource_panel.min_size[0]
7078                                && (resource_panel.max_size.is_none()
7079                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7080                            {
7081                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7082                            } else if resource_panel.max_size.is_some()
7083                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7084                            {
7085                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
7086                            } else {
7087                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
7088                            };
7089                        }
7090                        [true, false] => {
7091                            if resource_panel.last_frame_mouse_status.is_none()
7092                                && ui.input(|i| i.pointer.primary_pressed())
7093                            {
7094                                resource_panel.last_frame_mouse_status = Some((
7095                                    mouse_pos.into(),
7096                                    ClickAim::TopResize,
7097                                    [
7098                                        mouse_pos.x - resource_panel.position[0],
7099                                        mouse_pos.y - resource_panel.position[1],
7100                                    ],
7101                                ))
7102                            };
7103                            if resource_panel.size[1] > resource_panel.min_size[1]
7104                                && (resource_panel.max_size.is_none()
7105                                    || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7106                            {
7107                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7108                            } else if resource_panel.max_size.is_some()
7109                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7110                            {
7111                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7112                            } else {
7113                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7114                            };
7115                        }
7116                        [false, false] => {}
7117                    }
7118                }
7119                [false, true, false, true] => {
7120                    match [resource_panel.resizable[1], resource_panel.resizable[3]] {
7121                        [true, true] => {
7122                            if resource_panel.last_frame_mouse_status.is_none()
7123                                && ui.input(|i| i.pointer.primary_pressed())
7124                            {
7125                                resource_panel.last_frame_mouse_status = Some((
7126                                    mouse_pos.into(),
7127                                    ClickAim::RightBottomResize,
7128                                    [
7129                                        mouse_pos.x - resource_panel.position[0],
7130                                        mouse_pos.y - resource_panel.position[1],
7131                                    ],
7132                                ))
7133                            };
7134                            if resource_panel.size[0] > resource_panel.min_size[0]
7135                                && (resource_panel.max_size.is_none()
7136                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7137                                || resource_panel.size[1] > resource_panel.min_size[1]
7138                                    && (resource_panel.max_size.is_none()
7139                                        || resource_panel.size[1]
7140                                            < resource_panel.max_size.unwrap()[1])
7141                            {
7142                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
7143                            } else if resource_panel.max_size.is_some()
7144                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7145                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7146                            {
7147                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
7148                            } else {
7149                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
7150                            };
7151                        }
7152                        [false, true] => {
7153                            if resource_panel.last_frame_mouse_status.is_none()
7154                                && ui.input(|i| i.pointer.primary_pressed())
7155                            {
7156                                resource_panel.last_frame_mouse_status = Some((
7157                                    mouse_pos.into(),
7158                                    ClickAim::RightResize,
7159                                    [
7160                                        mouse_pos.x - resource_panel.position[0],
7161                                        mouse_pos.y - resource_panel.position[1],
7162                                    ],
7163                                ))
7164                            };
7165                            if resource_panel.size[0] > resource_panel.min_size[0]
7166                                && (resource_panel.max_size.is_none()
7167                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7168                            {
7169                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7170                            } else if resource_panel.max_size.is_some()
7171                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7172                            {
7173                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
7174                            } else {
7175                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
7176                            };
7177                        }
7178                        [true, false] => {
7179                            if resource_panel.last_frame_mouse_status.is_none()
7180                                && ui.input(|i| i.pointer.primary_pressed())
7181                            {
7182                                resource_panel.last_frame_mouse_status = Some((
7183                                    mouse_pos.into(),
7184                                    ClickAim::BottomResize,
7185                                    [
7186                                        mouse_pos.x - resource_panel.position[0],
7187                                        mouse_pos.y - resource_panel.position[1],
7188                                    ],
7189                                ))
7190                            };
7191                            if resource_panel.size[1] > resource_panel.min_size[1]
7192                                && (resource_panel.max_size.is_none()
7193                                    || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7194                            {
7195                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7196                            } else if resource_panel.max_size.is_some()
7197                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7198                            {
7199                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7200                            } else {
7201                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7202                            };
7203                        }
7204                        [false, false] => {}
7205                    }
7206                }
7207                [true, false, false, true] => {
7208                    match [resource_panel.resizable[0], resource_panel.resizable[3]] {
7209                        [true, true] => {
7210                            if resource_panel.last_frame_mouse_status.is_none()
7211                                && ui.input(|i| i.pointer.primary_pressed())
7212                            {
7213                                resource_panel.last_frame_mouse_status = Some((
7214                                    mouse_pos.into(),
7215                                    ClickAim::RightTopResize,
7216                                    [
7217                                        mouse_pos.x - resource_panel.position[0],
7218                                        mouse_pos.y - resource_panel.position[1],
7219                                    ],
7220                                ))
7221                            };
7222                            if resource_panel.size[0] > resource_panel.min_size[0]
7223                                && (resource_panel.max_size.is_none()
7224                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7225                                || resource_panel.size[1] > resource_panel.min_size[1]
7226                                    && (resource_panel.max_size.is_none()
7227                                        || resource_panel.size[1]
7228                                            < resource_panel.max_size.unwrap()[1])
7229                            {
7230                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
7231                            } else if resource_panel.max_size.is_some()
7232                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7233                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7234                            {
7235                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
7236                            } else {
7237                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
7238                            };
7239                        }
7240                        [false, true] => {
7241                            if resource_panel.last_frame_mouse_status.is_none()
7242                                && ui.input(|i| i.pointer.primary_pressed())
7243                            {
7244                                resource_panel.last_frame_mouse_status = Some((
7245                                    mouse_pos.into(),
7246                                    ClickAim::RightResize,
7247                                    [
7248                                        mouse_pos.x - resource_panel.position[0],
7249                                        mouse_pos.y - resource_panel.position[1],
7250                                    ],
7251                                ))
7252                            };
7253                            if resource_panel.size[0] > resource_panel.min_size[0]
7254                                && (resource_panel.max_size.is_none()
7255                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7256                            {
7257                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7258                            } else if resource_panel.max_size.is_some()
7259                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7260                            {
7261                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
7262                            } else {
7263                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
7264                            };
7265                        }
7266                        [true, false] => {
7267                            if resource_panel.last_frame_mouse_status.is_none()
7268                                && ui.input(|i| i.pointer.primary_pressed())
7269                            {
7270                                resource_panel.last_frame_mouse_status = Some((
7271                                    mouse_pos.into(),
7272                                    ClickAim::TopResize,
7273                                    [
7274                                        mouse_pos.x - resource_panel.position[0],
7275                                        mouse_pos.y - resource_panel.position[1],
7276                                    ],
7277                                ))
7278                            };
7279                            if resource_panel.size[1] > resource_panel.min_size[1]
7280                                && (resource_panel.max_size.is_none()
7281                                    || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7282                            {
7283                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7284                            } else if resource_panel.max_size.is_some()
7285                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7286                            {
7287                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7288                            } else {
7289                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7290                            };
7291                        }
7292                        [false, false] => {}
7293                    }
7294                }
7295                [false, true, true, false] => {
7296                    match [resource_panel.resizable[1], resource_panel.resizable[2]] {
7297                        [true, true] => {
7298                            if resource_panel.last_frame_mouse_status.is_none()
7299                                && ui.input(|i| i.pointer.primary_pressed())
7300                            {
7301                                resource_panel.last_frame_mouse_status = Some((
7302                                    mouse_pos.into(),
7303                                    ClickAim::LeftBottomResize,
7304                                    [
7305                                        mouse_pos.x - resource_panel.position[0],
7306                                        mouse_pos.y - resource_panel.position[1],
7307                                    ],
7308                                ))
7309                            };
7310                            if resource_panel.size[0] > resource_panel.min_size[0]
7311                                && (resource_panel.max_size.is_none()
7312                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7313                                || resource_panel.size[1] > resource_panel.min_size[1]
7314                                    && (resource_panel.max_size.is_none()
7315                                        || resource_panel.size[1]
7316                                            < resource_panel.max_size.unwrap()[1])
7317                            {
7318                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
7319                            } else if resource_panel.max_size.is_some()
7320                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7321                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7322                            {
7323                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
7324                            } else {
7325                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
7326                            };
7327                        }
7328                        [false, true] => {
7329                            if resource_panel.last_frame_mouse_status.is_none()
7330                                && ui.input(|i| i.pointer.primary_pressed())
7331                            {
7332                                resource_panel.last_frame_mouse_status = Some((
7333                                    mouse_pos.into(),
7334                                    ClickAim::LeftResize,
7335                                    [
7336                                        mouse_pos.x - resource_panel.position[0],
7337                                        mouse_pos.y - resource_panel.position[1],
7338                                    ],
7339                                ))
7340                            };
7341                            if resource_panel.size[0] > resource_panel.min_size[0]
7342                                && (resource_panel.max_size.is_none()
7343                                    || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7344                            {
7345                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7346                            } else if resource_panel.max_size.is_some()
7347                                && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7348                            {
7349                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
7350                            } else {
7351                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
7352                            };
7353                        }
7354                        [true, false] => {
7355                            if resource_panel.last_frame_mouse_status.is_none()
7356                                && ui.input(|i| i.pointer.primary_pressed())
7357                            {
7358                                resource_panel.last_frame_mouse_status = Some((
7359                                    mouse_pos.into(),
7360                                    ClickAim::BottomResize,
7361                                    [
7362                                        mouse_pos.x - resource_panel.position[0],
7363                                        mouse_pos.y - resource_panel.position[1],
7364                                    ],
7365                                ))
7366                            };
7367                            if resource_panel.size[1] > resource_panel.min_size[1]
7368                                && (resource_panel.max_size.is_none()
7369                                    || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7370                            {
7371                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7372                            } else if resource_panel.max_size.is_some()
7373                                && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7374                            {
7375                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7376                            } else {
7377                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7378                            };
7379                        }
7380                        [false, false] => {}
7381                    }
7382                }
7383                _ => {}
7384            };
7385            resource_panel.last_frame_mouse_status =
7386                if resource_panel.last_frame_mouse_status.is_none()
7387                    && rect.contains(mouse_pos)
7388                    && ui.input(|i| i.pointer.primary_pressed())
7389                {
7390                    Some((
7391                        [mouse_pos.x, mouse_pos.y],
7392                        ClickAim::Move,
7393                        [
7394                            mouse_pos.x - resource_panel.position[0],
7395                            mouse_pos.y - resource_panel.position[1],
7396                        ],
7397                    ))
7398                } else if resource_panel.last_frame_mouse_status.is_some()
7399                    && !ui.input(|i| i.pointer.primary_released())
7400                {
7401                    Some((
7402                        [mouse_pos.x, mouse_pos.y],
7403                        resource_panel.last_frame_mouse_status.unwrap().1,
7404                        resource_panel.last_frame_mouse_status.unwrap().2,
7405                    ))
7406                } else {
7407                    None
7408                };
7409            let [x_scroll_delta, y_scroll_delta] = if resource_panel.use_smooth_scroll_delta {
7410                ui.input(|i| i.smooth_scroll_delta).into()
7411            } else {
7412                ui.input(|i| i.raw_scroll_delta).into()
7413            };
7414            if let Some(_) = resource_panel.scroll_length_method[0]
7415                && x_scroll_delta != 0_f32
7416            {
7417                resource_panel.scroll_progress[0] = if resource_panel.scroll_progress[0]
7418                    + x_scroll_delta * resource_panel.scroll_sensitivity
7419                    > resource_panel.scroll_length[0]
7420                {
7421                    resource_panel.scroll_length[0]
7422                } else if resource_panel.scroll_progress[0]
7423                    + x_scroll_delta * resource_panel.scroll_sensitivity
7424                    > 0_f32
7425                {
7426                    resource_panel.scroll_progress[0]
7427                        + x_scroll_delta * resource_panel.scroll_sensitivity
7428                } else {
7429                    0_f32
7430                };
7431            };
7432            if let Some(_) = resource_panel.scroll_length_method[1]
7433                && y_scroll_delta != 0_f32
7434            {
7435                resource_panel.scroll_progress[1] = if resource_panel.scroll_progress[1]
7436                    + y_scroll_delta * resource_panel.scroll_sensitivity
7437                    > resource_panel.scroll_length[1]
7438                {
7439                    resource_panel.scroll_length[1]
7440                } else if resource_panel.scroll_progress[1]
7441                    + y_scroll_delta * resource_panel.scroll_sensitivity
7442                    > 0_f32
7443                {
7444                    resource_panel.scroll_progress[1]
7445                        + y_scroll_delta * resource_panel.scroll_sensitivity
7446                } else {
7447                    0_f32
7448                };
7449            };
7450        };
7451        if let Some((mouse_pos, click_aim, offset)) = resource_panel.last_frame_mouse_status {
7452            match click_aim {
7453                ClickAim::LeftTopResize => {
7454                    if resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7455                        > resource_panel.min_size[0]
7456                        && (resource_panel.max_size.is_none()
7457                            || resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7458                                < resource_panel.max_size.unwrap()[0])
7459                    {
7460                        resource_panel.origin_size[0] += resource_panel.position[0] - mouse_pos[0];
7461                        resource_panel.origin_position[0] = mouse_pos[0];
7462                    } else if resource_panel.max_size.is_some()
7463                        && resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7464                            >= resource_panel.max_size.unwrap()[0]
7465                    {
7466                        resource_panel.origin_position[0] -=
7467                            resource_panel.max_size.unwrap()[0] - resource_panel.origin_size[0];
7468                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7469                    } else {
7470                        resource_panel.origin_position[0] +=
7471                            resource_panel.origin_size[0] - resource_panel.min_size[0];
7472                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7473                    };
7474                    if resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7475                        > resource_panel.min_size[1]
7476                        && (resource_panel.max_size.is_none()
7477                            || resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7478                                < resource_panel.max_size.unwrap()[1])
7479                    {
7480                        resource_panel.origin_size[1] += resource_panel.position[1] - mouse_pos[1];
7481                        resource_panel.origin_position[1] = mouse_pos[1];
7482                    } else if resource_panel.max_size.is_some()
7483                        && resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7484                            >= resource_panel.max_size.unwrap()[1]
7485                    {
7486                        resource_panel.origin_position[1] -=
7487                            resource_panel.max_size.unwrap()[1] - resource_panel.origin_size[1];
7488                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7489                    } else {
7490                        resource_panel.origin_position[1] +=
7491                            resource_panel.origin_size[1] - resource_panel.min_size[1];
7492                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7493                    };
7494                    if resource_panel.size[0] > resource_panel.min_size[0]
7495                        && (resource_panel.max_size.is_none()
7496                            || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7497                        || resource_panel.size[1] > resource_panel.min_size[1]
7498                            && (resource_panel.max_size.is_none()
7499                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7500                    {
7501                        ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
7502                    } else if resource_panel.max_size.is_some()
7503                        && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7504                        && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7505                    {
7506                        ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
7507                    } else {
7508                        ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
7509                    };
7510                }
7511                ClickAim::RightBottomResize => {
7512                    if mouse_pos[0] - resource_panel.position[0] > resource_panel.min_size[0]
7513                        && (resource_panel.max_size.is_none()
7514                            || mouse_pos[0] - resource_panel.position[0]
7515                                < resource_panel.max_size.unwrap()[0])
7516                    {
7517                        resource_panel.origin_size[0] = mouse_pos[0] - resource_panel.position[0];
7518                    } else if resource_panel.max_size.is_some()
7519                        && mouse_pos[0] - resource_panel.position[0]
7520                            >= resource_panel.max_size.unwrap()[0]
7521                    {
7522                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7523                    } else {
7524                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7525                    };
7526                    if mouse_pos[1] - resource_panel.position[1] > resource_panel.min_size[1]
7527                        && (resource_panel.max_size.is_none()
7528                            || mouse_pos[1] - resource_panel.position[1]
7529                                < resource_panel.max_size.unwrap()[1])
7530                    {
7531                        resource_panel.origin_size[1] = mouse_pos[1] - resource_panel.position[1];
7532                    } else if resource_panel.max_size.is_some()
7533                        && mouse_pos[1] - resource_panel.position[1]
7534                            >= resource_panel.max_size.unwrap()[1]
7535                    {
7536                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7537                    } else {
7538                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7539                    };
7540                    if resource_panel.size[0] > resource_panel.min_size[0]
7541                        && (resource_panel.max_size.is_none()
7542                            || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7543                        || resource_panel.size[1] > resource_panel.min_size[1]
7544                            && (resource_panel.max_size.is_none()
7545                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7546                    {
7547                        ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
7548                    } else if resource_panel.max_size.is_some()
7549                        && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7550                        && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7551                    {
7552                        ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
7553                    } else {
7554                        ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
7555                    };
7556                }
7557                ClickAim::RightTopResize => {
7558                    if mouse_pos[0] - resource_panel.position[0] > resource_panel.min_size[0]
7559                        && (resource_panel.max_size.is_none()
7560                            || mouse_pos[0] - resource_panel.position[0]
7561                                < resource_panel.max_size.unwrap()[0])
7562                    {
7563                        resource_panel.origin_size[0] = mouse_pos[0] - resource_panel.position[0];
7564                    } else if resource_panel.max_size.is_some()
7565                        && mouse_pos[0] - resource_panel.position[0]
7566                            >= resource_panel.max_size.unwrap()[0]
7567                    {
7568                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7569                    } else {
7570                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7571                    };
7572                    if resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7573                        > resource_panel.min_size[1]
7574                        && (resource_panel.max_size.is_none()
7575                            || resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7576                                < resource_panel.max_size.unwrap()[1])
7577                    {
7578                        resource_panel.origin_size[1] += resource_panel.position[1] - mouse_pos[1];
7579                        resource_panel.origin_position[1] = mouse_pos[1];
7580                    } else if resource_panel.max_size.is_some()
7581                        && resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7582                            >= resource_panel.max_size.unwrap()[1]
7583                    {
7584                        resource_panel.origin_position[1] -=
7585                            resource_panel.max_size.unwrap()[1] - resource_panel.origin_size[1];
7586                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7587                    } else {
7588                        resource_panel.origin_position[1] +=
7589                            resource_panel.origin_size[1] - resource_panel.min_size[1];
7590                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7591                    };
7592                    if resource_panel.size[0] > resource_panel.min_size[0]
7593                        && (resource_panel.max_size.is_none()
7594                            || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7595                        || resource_panel.size[1] > resource_panel.min_size[1]
7596                            && (resource_panel.max_size.is_none()
7597                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7598                    {
7599                        ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
7600                    } else if resource_panel.max_size.is_some()
7601                        && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7602                        && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7603                    {
7604                        ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
7605                    } else {
7606                        ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
7607                    };
7608                }
7609                ClickAim::LeftBottomResize => {
7610                    if resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7611                        > resource_panel.min_size[0]
7612                        && (resource_panel.max_size.is_none()
7613                            || resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7614                                < resource_panel.max_size.unwrap()[0])
7615                    {
7616                        resource_panel.origin_size[0] += resource_panel.position[0] - mouse_pos[0];
7617                        resource_panel.origin_position[0] = mouse_pos[0];
7618                    } else if resource_panel.max_size.is_some()
7619                        && resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7620                            >= resource_panel.max_size.unwrap()[0]
7621                    {
7622                        resource_panel.origin_position[0] -=
7623                            resource_panel.max_size.unwrap()[0] - resource_panel.origin_size[0];
7624                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7625                    } else {
7626                        resource_panel.origin_position[0] +=
7627                            resource_panel.origin_size[0] - resource_panel.min_size[0];
7628                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7629                    };
7630                    if mouse_pos[1] - resource_panel.position[1] > resource_panel.min_size[1]
7631                        && (resource_panel.max_size.is_none()
7632                            || mouse_pos[1] - resource_panel.position[1]
7633                                < resource_panel.max_size.unwrap()[1])
7634                    {
7635                        resource_panel.origin_size[1] = mouse_pos[1] - resource_panel.position[1];
7636                    } else if resource_panel.max_size.is_some()
7637                        && mouse_pos[1] - resource_panel.position[1]
7638                            >= resource_panel.max_size.unwrap()[1]
7639                    {
7640                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7641                    } else {
7642                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7643                    };
7644                    if resource_panel.size[0] > resource_panel.min_size[0]
7645                        && (resource_panel.max_size.is_none()
7646                            || resource_panel.size[0] < resource_panel.max_size.unwrap()[0])
7647                        || resource_panel.size[1] > resource_panel.min_size[1]
7648                            && (resource_panel.max_size.is_none()
7649                                || resource_panel.size[1] < resource_panel.max_size.unwrap()[1])
7650                    {
7651                        ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
7652                    } else if resource_panel.max_size.is_some()
7653                        && resource_panel.size[0] >= resource_panel.max_size.unwrap()[0]
7654                        && resource_panel.size[1] >= resource_panel.max_size.unwrap()[1]
7655                    {
7656                        ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
7657                    } else {
7658                        ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
7659                    };
7660                }
7661                ClickAim::TopResize => {
7662                    if resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7663                        > resource_panel.min_size[1]
7664                        && (resource_panel.max_size.is_none()
7665                            || resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7666                                < resource_panel.max_size.unwrap()[1])
7667                    {
7668                        resource_panel.origin_size[1] += resource_panel.position[1] - mouse_pos[1];
7669                        resource_panel.origin_position[1] = mouse_pos[1];
7670                        ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7671                    } else if resource_panel.max_size.is_some()
7672                        && resource_panel.position[1] - mouse_pos[1] + resource_panel.size[1]
7673                            >= resource_panel.max_size.unwrap()[1]
7674                    {
7675                        resource_panel.origin_position[1] -=
7676                            resource_panel.max_size.unwrap()[1] - resource_panel.origin_size[1];
7677                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7678                        ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7679                    } else {
7680                        resource_panel.origin_position[1] +=
7681                            resource_panel.origin_size[1] - resource_panel.min_size[1];
7682                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7683                        ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7684                    };
7685                }
7686                ClickAim::BottomResize => {
7687                    if mouse_pos[1] - resource_panel.position[1] > resource_panel.min_size[1]
7688                        && (resource_panel.max_size.is_none()
7689                            || mouse_pos[1] - resource_panel.position[1]
7690                                < resource_panel.max_size.unwrap()[1])
7691                    {
7692                        resource_panel.origin_size[1] = mouse_pos[1] - resource_panel.position[1];
7693                        ctx.set_cursor_icon(CursorIcon::ResizeVertical);
7694                    } else if resource_panel.max_size.is_some()
7695                        && mouse_pos[1] - resource_panel.position[1]
7696                            >= resource_panel.max_size.unwrap()[1]
7697                    {
7698                        resource_panel.origin_size[1] = resource_panel.max_size.unwrap()[1];
7699                        ctx.set_cursor_icon(CursorIcon::ResizeNorth);
7700                    } else {
7701                        resource_panel.origin_size[1] = resource_panel.min_size[1];
7702                        ctx.set_cursor_icon(CursorIcon::ResizeSouth);
7703                    };
7704                }
7705                ClickAim::LeftResize => {
7706                    if resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7707                        > resource_panel.min_size[0]
7708                        && (resource_panel.max_size.is_none()
7709                            || resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7710                                < resource_panel.max_size.unwrap()[0])
7711                    {
7712                        resource_panel.origin_size[0] += resource_panel.position[0] - mouse_pos[0];
7713                        resource_panel.origin_position[0] = mouse_pos[0];
7714                        ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7715                    } else if resource_panel.max_size.is_some()
7716                        && resource_panel.position[0] - mouse_pos[0] + resource_panel.size[0]
7717                            >= resource_panel.max_size.unwrap()[0]
7718                    {
7719                        resource_panel.origin_position[0] -=
7720                            resource_panel.max_size.unwrap()[0] - resource_panel.origin_size[0];
7721                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7722                        ctx.set_cursor_icon(CursorIcon::ResizeEast);
7723                    } else {
7724                        resource_panel.origin_position[0] +=
7725                            resource_panel.origin_size[0] - resource_panel.min_size[0];
7726                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7727                        ctx.set_cursor_icon(CursorIcon::ResizeWest);
7728                    };
7729                }
7730                ClickAim::RightResize => {
7731                    if mouse_pos[0] - resource_panel.position[0] > resource_panel.min_size[0]
7732                        && (resource_panel.max_size.is_none()
7733                            || mouse_pos[0] - resource_panel.position[0]
7734                                < resource_panel.max_size.unwrap()[0])
7735                    {
7736                        resource_panel.origin_size[0] = mouse_pos[0] - resource_panel.position[0];
7737                        ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
7738                    } else if resource_panel.max_size.is_some()
7739                        && mouse_pos[0] - resource_panel.position[0]
7740                            >= resource_panel.max_size.unwrap()[0]
7741                    {
7742                        resource_panel.origin_size[0] = resource_panel.max_size.unwrap()[0];
7743                        ctx.set_cursor_icon(CursorIcon::ResizeWest);
7744                    } else {
7745                        resource_panel.origin_size[0] = resource_panel.min_size[0];
7746                        ctx.set_cursor_icon(CursorIcon::ResizeEast);
7747                    };
7748                }
7749                ClickAim::Move => {
7750                    if resource_panel.movable[0] {
7751                        resource_panel.origin_position[0] = mouse_pos[0] - offset[0];
7752                    };
7753                    if resource_panel.movable[1] {
7754                        resource_panel.origin_position[1] = mouse_pos[1] - offset[1];
7755                    };
7756                }
7757            };
7758        };
7759        if let Some(config) = &mut resource_panel.display_rect.clone() {
7760            *config = config
7761                .clone()
7762                .from_position_config(&PositionConfig::from_resource_panel(&resource_panel));
7763            let custom_rect = self
7764                .get_resource_mut::<CustomRect>(
7765                    &format!("{}DisplayRect", resource_panel.name),
7766                    "CustomRect",
7767                )
7768                .unwrap()
7769                .unwrap();
7770            *custom_rect = CustomRect::default()
7771                .name(&format!("{}DisplayRect", resource_panel.name))
7772                .from_config(config)
7773                .from_position_config(&PositionConfig::from_resource_panel(&resource_panel));
7774            self.custom_rect(
7775                &format!("{}DisplayRect", resource_panel.name),
7776                ui,
7777                ctx,
7778                safe_mode,
7779            )
7780            .unwrap();
7781        };
7782        let mut resource_point_list: Vec<([f32; 2], [f32; 2], [bool; 2])> = Vec::new();
7783        for rcr in &mut self.rust_constructor_resource {
7784            if self
7785                .basic_front_resource_list
7786                .contains(&rcr.expose_type().to_string())
7787            {
7788                let mut basic_front_resource: Box<dyn BasicFrontResource> = match rcr.expose_type()
7789                {
7790                    "Image" => {
7791                        let mut image =
7792                            Box::new(rcr.as_any().downcast_ref::<Image>().unwrap().clone());
7793                        image.x_location_grid = [0, 0];
7794                        image.y_location_grid = [0, 0];
7795                        image.x_size_grid = [0, 0];
7796                        image.y_size_grid = [0, 0];
7797                        image
7798                    }
7799                    "Text" => {
7800                        let mut text =
7801                            Box::new(rcr.as_any().downcast_ref::<Text>().unwrap().clone());
7802                        text.x_location_grid = [0, 0];
7803                        text.y_location_grid = [0, 0];
7804                        text.x_size_grid = [0, 0];
7805                        text.y_size_grid = [0, 0];
7806                        text
7807                    }
7808                    "CustomRect" => {
7809                        let mut custom_rect =
7810                            Box::new(rcr.as_any().downcast_ref::<CustomRect>().unwrap().clone());
7811                        custom_rect.x_location_grid = [0, 0];
7812                        custom_rect.y_location_grid = [0, 0];
7813                        custom_rect.x_size_grid = [0, 0];
7814                        custom_rect.y_size_grid = [0, 0];
7815                        custom_rect
7816                    }
7817                    _ => {
7818                        unreachable!()
7819                    }
7820                };
7821                if basic_front_resource.display_panel_name() == resource_panel.name {
7822                    basic_front_resource.modify_clip_rect(&Some(
7823                        PositionConfig::from_resource_panel(&resource_panel),
7824                    ));
7825                    basic_front_resource.modify_offset(
7826                        if basic_front_resource.display_allow_scrolling()[0] {
7827                            basic_front_resource.display_offset()[0]
7828                                + (resource_panel.scroll_progress[0]
7829                                    - resource_panel.last_frame_scroll_progress[0])
7830                        } else {
7831                            basic_front_resource.display_offset()[0]
7832                        },
7833                        if basic_front_resource.display_allow_scrolling()[1] {
7834                            basic_front_resource.display_offset()[1]
7835                                + (resource_panel.scroll_progress[1]
7836                                    - resource_panel.last_frame_scroll_progress[1])
7837                        } else {
7838                            basic_front_resource.display_offset()[1]
7839                        },
7840                    );
7841                    if let Some(layout) = &mut basic_front_resource.display_panel_layout().clone() {
7842                        if basic_front_resource
7843                            .display_allow_scrolling()
7844                            .contains(&false)
7845                        {
7846                            layout.1 = match layout.1 {
7847                                PanelLayout::Horizontal(top, bottom, left, right, _) => {
7848                                    PanelLayout::None(top, bottom, left, right, false)
7849                                }
7850                                PanelLayout::Vertical(top, bottom, left, right, _) => {
7851                                    PanelLayout::None(top, bottom, left, right, false)
7852                                }
7853                                PanelLayout::None(_, _, _, _, _) => layout.1,
7854                            };
7855                        };
7856                        match layout.1 {
7857                            PanelLayout::Vertical(top, bottom, left, right, move_to_bottom) => {
7858                                let mut modify_y = 0_f32;
7859                                let [default_x_position, default_y_position] = match layout.0 {
7860                                    PanelLocation::Absolute(x, y) => [
7861                                        resource_panel.position[0] + x,
7862                                        resource_panel.position[1] + y,
7863                                    ],
7864                                    PanelLocation::Relative([x, y]) => [
7865                                        resource_panel.position[0]
7866                                            + (resource_panel.size[0] / x[1] as f32 * x[0] as f32),
7867                                        resource_panel.position[1]
7868                                            + (resource_panel.size[1] / y[1] as f32 * y[0] as f32),
7869                                    ],
7870                                };
7871                                let default_x_position =
7872                                    match basic_front_resource.display_center_display().0 {
7873                                        HorizontalAlign::Left => default_x_position,
7874                                        HorizontalAlign::Center => {
7875                                            default_x_position
7876                                                - basic_front_resource.display_size()[0] / 2.0
7877                                        }
7878                                        HorizontalAlign::Right => {
7879                                            default_x_position
7880                                                - basic_front_resource.display_size()[0]
7881                                        }
7882                                    };
7883                                let default_y_position =
7884                                    match basic_front_resource.display_center_display().1 {
7885                                        VerticalAlign::Top => default_y_position,
7886                                        VerticalAlign::Center => {
7887                                            default_y_position
7888                                                - basic_front_resource.display_size()[1] / 2.0
7889                                        }
7890                                        VerticalAlign::Bottom => {
7891                                            default_y_position
7892                                                - basic_front_resource.display_size()[1]
7893                                        }
7894                                    };
7895                                for point in &resource_point_list {
7896                                    if default_x_position - left < point.1[0]
7897                                        && default_y_position - top < point.1[1]
7898                                        && default_x_position
7899                                            + basic_front_resource.display_size()[0]
7900                                            + right
7901                                            > point.0[0]
7902                                        && default_y_position
7903                                            + basic_front_resource.display_size()[1]
7904                                            + bottom
7905                                            > point.0[1]
7906                                    {
7907                                        if move_to_bottom
7908                                            && point.1[1] - default_y_position + top > modify_y
7909                                        {
7910                                            modify_y = point.1[1] - default_y_position + top;
7911                                        } else if !move_to_bottom
7912                                            && point.0[1]
7913                                                - default_y_position
7914                                                - basic_front_resource.display_size()[1]
7915                                                - bottom
7916                                                < modify_y
7917                                        {
7918                                            modify_y = point.0[1]
7919                                                - default_y_position
7920                                                - basic_front_resource.display_size()[1];
7921                                        };
7922                                    };
7923                                }
7924                                let real_x_position =
7925                                    match basic_front_resource.display_center_display().0 {
7926                                        HorizontalAlign::Left => default_x_position,
7927                                        HorizontalAlign::Center => {
7928                                            default_x_position
7929                                                + basic_front_resource.display_size()[0] / 2.0
7930                                        }
7931                                        HorizontalAlign::Right => {
7932                                            default_x_position
7933                                                + basic_front_resource.display_size()[0]
7934                                        }
7935                                    };
7936                                let real_y_position =
7937                                    match basic_front_resource.display_center_display().1 {
7938                                        VerticalAlign::Top => default_y_position + modify_y,
7939                                        VerticalAlign::Center => {
7940                                            default_y_position
7941                                                + modify_y
7942                                                + basic_front_resource.display_size()[1] / 2.0
7943                                        }
7944                                        VerticalAlign::Bottom => {
7945                                            default_y_position
7946                                                + modify_y
7947                                                + basic_front_resource.display_size()[1]
7948                                        }
7949                                    };
7950                                basic_front_resource
7951                                    .modify_position(real_x_position, real_y_position);
7952                                resource_point_list.push((
7953                                    [real_x_position - left, real_y_position - top],
7954                                    [
7955                                        real_x_position
7956                                            + basic_front_resource.display_size()[0]
7957                                            + right,
7958                                        real_y_position
7959                                            + basic_front_resource.display_size()[1]
7960                                            + bottom,
7961                                    ],
7962                                    basic_front_resource.display_allow_scrolling(),
7963                                ));
7964                            }
7965                            PanelLayout::Horizontal(top, bottom, left, right, move_to_right) => {
7966                                let mut modify_x = 0_f32;
7967                                let [default_x_position, default_y_position] = match layout.0 {
7968                                    PanelLocation::Absolute(x, y) => [
7969                                        resource_panel.position[0] + x,
7970                                        resource_panel.position[1] + y,
7971                                    ],
7972                                    PanelLocation::Relative([x, y]) => [
7973                                        resource_panel.position[0]
7974                                            + (resource_panel.size[0] / x[1] as f32 * x[0] as f32),
7975                                        resource_panel.position[1]
7976                                            + (resource_panel.size[1] / y[1] as f32 * y[0] as f32),
7977                                    ],
7978                                };
7979                                let default_x_position =
7980                                    match basic_front_resource.display_center_display().0 {
7981                                        HorizontalAlign::Left => default_x_position,
7982                                        HorizontalAlign::Center => {
7983                                            default_x_position
7984                                                - basic_front_resource.display_size()[0] / 2.0
7985                                        }
7986                                        HorizontalAlign::Right => {
7987                                            default_x_position
7988                                                - basic_front_resource.display_size()[0]
7989                                        }
7990                                    };
7991                                let default_y_position =
7992                                    match basic_front_resource.display_center_display().1 {
7993                                        VerticalAlign::Top => default_y_position,
7994                                        VerticalAlign::Center => {
7995                                            default_y_position
7996                                                - basic_front_resource.display_size()[1] / 2.0
7997                                        }
7998                                        VerticalAlign::Bottom => {
7999                                            default_y_position
8000                                                - basic_front_resource.display_size()[1]
8001                                        }
8002                                    };
8003                                for point in &resource_point_list {
8004                                    if default_x_position - left < point.1[0]
8005                                        && default_y_position - top < point.1[1]
8006                                        && default_x_position
8007                                            + basic_front_resource.display_size()[0]
8008                                            + right
8009                                            > point.0[0]
8010                                        && default_y_position
8011                                            + basic_front_resource.display_size()[1]
8012                                            + bottom
8013                                            > point.0[1]
8014                                    {
8015                                        if move_to_right
8016                                            && point.1[0] - default_x_position + left > modify_x
8017                                        {
8018                                            modify_x = point.1[0] - default_x_position + left;
8019                                        } else if !move_to_right
8020                                            && point.0[0]
8021                                                - default_x_position
8022                                                - basic_front_resource.display_size()[0]
8023                                                - right
8024                                                < modify_x
8025                                        {
8026                                            modify_x = point.0[0]
8027                                                - default_x_position
8028                                                - basic_front_resource.display_size()[0]
8029                                                - right;
8030                                        };
8031                                    };
8032                                }
8033                                let real_x_position =
8034                                    match basic_front_resource.display_center_display().0 {
8035                                        HorizontalAlign::Left => default_x_position + modify_x,
8036                                        HorizontalAlign::Center => {
8037                                            default_x_position
8038                                                + modify_x
8039                                                + basic_front_resource.display_size()[0] / 2.0
8040                                        }
8041                                        HorizontalAlign::Right => {
8042                                            default_x_position
8043                                                + modify_x
8044                                                + basic_front_resource.display_size()[0]
8045                                        }
8046                                    };
8047                                let real_y_position =
8048                                    match basic_front_resource.display_center_display().1 {
8049                                        VerticalAlign::Top => default_y_position,
8050                                        VerticalAlign::Center => {
8051                                            default_y_position
8052                                                + basic_front_resource.display_size()[1] / 2.0
8053                                        }
8054                                        VerticalAlign::Bottom => {
8055                                            default_y_position
8056                                                + basic_front_resource.display_size()[1]
8057                                        }
8058                                    };
8059                                basic_front_resource
8060                                    .modify_position(real_x_position, real_y_position);
8061                                resource_point_list.push((
8062                                    [real_x_position - left, real_y_position - top],
8063                                    [
8064                                        real_x_position
8065                                            + basic_front_resource.display_size()[0]
8066                                            + right,
8067                                        real_y_position
8068                                            + basic_front_resource.display_size()[1]
8069                                            + bottom,
8070                                    ],
8071                                    basic_front_resource.display_allow_scrolling(),
8072                                ));
8073                            }
8074                            PanelLayout::None(top, bottom, left, right, influence_layout) => {
8075                                let [default_x_position, default_y_position] = match layout.0 {
8076                                    PanelLocation::Absolute(x, y) => [
8077                                        resource_panel.position[0] + x,
8078                                        resource_panel.position[1] + y,
8079                                    ],
8080                                    PanelLocation::Relative([x, y]) => [
8081                                        resource_panel.position[0]
8082                                            + (resource_panel.size[0] / x[1] as f32 * x[0] as f32),
8083                                        resource_panel.position[1]
8084                                            + (resource_panel.size[1] / y[1] as f32 * y[0] as f32),
8085                                    ],
8086                                };
8087                                basic_front_resource
8088                                    .modify_position(default_x_position, default_y_position);
8089                                if influence_layout {
8090                                    resource_point_list.push((
8091                                        [default_x_position - left, default_y_position - top],
8092                                        [
8093                                            default_x_position
8094                                                + basic_front_resource.display_size()[0]
8095                                                + right,
8096                                            default_y_position
8097                                                + basic_front_resource.display_size()[1]
8098                                                + bottom,
8099                                        ],
8100                                        basic_front_resource.display_allow_scrolling(),
8101                                    ));
8102                                };
8103                            }
8104                        };
8105                    };
8106                    *rcr = basic_front_resource;
8107                };
8108            };
8109        }
8110        let mut resource_length = [[None, None], [None, None]];
8111        for point in resource_point_list {
8112            resource_length = [
8113                [
8114                    if resource_length[0][0].is_none()
8115                        || resource_length[0][0].is_some()
8116                            && point.0[0] < resource_length[0][0].unwrap()
8117                            && point.2[0]
8118                    {
8119                        Some(point.0[0])
8120                    } else {
8121                        resource_length[0][0]
8122                    },
8123                    if resource_length[0][1].is_none()
8124                        || resource_length[0][1].is_some()
8125                            && point.0[1] < resource_length[0][1].unwrap()
8126                            && point.2[1]
8127                    {
8128                        Some(point.0[1])
8129                    } else {
8130                        resource_length[0][1]
8131                    },
8132                ],
8133                [
8134                    if resource_length[1][0].is_none()
8135                        || resource_length[1][0].is_some()
8136                            && point.1[0] < resource_length[1][0].unwrap()
8137                            && point.2[0]
8138                    {
8139                        Some(point.1[0])
8140                    } else {
8141                        resource_length[1][0]
8142                    },
8143                    if resource_length[1][1].is_none()
8144                        || resource_length[1][1].is_some()
8145                            && point.1[1] < resource_length[1][1].unwrap()
8146                            && point.2[1]
8147                    {
8148                        Some(point.1[1])
8149                    } else {
8150                        resource_length[1][1]
8151                    },
8152                ],
8153            ]
8154        }
8155        if let Some(horizontal_scroll_length_method) = resource_panel.scroll_length_method[0] {
8156            resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
8157                ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
8158                ScrollLengthMethod::AutoFit => {
8159                    if let [Some(min), Some(max)] = [resource_length[0][0], resource_length[1][0]] {
8160                        let width = max - min;
8161                        if width - resource_panel.size[0] > 0_f32 {
8162                            width - resource_panel.size[0]
8163                        } else {
8164                            0_f32
8165                        }
8166                    } else {
8167                        0_f32
8168                    }
8169                }
8170            };
8171            resource_panel.scroll_progress[0] =
8172                if resource_panel.scroll_progress[0] > resource_panel.scroll_length[0] {
8173                    resource_panel.scroll_length[0]
8174                } else {
8175                    resource_panel.scroll_progress[0]
8176                };
8177        };
8178        if let Some(vertical_scroll_length_method) = resource_panel.scroll_length_method[1] {
8179            resource_panel.scroll_length[1] = match vertical_scroll_length_method {
8180                ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
8181                ScrollLengthMethod::AutoFit => {
8182                    if let [Some(min), Some(max)] = [resource_length[0][1], resource_length[1][1]] {
8183                        let height = max - min;
8184                        if height - resource_panel.size[1] > 0_f32 {
8185                            height - resource_panel.size[1]
8186                        } else {
8187                            0_f32
8188                        }
8189                    } else {
8190                        0_f32
8191                    }
8192                }
8193            };
8194            resource_panel.scroll_progress[1] =
8195                if resource_panel.scroll_progress[1] > resource_panel.scroll_length[1] {
8196                    resource_panel.scroll_length[1]
8197                } else {
8198                    resource_panel.scroll_progress[1]
8199                };
8200        };
8201        resource_panel.last_frame_scroll_progress = resource_panel.scroll_progress;
8202        self.replace_resource(
8203            &resource_panel.name,
8204            "ResourcePanel",
8205            resource_panel.clone(),
8206        )
8207        .unwrap();
8208        Ok(())
8209    }
8210}