Skip to main content

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