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(f32),
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, Copy, PartialEq, PartialOrd)]
2074pub enum PanelLocation {
2075    /// 依照此资源到资源板左上角的距离定位。
2076    Absolute([f32; 2]),
2077    /// 依照网格式定位方法进行定位。
2078    Relative([[u32; 2]; 2]),
2079}
2080
2081/// 用于存储资源数据的结构体。
2082#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
2083pub struct PanelStorage {
2084    /// 资源Id。
2085    pub id: RustConstructorId,
2086    /// 存储资源是否忽略渲染层。
2087    pub ignore_render_layer: bool,
2088    /// 存储资源是否隐藏。
2089    pub hidden: bool,
2090    /// 存储资源原始尺寸。
2091    pub origin_size: [f32; 2],
2092}
2093
2094/// RC的资源板。
2095#[derive(Debug, Clone, PartialEq, PartialOrd)]
2096pub struct ResourcePanel {
2097    /// 是否可通过拖拽更改ResourcePanel尺寸。
2098    pub resizable: [bool; 4],
2099    /// 在资源底部显示方框。
2100    pub background: BackgroundType,
2101    /// 最小尺寸。
2102    pub min_size: [f32; 2],
2103    /// 最大尺寸(可选)。
2104    pub max_size: Option<[f32; 2]>,
2105    /// 允许拖动ResourcePanel。
2106    pub movable: [bool; 2],
2107    /// 滚动长度计算方法(不需要滚动留空即可)。
2108    pub scroll_length_method: [Option<ScrollLengthMethod>; 2],
2109    /// 滚动敏感度。
2110    pub scroll_sensitivity: f32,
2111    /// 是否使用平滑滚动。
2112    pub use_smooth_scroll_delta: bool,
2113    /// 滚动条显示方法。
2114    pub scroll_bar_display_method: ScrollBarDisplayMethod,
2115    /// 控制资源的排版方式。
2116    pub layout: PanelLayout,
2117    /// 是否隐藏ResourcePanel。
2118    pub hidden: bool,
2119    /// 反转滚动方向。
2120    pub reverse_scroll_direction: [bool; 2],
2121    /// 自动缩放资源。
2122    pub auto_shrink: [bool; 2],
2123    /// 滚动长度。
2124    pub scroll_length: [f32; 2],
2125    /// 滚动进度。
2126    pub scroll_progress: [f32; 2],
2127    /// 是否按下鼠标与按下后鼠标状态。
2128    pub last_frame_mouse_status: Option<([f32; 2], ClickAim, [f32; 2])>,
2129    /// 本帧是否滚动。
2130    pub scrolled: [bool; 2],
2131    /// 滚动条透明度。
2132    pub scroll_bar_alpha: [u8; 2],
2133    /// 资源原始信息储存列表。
2134    pub resource_storage: Vec<PanelStorage>,
2135    /// 标签。
2136    pub tags: Vec<[String; 2]>,
2137}
2138
2139impl RustConstructorResource for ResourcePanel {
2140    fn as_any(&self) -> &dyn Any {
2141        self
2142    }
2143
2144    fn as_any_mut(&mut self) -> &mut dyn Any {
2145        self
2146    }
2147
2148    fn display_display_info(&self) -> Option<DisplayInfo> {
2149        None
2150    }
2151
2152    fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
2153
2154    fn display_tags(&self) -> Vec<[String; 2]> {
2155        self.tags.clone()
2156    }
2157
2158    fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
2159        if replace {
2160            self.tags = tags.to_owned();
2161        } else {
2162            for tag in tags {
2163                if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2164                    self.tags.remove(index);
2165                };
2166            }
2167            self.tags.extend(tags.iter().cloned());
2168        };
2169    }
2170}
2171
2172impl Default for ResourcePanel {
2173    fn default() -> Self {
2174        Self {
2175            resizable: [true, true, true, true],
2176            background: BackgroundType::default(),
2177            min_size: [10_f32, 10_f32],
2178            max_size: None,
2179            movable: [true, true],
2180            scroll_length_method: [None, None],
2181            scroll_sensitivity: 0_f32,
2182            use_smooth_scroll_delta: true,
2183            scroll_bar_display_method: ScrollBarDisplayMethod::OnlyScroll(
2184                BackgroundType::default(),
2185                [4_f32, 2_f32],
2186                4_f32,
2187            ),
2188            layout: (PanelLayout {
2189                panel_margin: PanelMargin::Vertical([0_f32, 0_f32, 0_f32, 0_f32], false),
2190                panel_location: PanelLocation::Absolute([0_f32, 0_f32]),
2191            }),
2192            hidden: false,
2193            reverse_scroll_direction: [false, false],
2194            auto_shrink: [true, false],
2195            scroll_length: [0_f32, 0_f32],
2196            scroll_progress: [0_f32, 0_f32],
2197            last_frame_mouse_status: None,
2198            scrolled: [false, false],
2199            scroll_bar_alpha: [0, 0],
2200            resource_storage: Vec::new(),
2201            tags: Vec::new(),
2202        }
2203    }
2204}
2205
2206impl ResourcePanel {
2207    #[inline]
2208    pub fn resizable(mut self, top: bool, bottom: bool, left: bool, right: bool) -> Self {
2209        self.resizable = [top, bottom, left, right];
2210        self
2211    }
2212
2213    #[inline]
2214    pub fn background(mut self, background: &BackgroundType) -> Self {
2215        self.background = background.clone();
2216        self
2217    }
2218
2219    #[inline]
2220    pub fn min_size(mut self, width: f32, height: f32) -> Self {
2221        self.min_size = [width, height];
2222        self
2223    }
2224
2225    #[inline]
2226    pub fn max_size(mut self, max_size: Option<[f32; 2]>) -> Self {
2227        self.max_size = max_size;
2228        self
2229    }
2230
2231    #[inline]
2232    pub fn movable(mut self, horizontal: bool, vertical: bool) -> Self {
2233        self.movable = [horizontal, vertical];
2234        self
2235    }
2236
2237    #[inline]
2238    pub fn scroll_length_method(
2239        mut self,
2240        horizontal: Option<ScrollLengthMethod>,
2241        vertical: Option<ScrollLengthMethod>,
2242    ) -> Self {
2243        self.scroll_length_method = [horizontal, vertical];
2244        self
2245    }
2246
2247    #[inline]
2248    pub fn scroll_sensitivity(mut self, scroll_sensitivity: f32) -> Self {
2249        self.scroll_sensitivity = scroll_sensitivity;
2250        self
2251    }
2252
2253    #[inline]
2254    pub fn use_smooth_scroll_delta(mut self, use_smooth_scroll_delta: bool) -> Self {
2255        self.use_smooth_scroll_delta = use_smooth_scroll_delta;
2256        self
2257    }
2258
2259    #[inline]
2260    pub fn scroll_bar_display_method(
2261        mut self,
2262        scroll_bar_display_method: ScrollBarDisplayMethod,
2263    ) -> Self {
2264        self.scroll_bar_display_method = scroll_bar_display_method;
2265        self
2266    }
2267
2268    #[inline]
2269    pub fn layout(mut self, layout: PanelLayout) -> Self {
2270        self.layout = layout;
2271        self
2272    }
2273
2274    #[inline]
2275    pub fn hidden(mut self, hidden: bool) -> Self {
2276        self.hidden = hidden;
2277        self
2278    }
2279
2280    #[inline]
2281    pub fn reverse_scroll_direction(mut self, horizontal: bool, vertical: bool) -> Self {
2282        self.reverse_scroll_direction = [horizontal, vertical];
2283        self
2284    }
2285
2286    #[inline]
2287    pub fn auto_shrink(mut self, horizontal: bool, vertical: bool) -> Self {
2288        self.auto_shrink = [horizontal, vertical];
2289        self
2290    }
2291
2292    #[inline]
2293    pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
2294        if replace {
2295            self.tags = tags.to_owned();
2296        } else {
2297            for tag in tags {
2298                if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2299                    self.tags.remove(index);
2300                };
2301            }
2302            self.tags.extend(tags.iter().cloned());
2303        };
2304        self
2305    }
2306}
2307
2308/// Switch在不同状态下的的外观配置。
2309#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
2310pub struct SwitchAppearanceConfig {
2311    /// Background的配置项。
2312    pub background_config: BackgroundType,
2313    /// Text的配置项。
2314    pub text_config: TextConfig,
2315    /// 提示Text的配置项。
2316    pub hint_text_config: TextConfig,
2317}
2318
2319/// Switch的可点击方法配置。
2320#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2321pub struct SwitchClickConfig {
2322    /// 点击方法。
2323    pub click_method: PointerButton,
2324    /// 点击后是否改变Switch状态。
2325    pub action: bool,
2326}
2327
2328/// 用于Switch资源判定的一些字段集合。
2329#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2330pub struct SwitchData {
2331    /// 是否点击切换状态。
2332    pub switched: bool,
2333    /// 点击的方法。
2334    pub last_frame_clicked: Option<usize>,
2335    /// Switch状态。
2336    pub state: u32,
2337}
2338
2339/// RC的开关资源。
2340#[derive(Debug, Clone, PartialEq)]
2341pub struct Switch {
2342    /// 外观(包括各类资源配置项,数量为开启的内容数量*Switch状态总数)。
2343    pub appearance: Vec<SwitchAppearanceConfig>,
2344    /// Background显示内容类型。
2345    pub background_type: BackgroundType,
2346    /// Text显示配置。
2347    pub text_config: TextConfig,
2348    /// 提示Text显示配置。
2349    pub hint_text_config: TextConfig,
2350    /// 是否启用鼠标悬浮和点击时的显示内容。
2351    pub enable_animation: [bool; 2],
2352    /// Switch状态总数。
2353    pub state_amount: u32,
2354    /// 可以用于点击Switch的方法。
2355    pub click_method: Vec<SwitchClickConfig>,
2356    /// 是否启用Switch(不启用会显示出填充资源,但无法交互)。
2357    pub enable: bool,
2358    /// Switch当前状态。
2359    pub state: u32,
2360    /// 上一帧是否有鼠标悬停。
2361    pub last_frame_hovered: bool,
2362    /// 上一帧是否被鼠标点击。
2363    pub last_frame_clicked: Option<usize>,
2364    /// 是否切换了Switch状态。
2365    pub switched: bool,
2366    /// 是否让创建的资源使用Switch的标签。
2367    pub use_switch_tags: bool,
2368    /// 标签。
2369    pub tags: Vec<[String; 2]>,
2370}
2371
2372impl RustConstructorResource for Switch {
2373    fn as_any(&self) -> &dyn Any {
2374        self
2375    }
2376
2377    fn as_any_mut(&mut self) -> &mut dyn Any {
2378        self
2379    }
2380
2381    fn display_display_info(&self) -> Option<DisplayInfo> {
2382        None
2383    }
2384
2385    fn modify_display_info(&mut self, _display_info: DisplayInfo) {}
2386
2387    fn display_tags(&self) -> Vec<[String; 2]> {
2388        self.tags.clone()
2389    }
2390
2391    fn modify_tags(&mut self, tags: &[[String; 2]], replace: bool) {
2392        if replace {
2393            self.tags = tags.to_owned();
2394        } else {
2395            for tag in tags {
2396                if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2397                    self.tags.remove(index);
2398                };
2399            }
2400            self.tags.extend(tags.iter().cloned());
2401        };
2402    }
2403}
2404
2405impl Default for Switch {
2406    fn default() -> Self {
2407        Self {
2408            appearance: vec![],
2409            background_type: BackgroundType::default(),
2410            text_config: TextConfig::default(),
2411            hint_text_config: TextConfig::default(),
2412            enable_animation: [false, false],
2413            state_amount: 0,
2414            click_method: vec![],
2415            enable: true,
2416            state: 0,
2417            last_frame_hovered: false,
2418            last_frame_clicked: None,
2419            switched: false,
2420            use_switch_tags: false,
2421            tags: Vec::new(),
2422        }
2423    }
2424}
2425
2426impl Switch {
2427    #[inline]
2428    pub fn appearance(mut self, appearance: &[SwitchAppearanceConfig]) -> Self {
2429        self.appearance = appearance.to_owned();
2430        self
2431    }
2432
2433    #[inline]
2434    pub fn background_type(mut self, background_type: &BackgroundType) -> Self {
2435        self.background_type = background_type.clone();
2436        self
2437    }
2438
2439    #[inline]
2440    pub fn text_config(mut self, text_config: &TextConfig) -> Self {
2441        self.text_config = text_config.clone();
2442        self
2443    }
2444
2445    #[inline]
2446    pub fn hint_text_config(mut self, hint_text_config: &TextConfig) -> Self {
2447        self.hint_text_config = hint_text_config.clone();
2448        self
2449    }
2450
2451    #[inline]
2452    pub fn enable_animation(mut self, enable_hover: bool, enable_click: bool) -> Self {
2453        self.enable_animation = [enable_hover, enable_click];
2454        self
2455    }
2456
2457    #[inline]
2458    pub fn state_amount(mut self, state_amount: u32) -> Self {
2459        self.state_amount = state_amount;
2460        self
2461    }
2462
2463    #[inline]
2464    pub fn click_method(mut self, click_method: Vec<SwitchClickConfig>) -> Self {
2465        self.click_method = click_method;
2466        self
2467    }
2468
2469    #[inline]
2470    pub fn enable(mut self, enable: bool) -> Self {
2471        self.enable = enable;
2472        self
2473    }
2474
2475    #[inline]
2476    pub fn use_switch_tags(mut self, use_switch_tags: bool) -> Self {
2477        self.use_switch_tags = use_switch_tags;
2478        self
2479    }
2480
2481    #[inline]
2482    pub fn tags(mut self, tags: &[[String; 2]], replace: bool) -> Self {
2483        if replace {
2484            self.tags = tags.to_owned();
2485        } else {
2486            for tag in tags {
2487                if let Some(index) = self.tags.iter().position(|x| x[0] == tag[0]) {
2488                    self.tags.remove(index);
2489                };
2490            }
2491            self.tags.extend(tags.iter().cloned());
2492        };
2493        self
2494    }
2495}
2496
2497/// RC资源最基本的错误处理。
2498#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2499pub struct RustConstructorError {
2500    /// 错误类型。
2501    pub error_id: String,
2502    /// 对此错误的描述。
2503    pub description: String,
2504}
2505
2506impl Display for RustConstructorError {
2507    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
2508        Debug::fmt(self, f)
2509    }
2510}
2511
2512impl Error for RustConstructorError {}
2513
2514/// 水平对齐方法。
2515#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2516pub enum HorizontalAlign {
2517    /// 左对齐。
2518    #[default]
2519    Left,
2520    /// 居中对齐。
2521    Center,
2522    /// 右对齐。
2523    Right,
2524}
2525
2526/// 垂直对齐方法。
2527#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2528pub enum VerticalAlign {
2529    /// 顶部对齐。
2530    #[default]
2531    Top,
2532    /// 居中对齐。
2533    Center,
2534    /// 底部对齐。
2535    Bottom,
2536}
2537
2538/// 渲染配置。
2539#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
2540pub enum RenderConfig {
2541    Line(f32, [u8; 4]),
2542    Rect([u8; 4], [u8; 4], [u8; 4], f32, BorderKind),
2543}
2544
2545/// 显示信息。
2546#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2547pub struct DisplayInfo {
2548    /// 启用资源。
2549    pub enable: bool,
2550    /// 隐藏资源。
2551    pub hidden: bool,
2552    /// 忽略渲染层级。
2553    pub ignore_render_layer: bool,
2554}
2555
2556/// 定位请求跳过渲染队列的资源的方法。
2557#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2558pub enum RequestMethod {
2559    /// 使用资源的唯一标识符。
2560    Id(RustConstructorId),
2561    /// 使用资源的引用者。
2562    Citer(RustConstructorId),
2563}
2564
2565/// 请求跳过渲染队列的类型。
2566#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2567pub enum RequestType {
2568    /// 直接置于顶层。
2569    Top,
2570    /// 上移指定层级。
2571    Up(u32),
2572}
2573
2574/// 控制显示活跃资源列表的方法。
2575#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2576pub enum ActiveListInfoMethod {
2577    /// 详细显示,包含资源本身与其id(可以选择是否格式化显示)。
2578    Detailed(bool),
2579    /// 简单显示,仅包含资源id。
2580    #[default]
2581    Simple,
2582}
2583
2584/// 程序主体。
2585#[derive(Debug)]
2586pub struct App {
2587    /// RC资源。
2588    pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
2589    /// RC资源刷新率。
2590    pub tick_interval: f32,
2591    /// 当前页面。
2592    pub current_page: String,
2593    /// 计时器。
2594    pub timer: Timer,
2595    /// 帧时间。
2596    pub frame_times: Vec<f32>,
2597    /// 上一帧时间。
2598    pub last_frame_time: Option<f32>,
2599    /// 标记哪些资源属于基本前端资源,此列表不应以任何形式进行修改。
2600    pub basic_front_resource_list: Vec<String>,
2601    /// 标记渲染物件的层级和位置。
2602    pub render_layer: Vec<(RustConstructorId, [[f32; 2]; 2], bool)>,
2603    /// 活跃资源列表。
2604    pub active_list: Vec<RustConstructorId>,
2605    /// 渲染队列。
2606    pub render_list: Vec<RustConstructorId>,
2607}
2608
2609impl Default for App {
2610    fn default() -> Self {
2611        App {
2612            rust_constructor_resource: Vec::new(),
2613            tick_interval: 0.05,
2614            current_page: String::new(),
2615            timer: Timer::default(),
2616            frame_times: Vec::new(),
2617            last_frame_time: None,
2618            basic_front_resource_list: vec![
2619                String::from("rust_constructor::Image"),
2620                String::from("rust_constructor::Text"),
2621                String::from("rust_constructor::CustomRect"),
2622            ],
2623            render_layer: Vec::new(),
2624            active_list: Vec::new(),
2625            render_list: Vec::new(),
2626        }
2627    }
2628}
2629
2630impl App {
2631    #[inline]
2632    pub fn tick_interval(mut self, tick_interval: f32) -> Self {
2633        self.tick_interval = tick_interval;
2634        self
2635    }
2636
2637    #[inline]
2638    pub fn current_page(mut self, current_page: &str) -> Self {
2639        self.current_page = current_page.to_string();
2640        self
2641    }
2642
2643    /// 从指定列表中获取标签。
2644    pub fn get_tag(&self, tag_name: &str, target: &[[String; 2]]) -> Option<(usize, String)> {
2645        target
2646            .iter()
2647            .position(|x| x[0] == tag_name)
2648            .map(|index| (index, target[index][1].clone()))
2649    }
2650
2651    /// 一次性绘制所有资源,会丢弃所有返回值,不建议使用。
2652    pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
2653        for i in 0..self.render_list.len() {
2654            #[allow(warnings)]
2655            self.draw_resource_by_index(ui, ctx, i);
2656        }
2657    }
2658
2659    /// 根据索引值绘制资源,建议使用for循环搭配。
2660    pub fn draw_resource_by_index(
2661        &mut self,
2662        ui: &mut Ui,
2663        ctx: &Context,
2664        index: usize,
2665    ) -> Result<(), RustConstructorError> {
2666        if let Some(render_resource) = self.render_list.clone().get(index) {
2667            match &*render_resource.discern_type {
2668                "rust_constructor::Image" => {
2669                    let image = self
2670                        .get_resource::<Image>(&render_resource.name, "rust_constructor::Image")?;
2671                    if image.display_info.enable {
2672                        let mut image = image.clone();
2673                        if image.cite_texture != image.last_frame_cite_texture {
2674                            let image_texture = self.get_resource::<ImageTexture>(
2675                                &image.cite_texture,
2676                                "rust_constructor::ImageTexture",
2677                            )?;
2678                            image.texture = image_texture.texture.clone();
2679                        };
2680                        [image.position, image.size] = self.position_size_processor(
2681                            image.basic_front_resource_config.position_size_config,
2682                            ctx,
2683                        );
2684                        if !image.display_info.hidden {
2685                            if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
2686                                let [min, size] = self.position_size_processor(clip_rect, ctx);
2687                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2688                            };
2689                            if let Some(texture) = &image.texture {
2690                                let rect = Rect::from_min_size(
2691                                    Pos2::new(image.position[0], image.position[1]),
2692                                    Vec2::new(image.size[0], image.size[1]),
2693                                );
2694
2695                                // 直接绘制图片
2696                                egui::Image::new(ImageSource::Texture((&texture.0).into()))
2697                                    .tint(Color32::from_rgba_unmultiplied(
2698                                        image.overlay_color[0],
2699                                        image.overlay_color[1],
2700                                        image.overlay_color[2],
2701                                        // 将图片透明度与覆盖颜色透明度相乘
2702                                        (image.alpha as f32 * image.overlay_alpha as f32 / 255_f32)
2703                                            as u8,
2704                                    ))
2705                                    .bg_fill(Color32::from_rgba_unmultiplied(
2706                                        image.background_color[0],
2707                                        image.background_color[1],
2708                                        image.background_color[2],
2709                                        (image.alpha as f32 * image.background_alpha as f32
2710                                            / 255_f32)
2711                                            as u8,
2712                                    ))
2713                                    .rotate(
2714                                        image.rotate_angle,
2715                                        [
2716                                            image.rotate_center[0] / image.size[0],
2717                                            image.rotate_center[1] / image.size[1],
2718                                        ]
2719                                        .into(),
2720                                    )
2721                                    .paint_at(ui, rect)
2722                            };
2723                            if image.basic_front_resource_config.clip_rect.is_some() {
2724                                ui.set_clip_rect(Rect::from_min_size(
2725                                    [0_f32, 0_f32].into(),
2726                                    [ctx.available_rect().width(), ctx.available_rect().height()]
2727                                        .into(),
2728                                ));
2729                            };
2730                        };
2731                        image.last_frame_cite_texture = image.cite_texture.clone();
2732                        self.replace_resource(&render_resource.name, image)?;
2733                    };
2734                }
2735                "rust_constructor::Text" => {
2736                    let text =
2737                        self.get_resource::<Text>(&render_resource.name, "rust_constructor::Text")?;
2738                    if text.display_info.enable {
2739                        let mut text = text.clone();
2740                        [_, text.truncate_size] = self.position_size_processor(
2741                            text.basic_front_resource_config.position_size_config,
2742                            ctx,
2743                        );
2744                        let display_content = if text.content.is_empty()
2745                            || text
2746                                .basic_front_resource_config
2747                                .position_size_config
2748                                .origin_size
2749                                .contains(&0_f32)
2750                        {
2751                            "".to_string()
2752                        } else {
2753                            let original_galley = ui.fonts_mut(|f| {
2754                                f.layout(
2755                                    text.content.to_string(),
2756                                    FontId::proportional(text.font_size),
2757                                    Color32::default(),
2758                                    text.truncate_size[0],
2759                                )
2760                            });
2761
2762                            let mut truncated = text.content.to_string();
2763                            let mut ellipsis = "";
2764                            if original_galley.size().y > text.truncate_size[1] {
2765                                // 如果超出,逐步缩短文本直到加上省略号后能放下
2766                                ellipsis = "...";
2767
2768                                while !truncated.is_empty() {
2769                                    let test_text = format!("{}{}", truncated, ellipsis);
2770                                    let test_galley = ui.fonts_mut(|f| {
2771                                        f.layout(
2772                                            test_text,
2773                                            FontId::proportional(text.font_size),
2774                                            Color32::default(),
2775                                            text.truncate_size[0],
2776                                        )
2777                                    });
2778
2779                                    if test_galley.size().y <= text.truncate_size[1] {
2780                                        break;
2781                                    }
2782
2783                                    // 移除最后一个字符
2784                                    truncated.pop();
2785                                }
2786                            };
2787                            format!("{}{}", truncated, ellipsis)
2788                        };
2789                        // 计算文本大小
2790                        let galley: Arc<Galley> = ui.fonts_mut(|f| {
2791                            f.layout(
2792                                display_content.to_string(),
2793                                if !text.font.is_empty() {
2794                                    if self
2795                                        .check_resource_exists(&text.font, "rust_constructor::Font")
2796                                        .is_none()
2797                                    {
2798                                        FontId::proportional(text.font_size)
2799                                    } else {
2800                                        FontId::new(
2801                                            text.font_size,
2802                                            FontFamily::Name(text.font.clone().into()),
2803                                        )
2804                                    }
2805                                } else {
2806                                    FontId::proportional(text.font_size)
2807                                },
2808                                Color32::from_rgba_unmultiplied(
2809                                    text.color[0],
2810                                    text.color[1],
2811                                    text.color[2],
2812                                    text.alpha,
2813                                ),
2814                                text.truncate_size[0],
2815                            )
2816                        });
2817                        text.size = [
2818                            if text.auto_fit[0] {
2819                                galley.size().x
2820                            } else {
2821                                text.truncate_size[0]
2822                            },
2823                            if text.auto_fit[1] {
2824                                galley.size().y
2825                            } else {
2826                                text.truncate_size[1]
2827                            },
2828                        ];
2829                        text.actual_size = [galley.size().x, galley.size().y];
2830                        [text.position, _] = self.position_size_processor(
2831                            text.basic_front_resource_config
2832                                .position_size_config
2833                                .x_size_grid(0_f32, 0_f32)
2834                                .y_size_grid(0_f32, 0_f32)
2835                                .origin_size(text.size[0], text.size[1]),
2836                            ctx,
2837                        );
2838                        // 查找超链接索引值
2839                        if text.last_frame_content != display_content {
2840                            text.hyperlink_index.clear();
2841
2842                            // 创建字节索引到字符索引的映射
2843                            let byte_to_char_map: std::collections::HashMap<usize, usize> =
2844                                display_content
2845                                    .char_indices()
2846                                    .enumerate()
2847                                    .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2848                                    .collect();
2849
2850                            for (hyperlink_text, method) in &text.hyperlink_text {
2851                                let matches: Vec<(usize, &str)> =
2852                                    display_content.match_indices(hyperlink_text).collect();
2853                                let text_char_count = hyperlink_text.chars().count();
2854
2855                                if let HyperlinkSelectMethod::All(url) = method {
2856                                    for (byte_index, _) in matches {
2857                                        if let Some(&start_char_index) =
2858                                            byte_to_char_map.get(&byte_index)
2859                                        {
2860                                            text.hyperlink_index.push((
2861                                                start_char_index,
2862                                                start_char_index + text_char_count,
2863                                                url.clone(),
2864                                            ));
2865                                        };
2866                                    }
2867                                } else if let HyperlinkSelectMethod::Segment(list) = method {
2868                                    for (index, url) in list {
2869                                        if *index >= matches.len() {
2870                                            continue;
2871                                        };
2872                                        let (byte_index, _) = matches[*index];
2873                                        if let Some(&start_char_index) =
2874                                            byte_to_char_map.get(&byte_index)
2875                                        {
2876                                            text.hyperlink_index.push((
2877                                                start_char_index,
2878                                                start_char_index + text_char_count,
2879                                                url.clone(),
2880                                            ));
2881                                        };
2882                                    }
2883                                };
2884                            }
2885                        };
2886                        if !text.display_info.hidden {
2887                            // 使用绝对定位放置文本
2888                            let rect =
2889                                Rect::from_min_size(text.position.into(), text.actual_size.into());
2890                            // 绘制背景颜色
2891                            ui.painter().rect_filled(
2892                                rect,
2893                                text.background_rounding,
2894                                Color32::from_rgba_unmultiplied(
2895                                    text.background_color[0],
2896                                    text.background_color[1],
2897                                    text.background_color[2],
2898                                    text.background_alpha,
2899                                ),
2900                            );
2901
2902                            if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2903                                let [min, size] = self.position_size_processor(clip_rect, ctx);
2904                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2905                            };
2906
2907                            // 绘制文本
2908                            ui.painter().galley(
2909                                text.position.into(),
2910                                galley.clone(),
2911                                Color32::from_rgba_unmultiplied(
2912                                    text.color[0],
2913                                    text.color[1],
2914                                    text.color[2],
2915                                    text.alpha,
2916                                ),
2917                            );
2918
2919                            // 绘制超链接
2920                            for (start, end, _) in &text.hyperlink_index {
2921                                // 获取超链接文本的范围
2922                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2923                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2924
2925                                let start_pos = start_cursor.left_top();
2926                                let end_pos = end_cursor.right_top();
2927                                // 绘制超链接下划线
2928                                // 检查超链接是否跨行
2929                                if start_cursor.min.y == end_cursor.min.y {
2930                                    // 单行超链接
2931                                    let underline_y = text.position[1]
2932                                        + start_pos.y
2933                                        + galley.rows.first().map_or(14.0, |row| row.height())
2934                                        - 2.0;
2935
2936                                    // 绘制下划线
2937                                    let color = Color32::from_rgba_unmultiplied(
2938                                        text.color[0],
2939                                        text.color[1],
2940                                        text.color[2],
2941                                        text.alpha,
2942                                    );
2943
2944                                    ui.painter().line_segment(
2945                                        [
2946                                            Pos2::new(text.position[0] + start_pos.x, underline_y),
2947                                            Pos2::new(text.position[0] + end_pos.x, underline_y),
2948                                        ],
2949                                        Stroke::new(text.font_size / 10_f32, color),
2950                                    );
2951                                } else {
2952                                    // 多行超链接
2953                                    let row_height =
2954                                        galley.rows.first().map_or(14.0, |row| row.height()); // 默认行高14.0
2955
2956                                    // 计算起始行和结束行的索引
2957                                    let start_row = (start_pos.y / row_height).round() as usize;
2958                                    let end_row = (end_pos.y / row_height).round() as usize;
2959
2960                                    for row in start_row..=end_row {
2961                                        let row_y =
2962                                            text.position[1] + row as f32 * row_height + row_height
2963                                                - 2.0; // 行底部稍微上移一点绘制下划线
2964
2965                                        // 获取当前行的矩形范围
2966                                        if let Some(current_row) = galley.rows.get(row) {
2967                                            let row_rect = current_row.rect();
2968
2969                                            let color = Color32::from_rgba_unmultiplied(
2970                                                text.color[0],
2971                                                text.color[1],
2972                                                text.color[2],
2973                                                text.alpha,
2974                                            );
2975
2976                                            if row == start_row {
2977                                                // 第一行从文本开始位置到行尾
2978                                                ui.painter().line_segment(
2979                                                    [
2980                                                        Pos2::new(
2981                                                            text.position[0] + start_pos.x,
2982                                                            row_y,
2983                                                        ),
2984                                                        Pos2::new(
2985                                                            text.position[0] + row_rect.max.x,
2986                                                            row_y,
2987                                                        ),
2988                                                    ],
2989                                                    Stroke::new(text.font_size / 10_f32, color),
2990                                                );
2991                                            } else if row == end_row {
2992                                                // 最后一行从行首到文本结束位置
2993                                                ui.painter().line_segment(
2994                                                    [
2995                                                        Pos2::new(
2996                                                            text.position[0] + row_rect.min.x,
2997                                                            row_y,
2998                                                        ),
2999                                                        Pos2::new(
3000                                                            text.position[0] + end_pos.x,
3001                                                            row_y,
3002                                                        ),
3003                                                    ],
3004                                                    Stroke::new(text.font_size / 10_f32, color),
3005                                                );
3006                                            } else {
3007                                                // 中间整行下划线
3008                                                ui.painter().line_segment(
3009                                                    [
3010                                                        Pos2::new(
3011                                                            text.position[0] + row_rect.min.x,
3012                                                            row_y,
3013                                                        ),
3014                                                        Pos2::new(
3015                                                            text.position[0] + row_rect.max.x,
3016                                                            row_y,
3017                                                        ),
3018                                                    ],
3019                                                    Stroke::new(text.font_size / 10_f32, color),
3020                                                );
3021                                            };
3022                                        };
3023                                    }
3024                                };
3025                            }
3026
3027                            if text.selectable {
3028                                // 处理选择逻辑
3029                                let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
3030                                    let relative_pos = pointer_pos - text.position.into();
3031                                    let cursor = galley.cursor_from_pos(relative_pos);
3032                                    cursor.index
3033                                };
3034
3035                                let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
3036                                let rect = Rect::from_min_size(
3037                                    text.position.into(),
3038                                    text.actual_size.into(),
3039                                );
3040                                let detect_result = ui.interact(
3041                                    rect,
3042                                    Id::new(&render_resource.name),
3043                                    Sense::click_and_drag(),
3044                                );
3045
3046                                if !detect_result.clicked()
3047                                    && (fullscreen_detect_result.any_click()
3048                                        || fullscreen_detect_result.any_pressed())
3049                                {
3050                                    text.selection = None;
3051                                };
3052
3053                                if let Some(index) = self.get_render_layer_resource(
3054                                    &render_resource.name,
3055                                    "rust_constructor::Text",
3056                                ) && let Some(mouse_pos) =
3057                                    fullscreen_detect_result.interact_pos()
3058                                    && self.resource_get_focus(index, mouse_pos.into())
3059                                    && (detect_result.clicked() || detect_result.drag_started())
3060                                {
3061                                    let cursor = cursor_at_pointer(mouse_pos.to_vec2());
3062                                    text.selection = Some((cursor, cursor));
3063                                };
3064
3065                                if detect_result.dragged()
3066                                    && text.selection.is_some()
3067                                    && let Some(pointer_pos) =
3068                                        ui.input(|i| i.pointer.interact_pos())
3069                                {
3070                                    let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3071                                    if let Some((start, _)) = text.selection {
3072                                        text.selection = Some((start, cursor));
3073                                    };
3074                                };
3075
3076                                if text.selection.is_some()
3077                                    && ui.input(|input| {
3078                                        input.key_released(Key::A) && input.modifiers.command
3079                                    })
3080                                {
3081                                    text.selection = Some((0, display_content.chars().count()));
3082                                };
3083
3084                                // 处理复制操作
3085                                let copy_triggered = ui.input(|input| {
3086                                    let c_released = input.key_released(Key::C);
3087                                    let cmd_pressed = input.modifiers.command;
3088                                    c_released && cmd_pressed
3089                                });
3090                                if copy_triggered && let Some((start, end)) = text.selection {
3091                                    let (start, end) = (start.min(end), start.max(end));
3092                                    let chars: Vec<char> = display_content.chars().collect();
3093                                    if start <= chars.len() && end <= chars.len() && start < end {
3094                                        let selected_text: String =
3095                                            chars[start..end].iter().collect();
3096                                        ui.ctx().copy_text(selected_text);
3097                                    };
3098                                };
3099
3100                                // 绘制选择区域背景
3101                                if let Some((start, end)) = text.selection {
3102                                    let (start, end) = (start.min(end), start.max(end));
3103                                    if start != end {
3104                                        // 获取选择区域的范围
3105                                        let start_cursor =
3106                                            galley.pos_from_cursor(CCursor::new(start));
3107                                        let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3108
3109                                        let start_pos = start_cursor.left_top();
3110                                        let end_pos = end_cursor.right_top();
3111                                        // 选择框绘制
3112                                        if start_pos.y == end_pos.y {
3113                                            // 单行选择
3114                                            let rows = &galley.rows;
3115                                            let row_height = if !rows.is_empty() {
3116                                                // 获取实际行的高度
3117                                                if let Some(row) = rows.first() {
3118                                                    row.height()
3119                                                } else {
3120                                                    text.actual_size[1]
3121                                                        / display_content.lines().count() as f32
3122                                                }
3123                                            } else {
3124                                                text.actual_size[1]
3125                                                    / display_content.lines().count() as f32
3126                                            };
3127
3128                                            let selection_rect = Rect::from_min_max(
3129                                                Pos2::new(
3130                                                    text.position[0] + start_pos.x,
3131                                                    text.position[1] + start_pos.y,
3132                                                ),
3133                                                Pos2::new(
3134                                                    text.position[0] + end_pos.x,
3135                                                    text.position[1] + start_pos.y + row_height,
3136                                                ),
3137                                            );
3138                                            ui.painter().rect_filled(
3139                                                selection_rect,
3140                                                0.0,
3141                                                Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3142                                            );
3143                                        } else {
3144                                            // 多行选择 - 为每行创建精确的矩形
3145                                            let rows = &galley.rows;
3146                                            let row_height = if !rows.is_empty() {
3147                                                rows[0].height()
3148                                            } else {
3149                                                text.actual_size[1]
3150                                                    / display_content.lines().count() as f32
3151                                            };
3152
3153                                            // 计算选择的上下边界
3154                                            let selection_top =
3155                                                text.position[1] + start_pos.y.min(end_pos.y);
3156                                            let selection_bottom =
3157                                                text.position[1] + start_pos.y.max(end_pos.y);
3158
3159                                            // 确定起始行和结束行的索引
3160                                            let start_row_index =
3161                                                (start_pos.y / row_height).floor() as usize;
3162                                            let end_row_index =
3163                                                (end_pos.y / row_height).floor() as usize;
3164                                            let (first_row_index, last_row_index) =
3165                                                if start_row_index <= end_row_index {
3166                                                    (start_row_index, end_row_index)
3167                                                } else {
3168                                                    (end_row_index, start_row_index)
3169                                                };
3170
3171                                            for (i, row) in rows.iter().enumerate() {
3172                                                let row_y =
3173                                                    text.position[1] + row_height * i as f32;
3174                                                let row_bottom = row_y + row_height;
3175                                                // 检查当前行是否与选择区域相交
3176                                                if row_bottom > selection_top
3177                                                    && row_y <= selection_bottom
3178                                                {
3179                                                    let left = if i == first_row_index {
3180                                                        // 首行 - 从选择开始位置开始
3181                                                        text.position[0] + start_pos.x
3182                                                    } else {
3183                                                        // 非首行 - 从行首开始
3184                                                        text.position[0] + row.rect().min.x
3185                                                    };
3186
3187                                                    let right = if i == last_row_index {
3188                                                        // 尾行 - 到选择结束位置结束
3189                                                        text.position[0] + end_pos.x
3190                                                    } else {
3191                                                        // 非尾行 - 到行尾结束
3192                                                        text.position[0] + row.rect().max.x
3193                                                    };
3194
3195                                                    let selection_rect = Rect::from_min_max(
3196                                                        Pos2::new(left, row_y),
3197                                                        Pos2::new(right, row_bottom),
3198                                                    );
3199
3200                                                    // 确保矩形有效
3201                                                    if selection_rect.width() > 0.0
3202                                                        && selection_rect.height() > 0.0
3203                                                    {
3204                                                        ui.painter().rect_filled(
3205                                                            selection_rect,
3206                                                            0.0,
3207                                                            Color32::from_rgba_unmultiplied(
3208                                                                0, 120, 255, 100,
3209                                                            ),
3210                                                        );
3211                                                    };
3212                                                };
3213                                            }
3214                                        };
3215                                    };
3216                                };
3217                            };
3218
3219                            // 处理超链接操作
3220                            for (start, end, url) in &text.hyperlink_index {
3221                                // 获取超链接文本的范围
3222                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3223                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3224
3225                                let start_pos = start_cursor.left_top();
3226                                let end_pos = end_cursor.right_top();
3227
3228                                let row_height =
3229                                    galley.rows.first().map_or(14.0, |row| row.height());
3230
3231                                // 为超链接创建交互响应对象
3232                                let link_responses = if start_cursor.min.y == end_cursor.min.y {
3233                                    // 单行超链接
3234                                    let link_rect = Rect::from_min_max(
3235                                        Pos2::new(
3236                                            text.position[0] + start_pos.x,
3237                                            text.position[1] + start_pos.y,
3238                                        ),
3239                                        Pos2::new(
3240                                            text.position[0] + end_pos.x,
3241                                            text.position[1] + start_pos.y + row_height,
3242                                        ),
3243                                    );
3244                                    vec![ui.interact(
3245                                        link_rect,
3246                                        egui::Id::new(format!(
3247                                            "link_{}_{}_{}",
3248                                            render_resource.name, start, end
3249                                        )),
3250                                        egui::Sense::click(),
3251                                    )]
3252                                } else {
3253                                    // 多行超链接
3254                                    let start_row = (start_pos.y / row_height).round() as usize;
3255                                    let end_row = (end_pos.y / row_height).round() as usize;
3256                                    let mut responses = Vec::new();
3257
3258                                    for row in start_row..=end_row {
3259                                        if let Some(current_row) = galley.rows.get(row) {
3260                                            let row_rect = current_row.rect();
3261                                            let row_y = text.position[1] + row as f32 * row_height;
3262
3263                                            let link_rect = if row == start_row {
3264                                                // 第一行从文本开始位置到行尾
3265                                                Rect::from_min_max(
3266                                                    Pos2::new(
3267                                                        text.position[0] + start_pos.x,
3268                                                        row_y,
3269                                                    ),
3270                                                    Pos2::new(
3271                                                        text.position[0] + row_rect.max.x,
3272                                                        row_y + row_height,
3273                                                    ),
3274                                                )
3275                                            } else if row == end_row {
3276                                                // 最后一行从行首到文本结束位置
3277                                                Rect::from_min_max(
3278                                                    Pos2::new(
3279                                                        text.position[0] + row_rect.min.x,
3280                                                        row_y,
3281                                                    ),
3282                                                    Pos2::new(
3283                                                        text.position[0] + end_pos.x,
3284                                                        row_y + row_height,
3285                                                    ),
3286                                                )
3287                                            } else {
3288                                                // 中间整行
3289                                                Rect::from_min_max(
3290                                                    Pos2::new(
3291                                                        text.position[0] + row_rect.min.x,
3292                                                        row_y,
3293                                                    ),
3294                                                    Pos2::new(
3295                                                        text.position[0] + row_rect.max.x,
3296                                                        row_y + row_height,
3297                                                    ),
3298                                                )
3299                                            };
3300
3301                                            responses.push(ui.interact(
3302                                                link_rect,
3303                                                Id::new(format!(
3304                                                    "link_{}_{}_{}_row_{}",
3305                                                    render_resource.name, start, end, row
3306                                                )),
3307                                                Sense::click(),
3308                                            ));
3309                                        };
3310                                    }
3311                                    responses
3312                                };
3313
3314                                // 检查是否正在点击这个超链接
3315                                let mut is_pressing_link = false;
3316                                for link_response in &link_responses {
3317                                    if let Some(index) = self.get_render_layer_resource(
3318                                        &render_resource.name,
3319                                        "rust_constructor::Text",
3320                                    ) && let Some(mouse_pos) =
3321                                        ui.input(|i| i.pointer.interact_pos())
3322                                        && self.resource_get_focus(index, mouse_pos.into())
3323                                    {
3324                                        if link_response.is_pointer_button_down_on()
3325                                            && !link_response.drag_started()
3326                                        {
3327                                            text.selection = None;
3328                                            if let Some(pointer_pos) =
3329                                                ui.input(|i| i.pointer.interact_pos())
3330                                            {
3331                                                let relative_pos = pointer_pos
3332                                                    - <[f32; 2] as Into<Pos2>>::into(text.position);
3333                                                let cursor = galley.cursor_from_pos(relative_pos);
3334                                                if cursor.index >= *start && cursor.index <= *end {
3335                                                    is_pressing_link = true;
3336                                                    break;
3337                                                };
3338                                            };
3339                                        };
3340                                        // 检查是否释放了鼠标(点击完成)
3341                                        let mut clicked_on_link = false;
3342                                        for link_response in &link_responses {
3343                                            if link_response.clicked()
3344                                                && let Some(pointer_pos) =
3345                                                    ui.input(|i| i.pointer.interact_pos())
3346                                            {
3347                                                let relative_pos = pointer_pos
3348                                                    - <[f32; 2] as Into<Pos2>>::into(text.position);
3349                                                let cursor = galley.cursor_from_pos(relative_pos);
3350                                                if cursor.index >= *start && cursor.index <= *end {
3351                                                    clicked_on_link = true;
3352                                                    break;
3353                                                };
3354                                            };
3355                                        }
3356
3357                                        if clicked_on_link {
3358                                            // 执行超链接跳转
3359                                            if !url.is_empty() {
3360                                                ui.ctx().open_url(OpenUrl::new_tab(url));
3361                                            };
3362                                        };
3363                                    };
3364                                }
3365
3366                                // 绘制超链接高亮(如果正在点击或悬停)
3367                                if is_pressing_link {
3368                                    if start_cursor.min.y == end_cursor.min.y {
3369                                        // 单行超链接高亮
3370                                        let selection_rect = Rect::from_min_max(
3371                                            Pos2::new(
3372                                                text.position[0] + start_pos.x,
3373                                                text.position[1] + start_pos.y,
3374                                            ),
3375                                            Pos2::new(
3376                                                text.position[0] + end_pos.x,
3377                                                text.position[1]
3378                                                    + start_pos.y
3379                                                    + galley
3380                                                        .rows
3381                                                        .first()
3382                                                        .map_or(14.0, |row| row.height()),
3383                                            ),
3384                                        );
3385                                        ui.painter().rect_filled(
3386                                            selection_rect,
3387                                            0.0,
3388                                            Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3389                                        );
3390                                    } else {
3391                                        // 多行超链接高亮
3392                                        let row_height =
3393                                            galley.rows.first().map_or(14.0, |row| row.height());
3394                                        let start_row = (start_pos.y / row_height).round() as usize;
3395                                        let end_row = (end_pos.y / row_height).round() as usize;
3396
3397                                        for row in start_row..=end_row {
3398                                            if let Some(current_row) = galley.rows.get(row) {
3399                                                let row_rect = current_row.rect();
3400
3401                                                if row == start_row {
3402                                                    // 第一行从文本开始位置到行尾
3403                                                    let selection_rect = Rect::from_min_max(
3404                                                        Pos2::new(
3405                                                            text.position[0] + start_pos.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                                                } else if row == end_row {
3424                                                    // 最后一行从行首到文本结束位置
3425                                                    let selection_rect = Rect::from_min_max(
3426                                                        Pos2::new(
3427                                                            text.position[0] + row_rect.min.x,
3428                                                            text.position[1]
3429                                                                + row as f32 * row_height,
3430                                                        ),
3431                                                        Pos2::new(
3432                                                            text.position[0] + end_pos.x,
3433                                                            text.position[1]
3434                                                                + row as f32 * row_height
3435                                                                + row_height,
3436                                                        ),
3437                                                    );
3438                                                    ui.painter().rect_filled(
3439                                                        selection_rect,
3440                                                        0.0,
3441                                                        Color32::from_rgba_unmultiplied(
3442                                                            0, 120, 255, 100,
3443                                                        ),
3444                                                    );
3445                                                } else {
3446                                                    // 中间整行高亮
3447                                                    let selection_rect = Rect::from_min_max(
3448                                                        Pos2::new(
3449                                                            text.position[0] + row_rect.min.x,
3450                                                            text.position[1]
3451                                                                + row as f32 * row_height,
3452                                                        ),
3453                                                        Pos2::new(
3454                                                            text.position[0] + row_rect.max.x,
3455                                                            text.position[1]
3456                                                                + row as f32 * row_height
3457                                                                + row_height,
3458                                                        ),
3459                                                    );
3460                                                    ui.painter().rect_filled(
3461                                                        selection_rect,
3462                                                        0.0,
3463                                                        Color32::from_rgba_unmultiplied(
3464                                                            0, 120, 255, 100,
3465                                                        ),
3466                                                    );
3467                                                };
3468                                            };
3469                                        }
3470                                    };
3471                                };
3472                            }
3473                            if text.basic_front_resource_config.clip_rect.is_some() {
3474                                ui.set_clip_rect(Rect::from_min_size(
3475                                    [0_f32, 0_f32].into(),
3476                                    [ctx.available_rect().width(), ctx.available_rect().height()]
3477                                        .into(),
3478                                ));
3479                            };
3480                        } else {
3481                            text.selection = None;
3482                        };
3483                        text.last_frame_content = display_content;
3484                        self.replace_resource(&render_resource.name, text)?;
3485                    };
3486                }
3487                "rust_constructor::CustomRect" => {
3488                    let custom_rect = self.get_resource::<CustomRect>(
3489                        &render_resource.name,
3490                        "rust_constructor::CustomRect",
3491                    )?;
3492                    if custom_rect.display_info.enable {
3493                        let mut custom_rect = custom_rect.clone();
3494                        [custom_rect.position, custom_rect.size] = self.position_size_processor(
3495                            custom_rect.basic_front_resource_config.position_size_config,
3496                            ctx,
3497                        );
3498                        if !custom_rect.display_info.hidden {
3499                            if let Some(clip_rect) =
3500                                custom_rect.basic_front_resource_config.clip_rect
3501                            {
3502                                let [min, size] = self.position_size_processor(clip_rect, ctx);
3503                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
3504                            };
3505                            ui.painter().rect(
3506                                Rect::from_min_max(
3507                                    Pos2::new(custom_rect.position[0], custom_rect.position[1]),
3508                                    Pos2::new(
3509                                        custom_rect.position[0] + custom_rect.size[0],
3510                                        custom_rect.position[1] + custom_rect.size[1],
3511                                    ),
3512                                ),
3513                                custom_rect.rounding,
3514                                Color32::from_rgba_unmultiplied(
3515                                    custom_rect.color[0],
3516                                    custom_rect.color[1],
3517                                    custom_rect.color[2],
3518                                    custom_rect.alpha,
3519                                ),
3520                                Stroke {
3521                                    width: custom_rect.border_width,
3522                                    color: Color32::from_rgba_unmultiplied(
3523                                        custom_rect.border_color[0],
3524                                        custom_rect.border_color[1],
3525                                        custom_rect.border_color[2],
3526                                        custom_rect.alpha,
3527                                    ),
3528                                },
3529                                match custom_rect.border_kind {
3530                                    BorderKind::Inside => StrokeKind::Inside,
3531                                    BorderKind::Middle => StrokeKind::Middle,
3532                                    BorderKind::Outside => StrokeKind::Outside,
3533                                },
3534                            );
3535                            if custom_rect.basic_front_resource_config.clip_rect.is_some() {
3536                                ui.set_clip_rect(Rect::from_min_size(
3537                                    [0_f32, 0_f32].into(),
3538                                    [ctx.available_rect().width(), ctx.available_rect().height()]
3539                                        .into(),
3540                                ));
3541                            };
3542                        };
3543                        self.replace_resource(&render_resource.name, custom_rect)?;
3544                    };
3545                }
3546                _ => {
3547                    unreachable!()
3548                }
3549            }
3550            Ok(())
3551        } else {
3552            Err(RustConstructorError {
3553                error_id: "IndexOutOfRange".to_string(),
3554                description: format!(
3555                    "The maximum index of the target list is {}, but the index is {index}.",
3556                    self.render_list.len() - 1
3557                ),
3558            })
3559        }
3560    }
3561
3562    /// 打印资源活跃情况。
3563    pub fn active_list_info(&self, method: ActiveListInfoMethod) -> String {
3564        let mut text = String::from("Resource Active Info:\n");
3565        for info in &self.active_list {
3566            if let ActiveListInfoMethod::Detailed(format) = method {
3567                if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3568                    text += &if format {
3569                        format!(
3570                            "\nName: {}\nType: {}\nDetail: {:#?}\n",
3571                            info.name, info.discern_type, self.rust_constructor_resource[index],
3572                        )
3573                    } else {
3574                        format!(
3575                            "\nName: {}\nType: {}\nDetail: {:?}\n",
3576                            info.name, info.discern_type, self.rust_constructor_resource[index],
3577                        )
3578                    };
3579                };
3580            } else {
3581                text += &format!("\nName: {}\nType: {}\n", info.name, info.discern_type);
3582            };
3583        }
3584        text
3585    }
3586
3587    /// 打印渲染层级列表。
3588    pub fn render_layer_info(&self) -> String {
3589        let mut text = String::from("Render Layer Info:\n");
3590        for (
3591            RustConstructorId { name, discern_type },
3592            [min_position, max_position],
3593            ignore_render_layer,
3594        ) in &self.render_layer
3595        {
3596            text += &format!(
3597                "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
3598                name, discern_type, min_position, max_position, ignore_render_layer
3599            );
3600        }
3601        text
3602    }
3603
3604    /// 打印渲染队列。
3605    pub fn render_list_info(&self) -> String {
3606        let mut text = String::from("Render List Info:\n");
3607        for RustConstructorId { name, discern_type } in &self.render_list {
3608            text += &format!("\nName: {:?}\nType: {:?}\n", name, discern_type);
3609        }
3610        text
3611    }
3612
3613    /// 更新渲染队列。
3614    pub fn update_render_list(&mut self) {
3615        if self.render_list.is_empty() {
3616            for info in &self.active_list {
3617                if self.basic_front_resource_list.contains(&info.discern_type) {
3618                    self.render_list.push(RustConstructorId {
3619                        name: info.name.clone(),
3620                        discern_type: info.discern_type.clone(),
3621                    });
3622                };
3623            }
3624        } else {
3625            let mut count = 0;
3626            for render_resource in &self.render_list.clone() {
3627                if !self.active_list.contains(render_resource) {
3628                    self.render_list.remove(count);
3629                } else {
3630                    count += 1;
3631                };
3632            }
3633            let mut insert_index = 0;
3634            for info in &self.active_list {
3635                if self.basic_front_resource_list.contains(&info.discern_type) {
3636                    if !self.render_list.contains(info) {
3637                        self.render_list.insert(
3638                            insert_index,
3639                            RustConstructorId {
3640                                name: info.name.clone(),
3641                                discern_type: info.discern_type.clone(),
3642                            },
3643                        );
3644                        insert_index += 1;
3645                    } else if self.render_list[insert_index].cmp(info) == Ordering::Equal {
3646                        insert_index += 1;
3647                    };
3648                };
3649            }
3650        };
3651    }
3652
3653    /// 请求在渲染队列中插队,且无视申请跳过队列的资源是否存在。
3654    pub fn try_request_jump_render_list(
3655        &mut self,
3656        requester: RequestMethod,
3657        request_type: RequestType,
3658    ) {
3659        #[allow(warnings)]
3660        self.request_jump_render_list(requester, request_type);
3661    }
3662
3663    /// 请求在渲染队列中插队。
3664    pub fn request_jump_render_list(
3665        &mut self,
3666        requester: RequestMethod,
3667        request_type: RequestType,
3668    ) -> Result<(), RustConstructorError> {
3669        match requester {
3670            RequestMethod::Id(RustConstructorId { name, discern_type }) => {
3671                if let Some(index) = self
3672                    .render_list
3673                    .iter()
3674                    .position(|x| x.name == name && x.discern_type == discern_type)
3675                {
3676                    self.jump_render_list_processor(index, request_type)?;
3677                    Ok(())
3678                } else {
3679                    Err(RustConstructorError {
3680                        error_id: "RenderResourceNotFound".to_string(),
3681                        description: format!(
3682                            "Render resource \"{name}({discern_type})\" not found.",
3683                        ),
3684                    })
3685                }
3686            }
3687            RequestMethod::Citer(RustConstructorId { name, discern_type }) => {
3688                for (i, render_resource) in self.render_list.iter().enumerate() {
3689                    let [resource_name, resource_type] = [
3690                        render_resource.name.clone(),
3691                        render_resource.discern_type.clone(),
3692                    ];
3693                    let tags = self
3694                        .get_box_resource(&resource_name, &resource_type)?
3695                        .display_tags();
3696                    if let [Some(tag_name), Some(tag_type)] = [
3697                        self.get_tag("citer_name", &tags),
3698                        self.get_tag("citer_type", &tags),
3699                    ] && tag_name.1 == name
3700                        && tag_type.1 == discern_type
3701                    {
3702                        self.jump_render_list_processor(i, request_type)?;
3703                        return Ok(());
3704                    };
3705                }
3706                Err(RustConstructorError {
3707                    error_id: "RenderResourceNotFound".to_string(),
3708                    description: format!("Render resource \"{name}({discern_type})\" not found.",),
3709                })
3710            }
3711        }
3712    }
3713
3714    /// 执行跳过渲染队列操作。
3715    pub fn jump_render_list_processor(
3716        &mut self,
3717        requester_index: usize,
3718        request_type: RequestType,
3719    ) -> Result<(), RustConstructorError> {
3720        if requester_index < self.render_list.len() {
3721            let requester = self.render_list.remove(requester_index);
3722            let new_index = match request_type {
3723                RequestType::Top => self.render_list.len(),
3724                RequestType::Up(up) => {
3725                    if requester_index + up as usize <= self.render_list.len() {
3726                        requester_index + up as usize
3727                    } else {
3728                        self.render_list.len()
3729                    }
3730                }
3731            };
3732            self.render_list.insert(new_index, requester);
3733            Ok(())
3734        } else {
3735            Err(RustConstructorError {
3736                error_id: "IndexOutOfRange".to_string(),
3737                description: format!(
3738                    "The maximum index of the target list is {}, but the index is {requester_index}.",
3739                    self.render_list.len() - 1
3740                ),
3741            })
3742        }
3743    }
3744
3745    /// 根据活跃资源更新渲染层级列表。
3746    pub fn update_render_layer(&mut self) {
3747        self.render_layer.clear();
3748        for info in &self.render_list {
3749            if let Some(index) = self.check_resource_exists(&info.name, &info.discern_type) {
3750                let basic_front_resource: Box<dyn BasicFrontResource> = match &*info.discern_type {
3751                    "rust_constructor::Image" => Box::new(
3752                        self.rust_constructor_resource[index]
3753                            .content
3754                            .as_any()
3755                            .downcast_ref::<Image>()
3756                            .unwrap()
3757                            .clone(),
3758                    ),
3759                    "rust_constructor::Text" => Box::new(
3760                        self.rust_constructor_resource[index]
3761                            .content
3762                            .as_any()
3763                            .downcast_ref::<Text>()
3764                            .unwrap()
3765                            .clone(),
3766                    ),
3767                    "rust_constructor::CustomRect" => Box::new(
3768                        self.rust_constructor_resource[index]
3769                            .content
3770                            .as_any()
3771                            .downcast_ref::<CustomRect>()
3772                            .unwrap()
3773                            .clone(),
3774                    ),
3775                    _ => {
3776                        unreachable!()
3777                    }
3778                };
3779                if let Some(display_info) = basic_front_resource.display_display_info() {
3780                    self.render_layer.push((
3781                        info.clone(),
3782                        [
3783                            basic_front_resource.display_position(),
3784                            [
3785                                basic_front_resource.display_position()[0]
3786                                    + basic_front_resource.display_size()[0],
3787                                basic_front_resource.display_position()[1]
3788                                    + basic_front_resource.display_size()[1],
3789                            ],
3790                        ],
3791                        display_info.ignore_render_layer,
3792                    ));
3793                };
3794            };
3795        }
3796    }
3797
3798    /// 绘制渲染层。
3799    pub fn display_render_layer(
3800        &self,
3801        ui: &mut Ui,
3802        render_config: &RenderConfig,
3803        ignore_render_config: &RenderConfig,
3804    ) {
3805        for (_, point, ignore_render_layer) in &self.render_layer {
3806            match if *ignore_render_layer {
3807                ignore_render_config
3808            } else {
3809                render_config
3810            } {
3811                RenderConfig::Rect(
3812                    corner_radius,
3813                    fill_color,
3814                    border_color,
3815                    border_width,
3816                    border_kind,
3817                ) => {
3818                    let rect = Rect::from_min_max(point[0].into(), point[1].into());
3819                    ui.painter().rect(
3820                        rect,
3821                        CornerRadius {
3822                            nw: corner_radius[0],
3823                            ne: corner_radius[1],
3824                            sw: corner_radius[2],
3825                            se: corner_radius[3],
3826                        },
3827                        Color32::from_rgba_unmultiplied(
3828                            fill_color[0],
3829                            fill_color[1],
3830                            fill_color[2],
3831                            fill_color[3],
3832                        ),
3833                        Stroke::new(
3834                            *border_width,
3835                            Color32::from_rgba_unmultiplied(
3836                                border_color[0],
3837                                border_color[1],
3838                                border_color[2],
3839                                border_color[3],
3840                            ),
3841                        ),
3842                        match *border_kind {
3843                            BorderKind::Inside => StrokeKind::Inside,
3844                            BorderKind::Middle => StrokeKind::Middle,
3845                            BorderKind::Outside => StrokeKind::Outside,
3846                        },
3847                    );
3848                }
3849                RenderConfig::Line(width, color) => {
3850                    ui.painter().line_segment(
3851                        [point[0].into(), point[1].into()],
3852                        Stroke::new(
3853                            *width,
3854                            Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3855                        ),
3856                    );
3857                }
3858            };
3859        }
3860    }
3861
3862    /// 通过名称和类型在渲染列表中查找资源。
3863    pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3864        self.render_layer
3865            .iter()
3866            .position(|x| x.0.name == name && x.0.discern_type == discern_type)
3867    }
3868
3869    /// 检查资源是否获取鼠标焦点。
3870    pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3871        for i in index + 1..self.render_layer.len() {
3872            let point = self.render_layer[i].1;
3873            if mouse_pos[0] > point[0][0]
3874                && mouse_pos[1] > point[0][1]
3875                && mouse_pos[0] < point[1][0]
3876                && mouse_pos[1] < point[1][1]
3877                && !self.render_layer[i].2
3878            {
3879                return false;
3880            };
3881        }
3882        true
3883    }
3884
3885    /// 标记活跃资源。
3886    pub fn add_active_resource(
3887        &mut self,
3888        name: &str,
3889        discern_type: &str,
3890    ) -> Result<(), RustConstructorError> {
3891        if self.check_resource_exists(name, discern_type).is_some() {
3892            self.active_list.push(RustConstructorId {
3893                name: name.to_string(),
3894                discern_type: discern_type.to_string(),
3895            });
3896            Ok(())
3897        } else {
3898            Err(RustConstructorError {
3899                error_id: "ResourceNotFound".to_string(),
3900                description: format!("Resource \"{name}({discern_type})\" not found."),
3901            })
3902        }
3903    }
3904
3905    /// 添加资源。
3906    pub fn add_resource<T: RustConstructorResource + 'static>(
3907        &mut self,
3908        name: &str,
3909        mut resource: T,
3910    ) -> Result<(), RustConstructorError> {
3911        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3912            list.0
3913        } else {
3914            type_name_of_val(&resource)
3915        };
3916        if self.check_resource_exists(name, discern_type).is_some() {
3917            return Err(RustConstructorError {
3918                error_id: "ResourceNameRepetition".to_string(),
3919                description: format!("Resource \"{name}({discern_type})\" has already existed."),
3920            });
3921        };
3922        if name.is_empty() {
3923            return Err(RustConstructorError {
3924                error_id: "ResourceUntitled".to_string(),
3925                description: "All resources must have a valid name.".to_string(),
3926            });
3927        };
3928        match discern_type {
3929            "rust_constructor::SplitTime" => {
3930                if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3931                    split_time.time = [self.timer.now_time, self.timer.total_time];
3932                };
3933            }
3934            "rust_constructor::ImageTexture" => {
3935                if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3936                    if let Ok(mut file) = File::open(&image_texture.cite_path) {
3937                        let mut buffer = Vec::new();
3938                        file.read_to_end(&mut buffer).unwrap();
3939                        let img_bytes = buffer;
3940                        let img = image::load_from_memory(&img_bytes).unwrap();
3941                        let color_data = match image_texture.flip {
3942                            [true, true] => img.fliph().flipv().into_rgba8(),
3943                            [true, false] => img.fliph().into_rgba8(),
3944                            [false, true] => img.flipv().into_rgba8(),
3945                            _ => img.into_rgba8(),
3946                        };
3947                        let (w, h) = (color_data.width(), color_data.height());
3948                        let raw_data: Vec<u8> = color_data.into_raw();
3949
3950                        let color_image =
3951                            ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3952                        let loaded_image_texture = image_texture.context.load_texture(
3953                            name,
3954                            color_image,
3955                            TextureOptions::LINEAR,
3956                        );
3957                        image_texture.texture =
3958                            Some(DebugTextureHandle::new(&loaded_image_texture));
3959                        image_texture.cite_path = image_texture.cite_path.to_string();
3960                    } else {
3961                        return Err(RustConstructorError {
3962                            error_id: "ImageLoadFailed".to_string(),
3963                            description: format!(
3964                                "Failed to load an image from the path \"{}\".",
3965                                image_texture.cite_path
3966                            ),
3967                        });
3968                    };
3969                };
3970            }
3971            "rust_constructor::Image" => {
3972                if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3973                    let image_texture = self.get_resource::<ImageTexture>(
3974                        &image.cite_texture,
3975                        "rust_constructor::ImageTexture",
3976                    )?;
3977                    image.texture = image_texture.texture.clone();
3978                    image.last_frame_cite_texture = image.cite_texture.clone();
3979                };
3980            }
3981            "rust_constructor::Font" => {
3982                if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3983                    let mut fonts = FontDefinitions::default();
3984                    if let Ok(font_read_data) = read(&font.path) {
3985                        let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3986                        fonts.font_data.insert(
3987                            name.to_owned(),
3988                            Arc::new(FontData::from_owned(
3989                                Arc::try_unwrap(font_data).ok().unwrap(),
3990                            )),
3991                        );
3992
3993                        // 将字体添加到字体列表中
3994                        fonts
3995                            .families
3996                            .entry(FontFamily::Proportional)
3997                            .or_default()
3998                            .insert(0, name.to_owned());
3999
4000                        fonts
4001                            .families
4002                            .entry(FontFamily::Monospace)
4003                            .or_default()
4004                            .insert(0, name.to_owned());
4005
4006                        font.font_definitions = fonts;
4007                    } else {
4008                        return Err(RustConstructorError {
4009                            error_id: "FontLoadFailed".to_string(),
4010                            description: format!(
4011                                "Failed to load a font from the path \"{}\".",
4012                                font.path
4013                            ),
4014                        });
4015                    }
4016                };
4017            }
4018            "rust_constructor::Background" => {
4019                if let Some(background) = resource.as_any_mut().downcast_mut::<Background>() {
4020                    match &background.background_type {
4021                        BackgroundType::CustomRect(config) => {
4022                            let mut custom_rect = CustomRect::default().from_config(config);
4023                            if background.use_background_tags {
4024                                custom_rect.modify_tags(&background.tags, false);
4025                            };
4026                            self.add_resource(name, custom_rect)
4027                        }
4028                        BackgroundType::Image(config) => {
4029                            let mut image = Image::default().from_config(config);
4030                            if background.use_background_tags {
4031                                image.modify_tags(&background.tags, false);
4032                            };
4033                            self.add_resource(name, image)
4034                        }
4035                    }?;
4036                };
4037            }
4038            "rust_constructor::Switch" => {
4039                if let Some(switch) = resource.as_any_mut().downcast_mut::<Switch>() {
4040                    let count = 1 + switch.enable_animation.iter().filter(|x| **x).count();
4041                    if switch.appearance.len() != count * switch.state_amount as usize {
4042                        return Err(RustConstructorError {
4043                            error_id: "SwitchAppearanceConfigMismatch".to_string(),
4044                            description: format!(
4045                                "Expected {} elements, found {}.",
4046                                count * switch.state_amount as usize,
4047                                switch.appearance.len()
4048                            ),
4049                        });
4050                    };
4051                    self.add_resource(
4052                        &format!("{name}Background"),
4053                        Background::default()
4054                            .background_type(&switch.background_type)
4055                            .auto_update(true)
4056                            .use_background_tags(true)
4057                            .tags(
4058                                if switch.use_switch_tags {
4059                                    &switch.tags
4060                                } else {
4061                                    &[]
4062                                },
4063                                false,
4064                            )
4065                            .tags(
4066                                &[
4067                                    ["citer_name".to_string(), name.to_string()],
4068                                    ["citer_type".to_string(), discern_type.to_string()],
4069                                ],
4070                                false,
4071                            ),
4072                    )?;
4073                    self.add_resource(
4074                        &format!("{name}Text"),
4075                        Text::default()
4076                            .from_config(&switch.text_config)
4077                            .tags(
4078                                if switch.use_switch_tags {
4079                                    &switch.tags
4080                                } else {
4081                                    &[]
4082                                },
4083                                false,
4084                            )
4085                            .tags(
4086                                &[
4087                                    ["citer_name".to_string(), name.to_string()],
4088                                    ["citer_type".to_string(), discern_type.to_string()],
4089                                ],
4090                                false,
4091                            ),
4092                    )?;
4093                    self.add_resource(
4094                        &format!("{name}HintText"),
4095                        Text::default()
4096                            .from_config(&switch.hint_text_config)
4097                            .ignore_render_layer(true)
4098                            .hidden(true)
4099                            .alpha(0)
4100                            .tags(
4101                                &[
4102                                    ["citer_name".to_string(), name.to_string()],
4103                                    ["citer_type".to_string(), discern_type.to_string()],
4104                                    ["disable_x_scrolling".to_string(), "".to_string()],
4105                                    ["disable_y_scrolling".to_string(), "".to_string()],
4106                                ],
4107                                false,
4108                            ),
4109                    )?;
4110                    self.add_resource(
4111                        &format!("{name}StartHoverTime"),
4112                        SplitTime::default().tags(
4113                            &[
4114                                ["citer_name".to_string(), name.to_string()],
4115                                ["citer_type".to_string(), discern_type.to_string()],
4116                            ],
4117                            false,
4118                        ),
4119                    )?;
4120                    self.add_resource(
4121                        &format!("{name}HintFadeAnimation"),
4122                        SplitTime::default().tags(
4123                            &[
4124                                ["citer_name".to_string(), name.to_string()],
4125                                ["citer_type".to_string(), discern_type.to_string()],
4126                            ],
4127                            false,
4128                        ),
4129                    )?;
4130                };
4131            }
4132            "rust_constructor::ResourcePanel" => {
4133                if let Some(resource_panel) = resource.as_any_mut().downcast_mut::<ResourcePanel>()
4134                {
4135                    self.add_resource(
4136                        &format!("{name}Background"),
4137                        Background::default()
4138                            .background_type(&resource_panel.background)
4139                            .auto_update(true)
4140                            .use_background_tags(true)
4141                            .tags(
4142                                &[
4143                                    ["citer_name".to_string(), name.to_string()],
4144                                    ["citer_type".to_string(), discern_type.to_string()],
4145                                ],
4146                                false,
4147                            ),
4148                    )?;
4149                    if let ScrollBarDisplayMethod::Always(_, _, _) =
4150                        &resource_panel.scroll_bar_display_method
4151                    {
4152                        self.add_resource(
4153                            &format!("{name}XScroll"),
4154                            Background::default()
4155                                .auto_update(true)
4156                                .use_background_tags(true)
4157                                .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}YScroll"),
4167                            Background::default()
4168                                .auto_update(true)
4169                                .use_background_tags(true)
4170                                .tags(
4171                                    &[
4172                                        ["citer_name".to_string(), name.to_string()],
4173                                        ["citer_type".to_string(), discern_type.to_string()],
4174                                    ],
4175                                    false,
4176                                ),
4177                        )?;
4178                    };
4179                    if let ScrollBarDisplayMethod::OnlyScroll(_, _, _) =
4180                        &resource_panel.scroll_bar_display_method
4181                    {
4182                        self.add_resource(
4183                            &format!("{name}XScroll"),
4184                            Background::default()
4185                                .auto_update(true)
4186                                .use_background_tags(true)
4187                                .tags(
4188                                    &[
4189                                        ["citer_name".to_string(), name.to_string()],
4190                                        ["citer_type".to_string(), discern_type.to_string()],
4191                                    ],
4192                                    false,
4193                                ),
4194                        )?;
4195                        self.add_resource(
4196                            &format!("{name}YScroll"),
4197                            Background::default()
4198                                .auto_update(true)
4199                                .use_background_tags(true)
4200                                .tags(
4201                                    &[
4202                                        ["citer_name".to_string(), name.to_string()],
4203                                        ["citer_type".to_string(), discern_type.to_string()],
4204                                    ],
4205                                    false,
4206                                ),
4207                        )?;
4208                        self.add_resource(
4209                            &format!("{name}ScrollBarXAlpha"),
4210                            SplitTime::default().tags(
4211                                &[
4212                                    ["citer_name".to_string(), name.to_string()],
4213                                    ["citer_type".to_string(), discern_type.to_string()],
4214                                ],
4215                                false,
4216                            ),
4217                        )?;
4218                        self.add_resource(
4219                            &format!("{name}ScrollBarXAlphaStart"),
4220                            SplitTime::default().tags(
4221                                &[
4222                                    ["citer_name".to_string(), name.to_string()],
4223                                    ["citer_type".to_string(), discern_type.to_string()],
4224                                ],
4225                                false,
4226                            ),
4227                        )?;
4228                        self.add_resource(
4229                            &format!("{name}ScrollBarYAlpha"),
4230                            SplitTime::default().tags(
4231                                &[
4232                                    ["citer_name".to_string(), name.to_string()],
4233                                    ["citer_type".to_string(), discern_type.to_string()],
4234                                ],
4235                                false,
4236                            ),
4237                        )?;
4238                        self.add_resource(
4239                            &format!("{name}ScrollBarYAlphaStart"),
4240                            SplitTime::default().tags(
4241                                &[
4242                                    ["citer_name".to_string(), name.to_string()],
4243                                    ["citer_type".to_string(), discern_type.to_string()],
4244                                ],
4245                                false,
4246                            ),
4247                        )?;
4248                    };
4249                };
4250            }
4251            _ => {}
4252        };
4253        self.rust_constructor_resource
4254            .push(RustConstructorResourceBox::new(
4255                name,
4256                discern_type,
4257                Box::new(resource),
4258            ));
4259        Ok(())
4260    }
4261
4262    /// 移除资源。此方法非常危险!务必确保资源一定不再使用后删除。
4263    pub fn drop_resource(
4264        &mut self,
4265        name: &str,
4266        discern_type: &str,
4267    ) -> Result<(), RustConstructorError> {
4268        if let Some(index) = self.check_resource_exists(name, discern_type) {
4269            self.rust_constructor_resource.remove(index);
4270            if let Some(index) = self
4271                .active_list
4272                .iter()
4273                .position(|x| x.name == name && x.discern_type == discern_type)
4274            {
4275                self.active_list.remove(index);
4276            };
4277            if let Some(index) = self
4278                .render_layer
4279                .iter()
4280                .position(|x| x.0.name == name && x.0.discern_type == discern_type)
4281            {
4282                self.render_layer.remove(index);
4283            };
4284            Ok(())
4285        } else {
4286            Err(RustConstructorError {
4287                error_id: "ResourceNotFound".to_string(),
4288                description: format!("Resource \"{name}({discern_type})\" not found."),
4289            })
4290        }
4291    }
4292
4293    /// 从列表中替换资源。
4294    pub fn replace_resource<T>(
4295        &mut self,
4296        name: &str,
4297        resource: T,
4298    ) -> Result<(), RustConstructorError>
4299    where
4300        T: RustConstructorResource + 'static,
4301    {
4302        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4303            list.0
4304        } else {
4305            type_name_of_val(&resource)
4306        };
4307        if let Some(index) = self.check_resource_exists(name, discern_type) {
4308            self.rust_constructor_resource[index] =
4309                RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
4310            Ok(())
4311        } else {
4312            Err(RustConstructorError {
4313                error_id: "ResourceNotFound".to_string(),
4314                description: format!("Resource \"{name}({discern_type})\" not found."),
4315            })
4316        }
4317    }
4318
4319    /// 从列表中获取封装的不可变资源。
4320    pub fn get_box_resource(
4321        &self,
4322        name: &str,
4323        discern_type: &str,
4324    ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
4325        if let Some(index) = self.check_resource_exists(name, discern_type) {
4326            Ok(&*self.rust_constructor_resource[index].content)
4327        } else {
4328            Err(RustConstructorError {
4329                error_id: "ResourceNotFound".to_string(),
4330                description: format!("Resource \"{name}({discern_type})\" not found."),
4331            })
4332        }
4333    }
4334
4335    /// 从列表中获取封装的可变资源。
4336    pub fn get_box_resource_mut(
4337        &mut self,
4338        name: &str,
4339        discern_type: &str,
4340    ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
4341        if let Some(index) = self.check_resource_exists(name, discern_type) {
4342            Ok(&mut *self.rust_constructor_resource[index].content)
4343        } else {
4344            Err(RustConstructorError {
4345                error_id: "ResourceNotFound".to_string(),
4346                description: format!("Resource \"{name}({discern_type})\" not found."),
4347            })
4348        }
4349    }
4350
4351    /// 从列表中获取不可变资源。
4352    pub fn get_resource<T>(
4353        &self,
4354        name: &str,
4355        discern_type: &str,
4356    ) -> Result<&T, RustConstructorError>
4357    where
4358        T: RustConstructorResource + 'static,
4359    {
4360        if let Some(resource) = self
4361            .get_box_resource(name, discern_type)?
4362            .as_any()
4363            .downcast_ref::<T>()
4364        {
4365            Ok(resource)
4366        } else {
4367            Err(RustConstructorError {
4368                error_id: "ResourceGenericMismatch".to_string(),
4369                description: format!(
4370                    "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4371                ),
4372            })
4373        }
4374    }
4375
4376    /// 从列表中获取可变资源。
4377    pub fn get_resource_mut<T>(
4378        &mut self,
4379        name: &str,
4380        discern_type: &str,
4381    ) -> Result<&mut T, RustConstructorError>
4382    where
4383        T: RustConstructorResource + 'static,
4384    {
4385        if let Some(resource) = self
4386            .get_box_resource_mut(name, discern_type)?
4387            .as_any_mut()
4388            .downcast_mut::<T>()
4389        {
4390            Ok(resource)
4391        } else {
4392            Err(RustConstructorError {
4393                error_id: "ResourceGenericMismatch".to_string(),
4394                description: format!(
4395                    "The generic type of the resource \"{name}({discern_type})\" is mismatched."
4396                ),
4397            })
4398        }
4399    }
4400
4401    /// 检查是否存在特定资源。
4402    pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
4403        self.rust_constructor_resource
4404            .iter()
4405            .position(|x| x.id.name == name && x.id.discern_type == discern_type)
4406    }
4407
4408    /// 快速放置。
4409    pub fn quick_place<T: RustConstructorResource + 'static>(
4410        &mut self,
4411        name: &str,
4412        resource: T,
4413        ui: &mut Ui,
4414        ctx: &Context,
4415    ) -> Result<(), RustConstructorError> {
4416        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
4417            list.0
4418        } else {
4419            type_name_of_val(&resource)
4420        };
4421        if self.check_resource_exists(name, discern_type).is_none() {
4422            self.add_resource(name, resource)
4423        } else {
4424            self.use_resource(name, discern_type, ui, ctx)
4425        }
4426    }
4427
4428    /// 调用资源。
4429    pub fn use_resource(
4430        &mut self,
4431        name: &str,
4432        discern_type: &str,
4433        ui: &mut Ui,
4434        ctx: &Context,
4435    ) -> Result<(), RustConstructorError> {
4436        if self.check_resource_exists(name, discern_type).is_some() {
4437            match discern_type {
4438                "rust_constructor::CustomRect"
4439                | "rust_constructor::Text"
4440                | "rust_constructor::Image" => {
4441                    self.add_active_resource(name, discern_type)?;
4442                }
4443                "rust_constructor::PageData" => {
4444                    // 更新帧数
4445                    self.update_frame_stats();
4446                    // 更新渲染队列。
4447                    self.update_render_list();
4448                    // 绘制渲染队列中的资源。
4449                    for i in 0..self.render_list.len() {
4450                        self.draw_resource_by_index(ui, ctx, i)?;
4451                    }
4452                    // 更新渲染列表。
4453                    self.update_render_layer();
4454                    // 更新资源活跃状态。
4455                    self.active_list.clear();
4456                    // 更新资源启用状态。
4457                    for rcr in &mut self.rust_constructor_resource {
4458                        if let Some(display_info) = &mut rcr.content.display_display_info() {
4459                            rcr.content.modify_display_info(DisplayInfo {
4460                                enable: true,
4461                                hidden: display_info.hidden,
4462                                ignore_render_layer: display_info.ignore_render_layer,
4463                            });
4464                        };
4465                    }
4466                    // 更新计时器
4467                    self.update_timer();
4468                    let current_page = &self.current_page.clone();
4469                    let page_data =
4470                        self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
4471                    if page_data.forced_update {
4472                        ctx.request_repaint();
4473                    };
4474                }
4475                "rust_constructor::Background" => {
4476                    let background = self.get_resource::<Background>(name, discern_type)?.clone();
4477                    if background.auto_update {
4478                        match &background.background_type {
4479                            BackgroundType::CustomRect(config) => {
4480                                let mut custom_rect = self
4481                                    .get_resource::<CustomRect>(
4482                                        name,
4483                                        "rust_constructor::CustomRect",
4484                                    )?
4485                                    .clone()
4486                                    .from_config(config);
4487                                if background.use_background_tags {
4488                                    custom_rect.modify_tags(&background.tags, false);
4489                                };
4490                                self.replace_resource(name, custom_rect)?;
4491                            }
4492                            BackgroundType::Image(config) => {
4493                                let mut image = self
4494                                    .get_resource::<Image>(name, "rust_constructor::Image")?
4495                                    .clone()
4496                                    .from_config(config);
4497                                if background.use_background_tags {
4498                                    image.modify_tags(&background.tags, false);
4499                                };
4500                                self.replace_resource(name, image)?;
4501                            }
4502                        };
4503                    };
4504                    match background.background_type {
4505                        BackgroundType::CustomRect(_) => {
4506                            self.use_resource(name, "rust_constructor::CustomRect", ui, ctx)
4507                        }
4508                        BackgroundType::Image(_) => {
4509                            self.use_resource(name, "rust_constructor::Image", ui, ctx)
4510                        }
4511                    }?;
4512                }
4513                "rust_constructor::Switch" => {
4514                    let mut switch = self
4515                        .get_resource::<Switch>(name, "rust_constructor::Switch")?
4516                        .clone();
4517                    let mut background = self
4518                        .get_resource::<Background>(
4519                            &format!("{name}Background"),
4520                            "rust_constructor::Background",
4521                        )?
4522                        .clone();
4523                    let background_resource_type = match switch.background_type {
4524                        BackgroundType::CustomRect(_) => "rust_constructor::CustomRect",
4525                        BackgroundType::Image(_) => "rust_constructor::Image",
4526                    };
4527                    let background_resource: Box<dyn BasicFrontResource> =
4528                        match background_resource_type {
4529                            "rust_constructor::CustomRect" => Box::new(
4530                                self.get_resource::<CustomRect>(
4531                                    &format!("{name}Background"),
4532                                    background_resource_type,
4533                                )?
4534                                .clone(),
4535                            ),
4536                            "rust_constructor::Image" => Box::new(
4537                                self.get_resource::<Image>(
4538                                    &format!("{name}Background"),
4539                                    background_resource_type,
4540                                )?
4541                                .clone(),
4542                            ),
4543                            _ => {
4544                                unreachable!()
4545                            }
4546                        };
4547                    let mut text = self
4548                        .get_resource::<Text>(&format!("{name}Text"), "rust_constructor::Text")?
4549                        .clone();
4550                    let mut hint_text = self
4551                        .get_resource::<Text>(&format!("{name}HintText"), "rust_constructor::Text")?
4552                        .clone();
4553                    let rect = Rect::from_min_size(
4554                        background_resource.display_position().into(),
4555                        background_resource.display_size().into(),
4556                    );
4557                    switch.switched = false;
4558                    let animation_count =
4559                        1 + switch.enable_animation.iter().filter(|x| **x).count();
4560                    let mut clicked = None;
4561                    let mut hovered = false;
4562                    let mut appearance_count = 0;
4563                    // 处理点击事件
4564                    if let Some(index) = self.get_render_layer_resource(
4565                        &format!("{name}Background"),
4566                        background_resource_type,
4567                    ) && switch.enable
4568                        && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
4569                        && self.resource_get_focus(index, mouse_pos.into())
4570                        && let Some(display_info) = background_resource.display_display_info()
4571                        && !display_info.hidden
4572                    {
4573                        // 判断是否在矩形内
4574                        if rect.contains(mouse_pos) {
4575                            if !switch.last_frame_hovered {
4576                                self.reset_split_time(&format!("{name}StartHoverTime"))?;
4577                            } else if self.timer.total_time
4578                                - self.get_split_time(&format!("{name}StartHoverTime"))?[1]
4579                                >= 2_f32
4580                                || hint_text.alpha != 0
4581                            {
4582                                hint_text.alpha = 255;
4583                                hint_text
4584                                    .basic_front_resource_config
4585                                    .position_size_config
4586                                    .origin_position = [mouse_pos.x, mouse_pos.y];
4587                            };
4588                            hint_text
4589                                .basic_front_resource_config
4590                                .position_size_config
4591                                .display_method
4592                                .0 = if mouse_pos.x + hint_text.actual_size[0]
4593                                <= ctx.available_rect().width()
4594                            {
4595                                HorizontalAlign::Left
4596                            } else {
4597                                HorizontalAlign::Right
4598                            };
4599                            hint_text
4600                                .basic_front_resource_config
4601                                .position_size_config
4602                                .display_method
4603                                .1 = if mouse_pos.y + hint_text.actual_size[1]
4604                                <= ctx.available_rect().height()
4605                            {
4606                                VerticalAlign::Top
4607                            } else {
4608                                VerticalAlign::Bottom
4609                            };
4610                            hovered = true;
4611                            for (count, click_method) in switch.click_method.iter().enumerate() {
4612                                if ui.input(|i| {
4613                                    switch.last_frame_clicked.is_none()
4614                                        && i.pointer.button_pressed(click_method.click_method)
4615                                        || switch.last_frame_clicked.is_some()
4616                                            && i.pointer.button_down(click_method.click_method)
4617                                }) {
4618                                    clicked = Some(count);
4619                                    break;
4620                                };
4621                            }
4622                            if let Some(clicked_index) = switch.last_frame_clicked
4623                                && clicked.is_none()
4624                            {
4625                                switch.switched = true;
4626                                if switch.click_method[clicked_index].action {
4627                                    if switch.state
4628                                        < (switch.appearance.len() / animation_count - 1) as u32
4629                                    {
4630                                        switch.state += 1;
4631                                    } else {
4632                                        switch.state = 0;
4633                                    };
4634                                };
4635                            };
4636                            appearance_count = if clicked.is_some() {
4637                                match switch.enable_animation {
4638                                    [true, true] => 2,
4639                                    [true, false] | [false, true] => 1,
4640                                    [false, false] => 0,
4641                                }
4642                            } else if switch.enable_animation[0] {
4643                                1
4644                            } else {
4645                                0
4646                            };
4647                        };
4648                    };
4649
4650                    // 若鼠标未悬挂在开关上,逐渐隐藏提示文本
4651                    if !hovered {
4652                        if switch.last_frame_hovered {
4653                            self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4654                        };
4655                        if self.timer.total_time
4656                            - self.get_split_time(&format!("{name}HintFadeAnimation"))?[1]
4657                            >= self.tick_interval
4658                        {
4659                            self.reset_split_time(&format!("{name}HintFadeAnimation"))?;
4660                            hint_text.alpha = hint_text.alpha.saturating_sub(10);
4661                        };
4662                    };
4663
4664                    hint_text.display_info.hidden = hint_text.alpha == 0;
4665
4666                    // 更新Background样式。
4667                    background.background_type = switch.appearance
4668                        [(switch.state * animation_count as u32 + appearance_count) as usize]
4669                        .background_config
4670                        .clone();
4671
4672                    background.modify_tags(
4673                        if switch.use_switch_tags {
4674                            &switch.tags
4675                        } else {
4676                            &[]
4677                        },
4678                        false,
4679                    );
4680
4681                    // 刷新提示Text。
4682                    let alpha = hint_text.alpha;
4683                    hint_text = hint_text
4684                        .from_config(
4685                            &switch.appearance[(switch.state * animation_count as u32
4686                                + appearance_count)
4687                                as usize]
4688                                .hint_text_config,
4689                        )
4690                        .ignore_render_layer(true);
4691                    hint_text.background_alpha = alpha;
4692                    hint_text.alpha = alpha;
4693                    hint_text.display_info.hidden = if let Some(display_info) =
4694                        background_resource.display_display_info()
4695                        && display_info.hidden
4696                    {
4697                        true
4698                    } else {
4699                        hint_text.display_info.hidden
4700                    };
4701
4702                    // 更新Text样式。
4703                    text = text
4704                        .tags(
4705                            if switch.use_switch_tags {
4706                                &switch.tags
4707                            } else {
4708                                &[]
4709                            },
4710                            false,
4711                        )
4712                        .from_config(
4713                            &switch.appearance[(switch.state * animation_count as u32
4714                                + appearance_count)
4715                                as usize]
4716                                .text_config,
4717                        );
4718
4719                    switch.last_frame_hovered = hovered;
4720                    switch.last_frame_clicked = clicked;
4721
4722                    self.replace_resource(&format!("{name}Text"), text)?;
4723                    self.replace_resource(&format!("{name}HintText"), hint_text)?;
4724                    self.replace_resource(name, switch)?;
4725                    self.replace_resource(&format!("{name}Background"), background)?;
4726
4727                    self.use_resource(
4728                        &format!("{name}Background"),
4729                        "rust_constructor::Background",
4730                        ui,
4731                        ctx,
4732                    )?;
4733                    self.use_resource(&format!("{name}Text"), "rust_constructor::Text", ui, ctx)?;
4734                    if alpha != 0 {
4735                        self.use_resource(
4736                            &format!("{name}HintText"),
4737                            "rust_constructor::Text",
4738                            ui,
4739                            ctx,
4740                        )?;
4741                    };
4742                }
4743                "rust_constructor::ResourcePanel" => {
4744                    let mut resource_panel = self
4745                        .get_resource::<ResourcePanel>(name, "rust_constructor::ResourcePanel")?
4746                        .clone();
4747                    let background = self
4748                        .get_resource::<Background>(
4749                            &format!("{name}Background"),
4750                            "rust_constructor::Background",
4751                        )?
4752                        .clone();
4753                    let background_resource: Box<dyn BasicFrontResource> =
4754                        match background.background_type.clone() {
4755                            BackgroundType::CustomRect(_) => Box::new(
4756                                self.get_resource::<CustomRect>(
4757                                    &format!("{name}Background"),
4758                                    "rust_constructor::CustomRect",
4759                                )?
4760                                .clone(),
4761                            ),
4762                            BackgroundType::Image(_) => Box::new(
4763                                self.get_resource::<Image>(
4764                                    &format!("{name}Background"),
4765                                    "rust_constructor::Image",
4766                                )?
4767                                .clone(),
4768                            ),
4769                        };
4770                    let (mut position_size_config, mut position, mut size) = (
4771                        background_resource
4772                            .display_basic_front_resource_config()
4773                            .position_size_config,
4774                        background_resource.display_position(),
4775                        background_resource.display_size(),
4776                    );
4777                    let rect = Rect::from_min_size(position.into(), size.into());
4778                    resource_panel.scrolled = [false, false];
4779                    if resource_panel.resizable.contains(&true)
4780                        || resource_panel.movable.contains(&true)
4781                    {
4782                        position_size_config.x_location_grid = [0_f32, 0_f32];
4783                        position_size_config.y_location_grid = [0_f32, 0_f32];
4784                        position_size_config.x_size_grid = [0_f32, 0_f32];
4785                        position_size_config.y_size_grid = [0_f32, 0_f32];
4786                    };
4787                    if resource_panel.min_size[0] < 10_f32 {
4788                        resource_panel.min_size[0] = 10_f32;
4789                    };
4790                    if resource_panel.min_size[1] < 10_f32 {
4791                        resource_panel.min_size[1] = 10_f32;
4792                    };
4793                    if position_size_config.origin_size[0] < resource_panel.min_size[0] {
4794                        position_size_config.origin_size[0] = resource_panel.min_size[0];
4795                    };
4796                    if position_size_config.origin_size[1] < resource_panel.min_size[1] {
4797                        position_size_config.origin_size[1] = resource_panel.min_size[1];
4798                    };
4799                    [position, size] = self.position_size_processor(position_size_config, ctx);
4800                    let scroll_delta: [f32; 2] = if resource_panel.use_smooth_scroll_delta {
4801                        ui.input(|i| i.smooth_scroll_delta).into()
4802                    } else {
4803                        ui.input(|i| i.raw_scroll_delta).into()
4804                    };
4805                    let [x_scroll_delta, y_scroll_delta] =
4806                        if scroll_delta[0].abs() >= scroll_delta[1].abs() {
4807                            [
4808                                if resource_panel.reverse_scroll_direction[0] {
4809                                    -scroll_delta[0]
4810                                } else {
4811                                    scroll_delta[0]
4812                                },
4813                                0_f32,
4814                            ]
4815                        } else {
4816                            [
4817                                0_f32,
4818                                if resource_panel.reverse_scroll_direction[1] {
4819                                    -scroll_delta[1]
4820                                } else {
4821                                    scroll_delta[1]
4822                                },
4823                            ]
4824                        };
4825                    if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
4826                        && !resource_panel.hidden
4827                    {
4828                        if let Some(index) = self.get_render_layer_resource(
4829                            &format!("{name}Background"),
4830                            match background.background_type {
4831                                BackgroundType::CustomRect(_) => "rust_constructor::CustomRect",
4832                                BackgroundType::Image(_) => "rust_constructor::Image",
4833                            },
4834                        ) && self.resource_get_focus(index, mouse_pos.into())
4835                        {
4836                            if ui.input(|i| i.pointer.primary_pressed())
4837                                && Rect::from_min_size(position.into(), size.into())
4838                                    .contains(mouse_pos)
4839                            {
4840                                self.request_jump_render_list(
4841                                    RequestMethod::Id(RustConstructorId {
4842                                        name: format!("{name}Background"),
4843                                        discern_type: match background.background_type {
4844                                            BackgroundType::CustomRect(_) => {
4845                                                "rust_constructor::CustomRect"
4846                                            }
4847                                            BackgroundType::Image(_) => "rust_constructor::Image",
4848                                        }
4849                                        .to_string(),
4850                                    }),
4851                                    RequestType::Top,
4852                                )
4853                                .unwrap();
4854                                let mut update_list = Vec::new();
4855                                for rcr in &self.rust_constructor_resource {
4856                                    if self
4857                                        .basic_front_resource_list
4858                                        .contains(&rcr.id.discern_type)
4859                                        && let Some(panel_name) =
4860                                            self.get_tag("panel_name", &rcr.content.display_tags())
4861                                        && panel_name.1 == name
4862                                    {
4863                                        update_list.push(rcr.id.clone());
4864                                    };
4865                                }
4866                                for id in update_list {
4867                                    self.try_request_jump_render_list(
4868                                        RequestMethod::Id(id),
4869                                        RequestType::Top,
4870                                    );
4871                                }
4872                                if let ScrollBarDisplayMethod::Always(ref background_type, _, _) =
4873                                    resource_panel.scroll_bar_display_method
4874                                {
4875                                    self.try_request_jump_render_list(
4876                                        RequestMethod::Id(RustConstructorId {
4877                                            name: format!("{name}XScroll"),
4878                                            discern_type: match background_type {
4879                                                BackgroundType::CustomRect(_) => {
4880                                                    "rust_constructor::CustomRect"
4881                                                }
4882                                                BackgroundType::Image(_) => {
4883                                                    "rust_constructor::Image"
4884                                                }
4885                                            }
4886                                            .to_string(),
4887                                        }),
4888                                        RequestType::Top,
4889                                    );
4890                                    self.try_request_jump_render_list(
4891                                        RequestMethod::Id(RustConstructorId {
4892                                            name: format!("{name}YScroll"),
4893                                            discern_type: match background_type {
4894                                                BackgroundType::CustomRect(_) => {
4895                                                    "rust_constructor::CustomRect"
4896                                                }
4897                                                BackgroundType::Image(_) => {
4898                                                    "rust_constructor::Image"
4899                                                }
4900                                            }
4901                                            .to_string(),
4902                                        }),
4903                                        RequestType::Top,
4904                                    );
4905                                };
4906                                if let ScrollBarDisplayMethod::OnlyScroll(
4907                                    ref background_type,
4908                                    _,
4909                                    _,
4910                                ) = resource_panel.scroll_bar_display_method
4911                                {
4912                                    self.try_request_jump_render_list(
4913                                        RequestMethod::Id(RustConstructorId {
4914                                            name: format!("{name}XScroll"),
4915                                            discern_type: match background_type {
4916                                                BackgroundType::CustomRect(_) => {
4917                                                    "rust_constructor::CustomRect"
4918                                                }
4919                                                BackgroundType::Image(_) => {
4920                                                    "rust_constructor::Image"
4921                                                }
4922                                            }
4923                                            .to_string(),
4924                                        }),
4925                                        RequestType::Top,
4926                                    );
4927                                    self.try_request_jump_render_list(
4928                                        RequestMethod::Id(RustConstructorId {
4929                                            name: format!("{name}YScroll"),
4930                                            discern_type: match background_type {
4931                                                BackgroundType::CustomRect(_) => {
4932                                                    "rust_constructor::CustomRect"
4933                                                }
4934                                                BackgroundType::Image(_) => {
4935                                                    "rust_constructor::Image"
4936                                                }
4937                                            }
4938                                            .to_string(),
4939                                        }),
4940                                        RequestType::Top,
4941                                    );
4942                                };
4943                            };
4944                            let top_rect = Rect::from_min_size(
4945                                [position[0], position[1]].into(),
4946                                [size[0], 3_f32].into(),
4947                            );
4948                            let bottom_rect = Rect::from_min_size(
4949                                [position[0], position[1] + size[1] - 3_f32].into(),
4950                                [size[0], 3_f32].into(),
4951                            );
4952                            let left_rect = Rect::from_min_size(
4953                                [position[0], position[1]].into(),
4954                                [3_f32, size[1]].into(),
4955                            );
4956                            let right_rect = Rect::from_min_size(
4957                                [position[0] + size[0] - 3_f32, position[1]].into(),
4958                                [3_f32, size[1]].into(),
4959                            );
4960                            match [
4961                                top_rect.contains(mouse_pos),
4962                                bottom_rect.contains(mouse_pos),
4963                                left_rect.contains(mouse_pos),
4964                                right_rect.contains(mouse_pos),
4965                            ] {
4966                                [true, false, false, false] => {
4967                                    if resource_panel.resizable[0] {
4968                                        if resource_panel.last_frame_mouse_status.is_none()
4969                                            && ui.input(|i| i.pointer.primary_pressed())
4970                                        {
4971                                            resource_panel.last_frame_mouse_status = Some((
4972                                                mouse_pos.into(),
4973                                                ClickAim::TopResize,
4974                                                [
4975                                                    mouse_pos.x - position[0],
4976                                                    mouse_pos.y - position[1],
4977                                                ],
4978                                            ))
4979                                        };
4980                                        if size[1] > resource_panel.min_size[1]
4981                                            && (resource_panel.max_size.is_none()
4982                                                || size[1] < resource_panel.max_size.unwrap()[1])
4983                                        {
4984                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4985                                        } else if resource_panel.max_size.is_some()
4986                                            && size[1] >= resource_panel.max_size.unwrap()[1]
4987                                        {
4988                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4989                                        } else {
4990                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4991                                        };
4992                                    };
4993                                }
4994                                [false, true, false, false] => {
4995                                    if resource_panel.resizable[1] {
4996                                        if resource_panel.last_frame_mouse_status.is_none()
4997                                            && ui.input(|i| i.pointer.primary_pressed())
4998                                        {
4999                                            resource_panel.last_frame_mouse_status = Some((
5000                                                mouse_pos.into(),
5001                                                ClickAim::BottomResize,
5002                                                [
5003                                                    mouse_pos.x - position[0],
5004                                                    mouse_pos.y - position[1],
5005                                                ],
5006                                            ))
5007                                        };
5008                                        if size[1] > resource_panel.min_size[1]
5009                                            && (resource_panel.max_size.is_none()
5010                                                || size[1] < resource_panel.max_size.unwrap()[1])
5011                                        {
5012                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5013                                        } else if resource_panel.max_size.is_some()
5014                                            && size[1] >= resource_panel.max_size.unwrap()[1]
5015                                        {
5016                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5017                                        } else {
5018                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5019                                        };
5020                                    };
5021                                }
5022                                [false, false, true, false] => {
5023                                    if resource_panel.resizable[2] {
5024                                        if resource_panel.last_frame_mouse_status.is_none()
5025                                            && ui.input(|i| i.pointer.primary_pressed())
5026                                        {
5027                                            resource_panel.last_frame_mouse_status = Some((
5028                                                mouse_pos.into(),
5029                                                ClickAim::LeftResize,
5030                                                [
5031                                                    mouse_pos.x - position[0],
5032                                                    mouse_pos.y - position[1],
5033                                                ],
5034                                            ))
5035                                        };
5036                                        if size[0] > resource_panel.min_size[0]
5037                                            && (resource_panel.max_size.is_none()
5038                                                || size[0] < resource_panel.max_size.unwrap()[0])
5039                                        {
5040                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5041                                        } else if resource_panel.max_size.is_some()
5042                                            && size[0] >= resource_panel.max_size.unwrap()[0]
5043                                        {
5044                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
5045                                        } else {
5046                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
5047                                        };
5048                                    };
5049                                }
5050                                [false, false, false, true] => {
5051                                    if resource_panel.resizable[3] {
5052                                        if resource_panel.last_frame_mouse_status.is_none()
5053                                            && ui.input(|i| i.pointer.primary_pressed())
5054                                        {
5055                                            resource_panel.last_frame_mouse_status = Some((
5056                                                mouse_pos.into(),
5057                                                ClickAim::RightResize,
5058                                                [
5059                                                    mouse_pos.x - position[0],
5060                                                    mouse_pos.y - position[1],
5061                                                ],
5062                                            ))
5063                                        };
5064                                        if size[0] > resource_panel.min_size[0]
5065                                            && (resource_panel.max_size.is_none()
5066                                                || size[0] < resource_panel.max_size.unwrap()[0])
5067                                        {
5068                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5069                                        } else if resource_panel.max_size.is_some()
5070                                            && size[0] >= resource_panel.max_size.unwrap()[0]
5071                                        {
5072                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
5073                                        } else {
5074                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
5075                                        };
5076                                    };
5077                                }
5078                                [true, false, true, false] => {
5079                                    match [resource_panel.resizable[0], resource_panel.resizable[2]]
5080                                    {
5081                                        [true, true] => {
5082                                            if resource_panel.last_frame_mouse_status.is_none()
5083                                                && ui.input(|i| i.pointer.primary_pressed())
5084                                            {
5085                                                resource_panel.last_frame_mouse_status = Some((
5086                                                    mouse_pos.into(),
5087                                                    ClickAim::LeftTopResize,
5088                                                    [
5089                                                        mouse_pos.x - position[0],
5090                                                        mouse_pos.y - position[1],
5091                                                    ],
5092                                                ))
5093                                            };
5094                                            if size[0] > resource_panel.min_size[0]
5095                                                && (resource_panel.max_size.is_none()
5096                                                    || size[0]
5097                                                        < resource_panel.max_size.unwrap()[0])
5098                                                || size[1] > resource_panel.min_size[1]
5099                                                    && (resource_panel.max_size.is_none()
5100                                                        || size[1]
5101                                                            < resource_panel.max_size.unwrap()[1])
5102                                            {
5103                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5104                                            } else if resource_panel.max_size.is_some()
5105                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5106                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5107                                            {
5108                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
5109                                            } else {
5110                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
5111                                            };
5112                                        }
5113                                        [false, true] => {
5114                                            if resource_panel.last_frame_mouse_status.is_none()
5115                                                && ui.input(|i| i.pointer.primary_pressed())
5116                                            {
5117                                                resource_panel.last_frame_mouse_status = Some((
5118                                                    mouse_pos.into(),
5119                                                    ClickAim::LeftResize,
5120                                                    [
5121                                                        mouse_pos.x - position[0],
5122                                                        mouse_pos.y - position[1],
5123                                                    ],
5124                                                ))
5125                                            };
5126                                            if size[0] > resource_panel.min_size[0]
5127                                                && (resource_panel.max_size.is_none()
5128                                                    || size[0]
5129                                                        < resource_panel.max_size.unwrap()[0])
5130                                            {
5131                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5132                                            } else if resource_panel.max_size.is_some()
5133                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5134                                            {
5135                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
5136                                            } else {
5137                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
5138                                            };
5139                                        }
5140                                        [true, false] => {
5141                                            if resource_panel.last_frame_mouse_status.is_none()
5142                                                && ui.input(|i| i.pointer.primary_pressed())
5143                                            {
5144                                                resource_panel.last_frame_mouse_status = Some((
5145                                                    mouse_pos.into(),
5146                                                    ClickAim::TopResize,
5147                                                    [
5148                                                        mouse_pos.x - position[0],
5149                                                        mouse_pos.y - position[1],
5150                                                    ],
5151                                                ))
5152                                            };
5153                                            if size[1] > resource_panel.min_size[1]
5154                                                && (resource_panel.max_size.is_none()
5155                                                    || size[1]
5156                                                        < resource_panel.max_size.unwrap()[1])
5157                                            {
5158                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5159                                            } else if resource_panel.max_size.is_some()
5160                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5161                                            {
5162                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5163                                            } else {
5164                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5165                                            };
5166                                        }
5167                                        [false, false] => {}
5168                                    }
5169                                }
5170                                [false, true, false, true] => {
5171                                    match [resource_panel.resizable[1], resource_panel.resizable[3]]
5172                                    {
5173                                        [true, true] => {
5174                                            if resource_panel.last_frame_mouse_status.is_none()
5175                                                && ui.input(|i| i.pointer.primary_pressed())
5176                                            {
5177                                                resource_panel.last_frame_mouse_status = Some((
5178                                                    mouse_pos.into(),
5179                                                    ClickAim::RightBottomResize,
5180                                                    [
5181                                                        mouse_pos.x - position[0],
5182                                                        mouse_pos.y - position[1],
5183                                                    ],
5184                                                ))
5185                                            };
5186                                            if size[0] > resource_panel.min_size[0]
5187                                                && (resource_panel.max_size.is_none()
5188                                                    || size[0]
5189                                                        < resource_panel.max_size.unwrap()[0])
5190                                                || size[1] > resource_panel.min_size[1]
5191                                                    && (resource_panel.max_size.is_none()
5192                                                        || size[1]
5193                                                            < resource_panel.max_size.unwrap()[1])
5194                                            {
5195                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5196                                            } else if resource_panel.max_size.is_some()
5197                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5198                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5199                                            {
5200                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
5201                                            } else {
5202                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
5203                                            };
5204                                        }
5205                                        [false, true] => {
5206                                            if resource_panel.last_frame_mouse_status.is_none()
5207                                                && ui.input(|i| i.pointer.primary_pressed())
5208                                            {
5209                                                resource_panel.last_frame_mouse_status = Some((
5210                                                    mouse_pos.into(),
5211                                                    ClickAim::RightResize,
5212                                                    [
5213                                                        mouse_pos.x - position[0],
5214                                                        mouse_pos.y - position[1],
5215                                                    ],
5216                                                ))
5217                                            };
5218                                            if size[0] > resource_panel.min_size[0]
5219                                                && (resource_panel.max_size.is_none()
5220                                                    || size[0]
5221                                                        < resource_panel.max_size.unwrap()[0])
5222                                            {
5223                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5224                                            } else if resource_panel.max_size.is_some()
5225                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5226                                            {
5227                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
5228                                            } else {
5229                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
5230                                            };
5231                                        }
5232                                        [true, false] => {
5233                                            if resource_panel.last_frame_mouse_status.is_none()
5234                                                && ui.input(|i| i.pointer.primary_pressed())
5235                                            {
5236                                                resource_panel.last_frame_mouse_status = Some((
5237                                                    mouse_pos.into(),
5238                                                    ClickAim::BottomResize,
5239                                                    [
5240                                                        mouse_pos.x - position[0],
5241                                                        mouse_pos.y - position[1],
5242                                                    ],
5243                                                ))
5244                                            };
5245                                            if size[1] > resource_panel.min_size[1]
5246                                                && (resource_panel.max_size.is_none()
5247                                                    || size[1]
5248                                                        < resource_panel.max_size.unwrap()[1])
5249                                            {
5250                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5251                                            } else if resource_panel.max_size.is_some()
5252                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5253                                            {
5254                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5255                                            } else {
5256                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5257                                            };
5258                                        }
5259                                        [false, false] => {}
5260                                    }
5261                                }
5262                                [true, false, false, true] => {
5263                                    match [resource_panel.resizable[0], resource_panel.resizable[3]]
5264                                    {
5265                                        [true, true] => {
5266                                            if resource_panel.last_frame_mouse_status.is_none()
5267                                                && ui.input(|i| i.pointer.primary_pressed())
5268                                            {
5269                                                resource_panel.last_frame_mouse_status = Some((
5270                                                    mouse_pos.into(),
5271                                                    ClickAim::RightTopResize,
5272                                                    [
5273                                                        mouse_pos.x - position[0],
5274                                                        mouse_pos.y - position[1],
5275                                                    ],
5276                                                ))
5277                                            };
5278                                            if size[0] > resource_panel.min_size[0]
5279                                                && (resource_panel.max_size.is_none()
5280                                                    || size[0]
5281                                                        < resource_panel.max_size.unwrap()[0])
5282                                                || size[1] > resource_panel.min_size[1]
5283                                                    && (resource_panel.max_size.is_none()
5284                                                        || size[1]
5285                                                            < resource_panel.max_size.unwrap()[1])
5286                                            {
5287                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5288                                            } else if resource_panel.max_size.is_some()
5289                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5290                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5291                                            {
5292                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5293                                            } else {
5294                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5295                                            };
5296                                        }
5297                                        [false, true] => {
5298                                            if resource_panel.last_frame_mouse_status.is_none()
5299                                                && ui.input(|i| i.pointer.primary_pressed())
5300                                            {
5301                                                resource_panel.last_frame_mouse_status = Some((
5302                                                    mouse_pos.into(),
5303                                                    ClickAim::RightResize,
5304                                                    [
5305                                                        mouse_pos.x - position[0],
5306                                                        mouse_pos.y - position[1],
5307                                                    ],
5308                                                ))
5309                                            };
5310                                            if size[0] > resource_panel.min_size[0]
5311                                                && (resource_panel.max_size.is_none()
5312                                                    || size[0]
5313                                                        < resource_panel.max_size.unwrap()[0])
5314                                            {
5315                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5316                                            } else if resource_panel.max_size.is_some()
5317                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5318                                            {
5319                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
5320                                            } else {
5321                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
5322                                            };
5323                                        }
5324                                        [true, false] => {
5325                                            if resource_panel.last_frame_mouse_status.is_none()
5326                                                && ui.input(|i| i.pointer.primary_pressed())
5327                                            {
5328                                                resource_panel.last_frame_mouse_status = Some((
5329                                                    mouse_pos.into(),
5330                                                    ClickAim::TopResize,
5331                                                    [
5332                                                        mouse_pos.x - position[0],
5333                                                        mouse_pos.y - position[1],
5334                                                    ],
5335                                                ))
5336                                            };
5337                                            if size[1] > resource_panel.min_size[1]
5338                                                && (resource_panel.max_size.is_none()
5339                                                    || size[1]
5340                                                        < resource_panel.max_size.unwrap()[1])
5341                                            {
5342                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5343                                            } else if resource_panel.max_size.is_some()
5344                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5345                                            {
5346                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5347                                            } else {
5348                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5349                                            };
5350                                        }
5351                                        [false, false] => {}
5352                                    }
5353                                }
5354                                [false, true, true, false] => {
5355                                    match [resource_panel.resizable[1], resource_panel.resizable[2]]
5356                                    {
5357                                        [true, true] => {
5358                                            if resource_panel.last_frame_mouse_status.is_none()
5359                                                && ui.input(|i| i.pointer.primary_pressed())
5360                                            {
5361                                                resource_panel.last_frame_mouse_status = Some((
5362                                                    mouse_pos.into(),
5363                                                    ClickAim::LeftBottomResize,
5364                                                    [
5365                                                        mouse_pos.x - position[0],
5366                                                        mouse_pos.y - position[1],
5367                                                    ],
5368                                                ))
5369                                            };
5370                                            if size[0] > resource_panel.min_size[0]
5371                                                && (resource_panel.max_size.is_none()
5372                                                    || size[0]
5373                                                        < resource_panel.max_size.unwrap()[0])
5374                                                || size[1] > resource_panel.min_size[1]
5375                                                    && (resource_panel.max_size.is_none()
5376                                                        || size[1]
5377                                                            < resource_panel.max_size.unwrap()[1])
5378                                            {
5379                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5380                                            } else if resource_panel.max_size.is_some()
5381                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5382                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5383                                            {
5384                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5385                                            } else {
5386                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5387                                            };
5388                                        }
5389                                        [false, true] => {
5390                                            if resource_panel.last_frame_mouse_status.is_none()
5391                                                && ui.input(|i| i.pointer.primary_pressed())
5392                                            {
5393                                                resource_panel.last_frame_mouse_status = Some((
5394                                                    mouse_pos.into(),
5395                                                    ClickAim::LeftResize,
5396                                                    [
5397                                                        mouse_pos.x - position[0],
5398                                                        mouse_pos.y - position[1],
5399                                                    ],
5400                                                ))
5401                                            };
5402                                            if size[0] > resource_panel.min_size[0]
5403                                                && (resource_panel.max_size.is_none()
5404                                                    || size[0]
5405                                                        < resource_panel.max_size.unwrap()[0])
5406                                            {
5407                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5408                                            } else if resource_panel.max_size.is_some()
5409                                                && size[0] >= resource_panel.max_size.unwrap()[0]
5410                                            {
5411                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
5412                                            } else {
5413                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
5414                                            };
5415                                        }
5416                                        [true, false] => {
5417                                            if resource_panel.last_frame_mouse_status.is_none()
5418                                                && ui.input(|i| i.pointer.primary_pressed())
5419                                            {
5420                                                resource_panel.last_frame_mouse_status = Some((
5421                                                    mouse_pos.into(),
5422                                                    ClickAim::BottomResize,
5423                                                    [
5424                                                        mouse_pos.x - position[0],
5425                                                        mouse_pos.y - position[1],
5426                                                    ],
5427                                                ))
5428                                            };
5429                                            if size[1] > resource_panel.min_size[1]
5430                                                && (resource_panel.max_size.is_none()
5431                                                    || size[1]
5432                                                        < resource_panel.max_size.unwrap()[1])
5433                                            {
5434                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5435                                            } else if resource_panel.max_size.is_some()
5436                                                && size[1] >= resource_panel.max_size.unwrap()[1]
5437                                            {
5438                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5439                                            } else {
5440                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5441                                            };
5442                                        }
5443                                        [false, false] => {}
5444                                    }
5445                                }
5446                                _ => {}
5447                            };
5448                            resource_panel.last_frame_mouse_status =
5449                                if resource_panel.last_frame_mouse_status.is_none()
5450                                    && rect.contains(mouse_pos)
5451                                    && ui.input(|i| i.pointer.primary_pressed())
5452                                {
5453                                    Some((
5454                                        [mouse_pos.x, mouse_pos.y],
5455                                        ClickAim::Move,
5456                                        [mouse_pos.x - position[0], mouse_pos.y - position[1]],
5457                                    ))
5458                                } else if resource_panel.last_frame_mouse_status.is_some()
5459                                    && !ui.input(|i| i.pointer.primary_released())
5460                                {
5461                                    Some((
5462                                        [mouse_pos.x, mouse_pos.y],
5463                                        resource_panel.last_frame_mouse_status.unwrap().1,
5464                                        resource_panel.last_frame_mouse_status.unwrap().2,
5465                                    ))
5466                                } else {
5467                                    None
5468                                };
5469                            if resource_panel.scroll_length_method[0].is_some()
5470                                && x_scroll_delta != 0_f32
5471                                && rect.contains(mouse_pos)
5472                            {
5473                                resource_panel.scrolled[0] = true;
5474                                resource_panel.scroll_progress[0] = if resource_panel
5475                                    .scroll_progress[0]
5476                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
5477                                    > resource_panel.scroll_length[0]
5478                                {
5479                                    resource_panel.scroll_length[0]
5480                                } else if resource_panel.scroll_progress[0]
5481                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
5482                                    > 0_f32
5483                                {
5484                                    resource_panel.scroll_progress[0]
5485                                        + -x_scroll_delta * resource_panel.scroll_sensitivity
5486                                } else {
5487                                    0_f32
5488                                };
5489                            };
5490                            if resource_panel.scroll_length_method[1].is_some()
5491                                && y_scroll_delta != 0_f32
5492                                && rect.contains(mouse_pos)
5493                            {
5494                                resource_panel.scrolled[1] = true;
5495                                resource_panel.scroll_progress[1] = if resource_panel
5496                                    .scroll_progress[1]
5497                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
5498                                    > resource_panel.scroll_length[1]
5499                                {
5500                                    resource_panel.scroll_length[1]
5501                                } else if resource_panel.scroll_progress[1]
5502                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
5503                                    > 0_f32
5504                                {
5505                                    resource_panel.scroll_progress[1]
5506                                        + -y_scroll_delta * resource_panel.scroll_sensitivity
5507                                } else {
5508                                    0_f32
5509                                };
5510                            };
5511                        } else if ui.input(|i| i.pointer.primary_released()) {
5512                            resource_panel.last_frame_mouse_status = None;
5513                        };
5514                    };
5515                    if let Some((mouse_pos, click_aim, offset)) =
5516                        resource_panel.last_frame_mouse_status
5517                    {
5518                        match click_aim {
5519                            ClickAim::LeftTopResize => {
5520                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5521                                    && (resource_panel.max_size.is_none()
5522                                        || position[0] - mouse_pos[0] + size[0]
5523                                            < resource_panel.max_size.unwrap()[0])
5524                                {
5525                                    position_size_config.origin_size[0] +=
5526                                        position[0] - mouse_pos[0];
5527                                    position_size_config.origin_position[0] = mouse_pos[0];
5528                                } else if resource_panel.max_size.is_some()
5529                                    && position[0] - mouse_pos[0] + size[0]
5530                                        >= resource_panel.max_size.unwrap()[0]
5531                                {
5532                                    position_size_config.origin_position[0] -=
5533                                        resource_panel.max_size.unwrap()[0]
5534                                            - position_size_config.origin_size[0];
5535                                    position_size_config.origin_size[0] =
5536                                        resource_panel.max_size.unwrap()[0];
5537                                } else {
5538                                    position_size_config.origin_position[0] += position_size_config
5539                                        .origin_size[0]
5540                                        - resource_panel.min_size[0];
5541                                    position_size_config.origin_size[0] =
5542                                        resource_panel.min_size[0];
5543                                };
5544                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5545                                    && (resource_panel.max_size.is_none()
5546                                        || position[1] - mouse_pos[1] + size[1]
5547                                            < resource_panel.max_size.unwrap()[1])
5548                                {
5549                                    position_size_config.origin_size[1] +=
5550                                        position[1] - mouse_pos[1];
5551                                    position_size_config.origin_position[1] = mouse_pos[1];
5552                                } else if resource_panel.max_size.is_some()
5553                                    && position[1] - mouse_pos[1] + size[1]
5554                                        >= resource_panel.max_size.unwrap()[1]
5555                                {
5556                                    position_size_config.origin_position[1] -=
5557                                        resource_panel.max_size.unwrap()[1]
5558                                            - position_size_config.origin_size[1];
5559                                    position_size_config.origin_size[1] =
5560                                        resource_panel.max_size.unwrap()[1];
5561                                } else {
5562                                    position_size_config.origin_position[1] += position_size_config
5563                                        .origin_size[1]
5564                                        - resource_panel.min_size[1];
5565                                    position_size_config.origin_size[1] =
5566                                        resource_panel.min_size[1];
5567                                };
5568                                if size[0] > resource_panel.min_size[0]
5569                                    && (resource_panel.max_size.is_none()
5570                                        || size[0] < resource_panel.max_size.unwrap()[0])
5571                                    || size[1] > resource_panel.min_size[1]
5572                                        && (resource_panel.max_size.is_none()
5573                                            || size[1] < resource_panel.max_size.unwrap()[1])
5574                                {
5575                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5576                                } else if resource_panel.max_size.is_some()
5577                                    && size[0] >= resource_panel.max_size.unwrap()[0]
5578                                    && size[1] >= resource_panel.max_size.unwrap()[1]
5579                                {
5580                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
5581                                } else {
5582                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
5583                                };
5584                            }
5585                            ClickAim::RightBottomResize => {
5586                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5587                                    && (resource_panel.max_size.is_none()
5588                                        || mouse_pos[0] - position[0]
5589                                            < resource_panel.max_size.unwrap()[0])
5590                                {
5591                                    position_size_config.origin_size[0] =
5592                                        mouse_pos[0] - position[0];
5593                                } else if resource_panel.max_size.is_some()
5594                                    && mouse_pos[0] - position[0]
5595                                        >= resource_panel.max_size.unwrap()[0]
5596                                {
5597                                    position_size_config.origin_size[0] =
5598                                        resource_panel.max_size.unwrap()[0];
5599                                } else {
5600                                    position_size_config.origin_size[0] =
5601                                        resource_panel.min_size[0];
5602                                };
5603                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5604                                    && (resource_panel.max_size.is_none()
5605                                        || mouse_pos[1] - position[1]
5606                                            < resource_panel.max_size.unwrap()[1])
5607                                {
5608                                    position_size_config.origin_size[1] =
5609                                        mouse_pos[1] - position[1];
5610                                } else if resource_panel.max_size.is_some()
5611                                    && mouse_pos[1] - position[1]
5612                                        >= resource_panel.max_size.unwrap()[1]
5613                                {
5614                                    position_size_config.origin_size[1] =
5615                                        resource_panel.max_size.unwrap()[1];
5616                                } else {
5617                                    position_size_config.origin_size[1] =
5618                                        resource_panel.min_size[1];
5619                                };
5620                                if size[0] > resource_panel.min_size[0]
5621                                    && (resource_panel.max_size.is_none()
5622                                        || size[0] < resource_panel.max_size.unwrap()[0])
5623                                    || size[1] > resource_panel.min_size[1]
5624                                        && (resource_panel.max_size.is_none()
5625                                            || size[1] < resource_panel.max_size.unwrap()[1])
5626                                {
5627                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
5628                                } else if resource_panel.max_size.is_some()
5629                                    && size[0] >= resource_panel.max_size.unwrap()[0]
5630                                    && size[1] >= resource_panel.max_size.unwrap()[1]
5631                                {
5632                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
5633                                } else {
5634                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
5635                                };
5636                            }
5637                            ClickAim::RightTopResize => {
5638                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5639                                    && (resource_panel.max_size.is_none()
5640                                        || mouse_pos[0] - position[0]
5641                                            < resource_panel.max_size.unwrap()[0])
5642                                {
5643                                    position_size_config.origin_size[0] =
5644                                        mouse_pos[0] - position[0];
5645                                } else if resource_panel.max_size.is_some()
5646                                    && mouse_pos[0] - position[0]
5647                                        >= resource_panel.max_size.unwrap()[0]
5648                                {
5649                                    position_size_config.origin_size[0] =
5650                                        resource_panel.max_size.unwrap()[0];
5651                                } else {
5652                                    position_size_config.origin_size[0] =
5653                                        resource_panel.min_size[0];
5654                                };
5655                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5656                                    && (resource_panel.max_size.is_none()
5657                                        || position[1] - mouse_pos[1] + size[1]
5658                                            < resource_panel.max_size.unwrap()[1])
5659                                {
5660                                    position_size_config.origin_size[1] +=
5661                                        position[1] - mouse_pos[1];
5662                                    position_size_config.origin_position[1] = mouse_pos[1];
5663                                } else if resource_panel.max_size.is_some()
5664                                    && position[1] - mouse_pos[1] + size[1]
5665                                        >= resource_panel.max_size.unwrap()[1]
5666                                {
5667                                    position_size_config.origin_position[1] -=
5668                                        resource_panel.max_size.unwrap()[1]
5669                                            - position_size_config.origin_size[1];
5670                                    position_size_config.origin_size[1] =
5671                                        resource_panel.max_size.unwrap()[1];
5672                                } else {
5673                                    position_size_config.origin_position[1] += position_size_config
5674                                        .origin_size[1]
5675                                        - resource_panel.min_size[1];
5676                                    position_size_config.origin_size[1] =
5677                                        resource_panel.min_size[1];
5678                                };
5679                                if size[0] > resource_panel.min_size[0]
5680                                    && (resource_panel.max_size.is_none()
5681                                        || size[0] < resource_panel.max_size.unwrap()[0])
5682                                    || size[1] > resource_panel.min_size[1]
5683                                        && (resource_panel.max_size.is_none()
5684                                            || size[1] < resource_panel.max_size.unwrap()[1])
5685                                {
5686                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5687                                } else if resource_panel.max_size.is_some()
5688                                    && size[0] >= resource_panel.max_size.unwrap()[0]
5689                                    && size[1] >= resource_panel.max_size.unwrap()[1]
5690                                {
5691                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
5692                                } else {
5693                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
5694                                };
5695                            }
5696                            ClickAim::LeftBottomResize => {
5697                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5698                                    && (resource_panel.max_size.is_none()
5699                                        || position[0] - mouse_pos[0] + size[0]
5700                                            < resource_panel.max_size.unwrap()[0])
5701                                {
5702                                    position_size_config.origin_size[0] +=
5703                                        position[0] - mouse_pos[0];
5704                                    position_size_config.origin_position[0] = mouse_pos[0];
5705                                } else if resource_panel.max_size.is_some()
5706                                    && position[0] - mouse_pos[0] + size[0]
5707                                        >= resource_panel.max_size.unwrap()[0]
5708                                {
5709                                    position_size_config.origin_position[0] -=
5710                                        resource_panel.max_size.unwrap()[0]
5711                                            - position_size_config.origin_size[0];
5712                                    position_size_config.origin_size[0] =
5713                                        resource_panel.max_size.unwrap()[0];
5714                                } else {
5715                                    position_size_config.origin_position[0] += position_size_config
5716                                        .origin_size[0]
5717                                        - resource_panel.min_size[0];
5718                                    position_size_config.origin_size[0] =
5719                                        resource_panel.min_size[0];
5720                                };
5721                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5722                                    && (resource_panel.max_size.is_none()
5723                                        || mouse_pos[1] - position[1]
5724                                            < resource_panel.max_size.unwrap()[1])
5725                                {
5726                                    position_size_config.origin_size[1] =
5727                                        mouse_pos[1] - position[1];
5728                                } else if resource_panel.max_size.is_some()
5729                                    && mouse_pos[1] - position[1]
5730                                        >= resource_panel.max_size.unwrap()[1]
5731                                {
5732                                    position_size_config.origin_size[1] =
5733                                        resource_panel.max_size.unwrap()[1];
5734                                } else {
5735                                    position_size_config.origin_size[1] =
5736                                        resource_panel.min_size[1];
5737                                };
5738                                if size[0] > resource_panel.min_size[0]
5739                                    && (resource_panel.max_size.is_none()
5740                                        || size[0] < resource_panel.max_size.unwrap()[0])
5741                                    || size[1] > resource_panel.min_size[1]
5742                                        && (resource_panel.max_size.is_none()
5743                                            || size[1] < resource_panel.max_size.unwrap()[1])
5744                                {
5745                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
5746                                } else if resource_panel.max_size.is_some()
5747                                    && size[0] >= resource_panel.max_size.unwrap()[0]
5748                                    && size[1] >= resource_panel.max_size.unwrap()[1]
5749                                {
5750                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
5751                                } else {
5752                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
5753                                };
5754                            }
5755                            ClickAim::TopResize => {
5756                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
5757                                    && (resource_panel.max_size.is_none()
5758                                        || position[1] - mouse_pos[1] + size[1]
5759                                            < resource_panel.max_size.unwrap()[1])
5760                                {
5761                                    position_size_config.origin_size[1] +=
5762                                        position[1] - mouse_pos[1];
5763                                    position_size_config.origin_position[1] = mouse_pos[1];
5764                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5765                                } else if resource_panel.max_size.is_some()
5766                                    && position[1] - mouse_pos[1] + size[1]
5767                                        >= resource_panel.max_size.unwrap()[1]
5768                                {
5769                                    position_size_config.origin_position[1] -=
5770                                        resource_panel.max_size.unwrap()[1]
5771                                            - position_size_config.origin_size[1];
5772                                    position_size_config.origin_size[1] =
5773                                        resource_panel.max_size.unwrap()[1];
5774                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5775                                } else {
5776                                    position_size_config.origin_position[1] += position_size_config
5777                                        .origin_size[1]
5778                                        - resource_panel.min_size[1];
5779                                    position_size_config.origin_size[1] =
5780                                        resource_panel.min_size[1];
5781                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5782                                };
5783                            }
5784                            ClickAim::BottomResize => {
5785                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
5786                                    && (resource_panel.max_size.is_none()
5787                                        || mouse_pos[1] - position[1]
5788                                            < resource_panel.max_size.unwrap()[1])
5789                                {
5790                                    position_size_config.origin_size[1] =
5791                                        mouse_pos[1] - position[1];
5792                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
5793                                } else if resource_panel.max_size.is_some()
5794                                    && mouse_pos[1] - position[1]
5795                                        >= resource_panel.max_size.unwrap()[1]
5796                                {
5797                                    position_size_config.origin_size[1] =
5798                                        resource_panel.max_size.unwrap()[1];
5799                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
5800                                } else {
5801                                    position_size_config.origin_size[1] =
5802                                        resource_panel.min_size[1];
5803                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
5804                                };
5805                            }
5806                            ClickAim::LeftResize => {
5807                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
5808                                    && (resource_panel.max_size.is_none()
5809                                        || position[0] - mouse_pos[0] + size[0]
5810                                            < resource_panel.max_size.unwrap()[0])
5811                                {
5812                                    position_size_config.origin_size[0] +=
5813                                        position[0] - mouse_pos[0];
5814                                    position_size_config.origin_position[0] = mouse_pos[0];
5815                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5816                                } else if resource_panel.max_size.is_some()
5817                                    && position[0] - mouse_pos[0] + size[0]
5818                                        >= resource_panel.max_size.unwrap()[0]
5819                                {
5820                                    position_size_config.origin_position[0] -=
5821                                        resource_panel.max_size.unwrap()[0]
5822                                            - position_size_config.origin_size[0];
5823                                    position_size_config.origin_size[0] =
5824                                        resource_panel.max_size.unwrap()[0];
5825                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
5826                                } else {
5827                                    position_size_config.origin_position[0] += position_size_config
5828                                        .origin_size[0]
5829                                        - resource_panel.min_size[0];
5830                                    position_size_config.origin_size[0] =
5831                                        resource_panel.min_size[0];
5832                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
5833                                };
5834                            }
5835                            ClickAim::RightResize => {
5836                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
5837                                    && (resource_panel.max_size.is_none()
5838                                        || mouse_pos[0] - position[0]
5839                                            < resource_panel.max_size.unwrap()[0])
5840                                {
5841                                    position_size_config.origin_size[0] =
5842                                        mouse_pos[0] - position[0];
5843                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
5844                                } else if resource_panel.max_size.is_some()
5845                                    && mouse_pos[0] - position[0]
5846                                        >= resource_panel.max_size.unwrap()[0]
5847                                {
5848                                    position_size_config.origin_size[0] =
5849                                        resource_panel.max_size.unwrap()[0];
5850                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
5851                                } else {
5852                                    position_size_config.origin_size[0] =
5853                                        resource_panel.min_size[0];
5854                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
5855                                };
5856                            }
5857                            ClickAim::Move => {
5858                                if resource_panel.movable[0] {
5859                                    position_size_config.origin_position[0] =
5860                                        mouse_pos[0] - offset[0];
5861                                };
5862                                if resource_panel.movable[1] {
5863                                    position_size_config.origin_position[1] =
5864                                        mouse_pos[1] - offset[1];
5865                                };
5866                            }
5867                        };
5868                    };
5869                    [position, size] = self.position_size_processor(position_size_config, ctx);
5870                    let background_type = match background.background_type.clone() {
5871                        BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
5872                            config
5873                                .position_size_config(Some(position_size_config))
5874                                .hidden(Some(resource_panel.hidden)),
5875                        ),
5876                        BackgroundType::Image(config) => BackgroundType::Image(
5877                            config
5878                                .position_size_config(Some(position_size_config))
5879                                .hidden(Some(resource_panel.hidden)),
5880                        ),
5881                    };
5882                    self.replace_resource(
5883                        &format!("{name}Background"),
5884                        background.clone().background_type(&background_type).clone(),
5885                    )?;
5886                    self.use_resource(
5887                        &format!("{name}Background"),
5888                        "rust_constructor::Background",
5889                        ui,
5890                        ctx,
5891                    )?;
5892                    let mut resource_point_list: Vec<([f32; 2], [f32; 2], [bool; 2])> = Vec::new();
5893                    let mut use_resource_list = Vec::new();
5894                    let mut replace_resource_list = Vec::new();
5895                    for rcr in &self.rust_constructor_resource {
5896                        if self
5897                            .basic_front_resource_list
5898                            .contains(&rcr.id.discern_type)
5899                            && let Some(panel_name) =
5900                                self.get_tag("panel_name", &rcr.content.display_tags())
5901                            && panel_name.1 == name
5902                        {
5903                            if let [Some(citer_name), Some(citer_type)] = [
5904                                self.get_tag("citer_name", &rcr.content.display_tags()),
5905                                self.get_tag("citer_type", &rcr.content.display_tags()),
5906                            ] {
5907                                if !use_resource_list
5908                                    .iter()
5909                                    .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
5910                                {
5911                                    use_resource_list.push([citer_name.1, citer_type.1]);
5912                                };
5913                            } else if !use_resource_list
5914                                .iter()
5915                                .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
5916                            {
5917                                use_resource_list
5918                                    .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
5919                            };
5920                            let mut basic_front_resource: Box<dyn BasicFrontResource> = match &*rcr
5921                                .id
5922                                .discern_type
5923                            {
5924                                "rust_constructor::Image" => Box::new(
5925                                    rcr.content
5926                                        .as_any()
5927                                        .downcast_ref::<Image>()
5928                                        .unwrap()
5929                                        .clone(),
5930                                ),
5931                                "rust_constructor::Text" => Box::new(
5932                                    rcr.content.as_any().downcast_ref::<Text>().unwrap().clone(),
5933                                ),
5934                                "rust_constructor::CustomRect" => Box::new(
5935                                    rcr.content
5936                                        .as_any()
5937                                        .downcast_ref::<CustomRect>()
5938                                        .unwrap()
5939                                        .clone(),
5940                                ),
5941                                _ => {
5942                                    unreachable!()
5943                                }
5944                            };
5945                            if !resource_panel
5946                                .resource_storage
5947                                .iter()
5948                                .any(|x| x.id == rcr.id)
5949                            {
5950                                resource_panel.resource_storage.push(PanelStorage {
5951                                    id: rcr.id.clone(),
5952                                    ignore_render_layer: if let Some(display_info) =
5953                                        basic_front_resource.display_display_info()
5954                                    {
5955                                        display_info.ignore_render_layer
5956                                    } else {
5957                                        false
5958                                    },
5959                                    hidden: if let Some(display_info) =
5960                                        basic_front_resource.display_display_info()
5961                                    {
5962                                        display_info.hidden
5963                                    } else {
5964                                        false
5965                                    },
5966                                    origin_size: basic_front_resource
5967                                        .display_position_size_config()
5968                                        .origin_size,
5969                                });
5970                            };
5971                            let enable_scrolling = [
5972                                self.get_tag("disable_x_scrolling", &rcr.content.display_tags())
5973                                    .is_none(),
5974                                self.get_tag("disable_y_scrolling", &rcr.content.display_tags())
5975                                    .is_none(),
5976                            ];
5977                            let offset = basic_front_resource.display_position_size_config().offset;
5978                            basic_front_resource.modify_position_size_config(
5979                                basic_front_resource
5980                                    .display_position_size_config()
5981                                    .x_location_grid(0_f32, 0_f32)
5982                                    .y_location_grid(0_f32, 0_f32)
5983                                    .x_size_grid(0_f32, 0_f32)
5984                                    .y_size_grid(0_f32, 0_f32)
5985                                    .offset(
5986                                        if enable_scrolling[0] {
5987                                            -resource_panel.scroll_progress[0]
5988                                        } else {
5989                                            offset[0]
5990                                        },
5991                                        if enable_scrolling[1] {
5992                                            -resource_panel.scroll_progress[1]
5993                                        } else {
5994                                            offset[1]
5995                                        },
5996                                    ),
5997                            );
5998                            match resource_panel.layout.panel_margin {
5999                                PanelMargin::Vertical(
6000                                    [top, bottom, left, right],
6001                                    move_to_bottom,
6002                                ) => {
6003                                    let mut modify_y = 0_f32;
6004                                    let [default_x_position, default_y_position] =
6005                                        match resource_panel.layout.panel_location {
6006                                            PanelLocation::Absolute([x, y]) => {
6007                                                [position[0] + x, position[1] + y]
6008                                            }
6009                                            PanelLocation::Relative([x, y]) => [
6010                                                position[0] + (size[0] / x[1] as f32 * x[0] as f32),
6011                                                position[1] + (size[1] / y[1] as f32 * y[0] as f32),
6012                                            ],
6013                                        };
6014                                    let default_x_position = match basic_front_resource
6015                                        .display_position_size_config()
6016                                        .display_method
6017                                        .0
6018                                    {
6019                                        HorizontalAlign::Left => default_x_position,
6020                                        HorizontalAlign::Center => {
6021                                            default_x_position
6022                                                - basic_front_resource.display_size()[0] / 2.0
6023                                        }
6024                                        HorizontalAlign::Right => {
6025                                            default_x_position
6026                                                - basic_front_resource.display_size()[0]
6027                                        }
6028                                    };
6029                                    let default_y_position = match basic_front_resource
6030                                        .display_position_size_config()
6031                                        .display_method
6032                                        .1
6033                                    {
6034                                        VerticalAlign::Top => default_y_position,
6035                                        VerticalAlign::Center => {
6036                                            default_y_position
6037                                                - basic_front_resource.display_size()[1] / 2.0
6038                                        }
6039                                        VerticalAlign::Bottom => {
6040                                            default_y_position
6041                                                - basic_front_resource.display_size()[1]
6042                                        }
6043                                    };
6044                                    for point in &resource_point_list {
6045                                        if default_x_position - left < point.1[0]
6046                                            && default_y_position - top + modify_y < point.1[1]
6047                                            && default_x_position
6048                                                + basic_front_resource.display_size()[0]
6049                                                + right
6050                                                > point.0[0]
6051                                            && default_y_position
6052                                                + basic_front_resource.display_size()[1]
6053                                                + bottom
6054                                                + modify_y
6055                                                > point.0[1]
6056                                        {
6057                                            if move_to_bottom
6058                                                && point.1[1] - default_y_position + top > modify_y
6059                                            {
6060                                                modify_y = point.1[1] - default_y_position + top;
6061                                            } else if !move_to_bottom
6062                                                && point.0[1]
6063                                                    - default_y_position
6064                                                    - basic_front_resource.display_size()[1]
6065                                                    - bottom
6066                                                    < modify_y
6067                                            {
6068                                                modify_y = point.0[1]
6069                                                    - default_y_position
6070                                                    - basic_front_resource.display_size()[1]
6071                                                    - bottom;
6072                                            };
6073                                        };
6074                                    }
6075                                    let real_x_position = match basic_front_resource
6076                                        .display_position_size_config()
6077                                        .display_method
6078                                        .0
6079                                    {
6080                                        HorizontalAlign::Left => default_x_position,
6081                                        HorizontalAlign::Center => {
6082                                            default_x_position
6083                                                + basic_front_resource.display_size()[0] / 2.0
6084                                        }
6085                                        HorizontalAlign::Right => {
6086                                            default_x_position
6087                                                + basic_front_resource.display_size()[0]
6088                                        }
6089                                    };
6090                                    let real_y_position = match basic_front_resource
6091                                        .display_position_size_config()
6092                                        .display_method
6093                                        .1
6094                                    {
6095                                        VerticalAlign::Top => default_y_position + modify_y,
6096                                        VerticalAlign::Center => {
6097                                            default_y_position
6098                                                + modify_y
6099                                                + basic_front_resource.display_size()[1] / 2.0
6100                                        }
6101                                        VerticalAlign::Bottom => {
6102                                            default_y_position
6103                                                + modify_y
6104                                                + basic_front_resource.display_size()[1]
6105                                        }
6106                                    };
6107                                    let default_storage = if let Some(resource_storage) =
6108                                        resource_panel
6109                                            .resource_storage
6110                                            .iter()
6111                                            .find(|x| x.id == rcr.id)
6112                                    {
6113                                        (true, resource_storage.origin_size)
6114                                    } else {
6115                                        (false, [0_f32, 0_f32])
6116                                    };
6117                                    basic_front_resource.modify_position_size_config(
6118                                        basic_front_resource
6119                                            .display_position_size_config()
6120                                            .origin_size(
6121                                                if basic_front_resource.display_position()[0]
6122                                                    < position[0] + size[0]
6123                                                {
6124                                                    if resource_panel.auto_shrink[0]
6125                                                        && basic_front_resource
6126                                                            .display_position_size_config()
6127                                                            .origin_size[0]
6128                                                            > position_size_config.origin_size[0]
6129                                                                - (basic_front_resource
6130                                                                    .display_position()[0]
6131                                                                    - position[0])
6132                                                                - right
6133                                                    {
6134                                                        position_size_config.origin_size[0]
6135                                                            - (basic_front_resource
6136                                                                .display_position()[0]
6137                                                                - position[0])
6138                                                            - right
6139                                                    } else if default_storage.0 {
6140                                                        if default_storage.1[0]
6141                                                            > position_size_config.origin_size[0]
6142                                                                - (basic_front_resource
6143                                                                    .display_position()[0]
6144                                                                    - position[0])
6145                                                                - right
6146                                                        {
6147                                                            position_size_config.origin_size[0]
6148                                                                - (basic_front_resource
6149                                                                    .display_position()[0]
6150                                                                    - position[0])
6151                                                                - right
6152                                                        } else {
6153                                                            default_storage.1[0]
6154                                                        }
6155                                                    } else {
6156                                                        basic_front_resource
6157                                                            .display_position_size_config()
6158                                                            .origin_size[0]
6159                                                    }
6160                                                } else {
6161                                                    0_f32
6162                                                },
6163                                                if basic_front_resource.display_position()[1]
6164                                                    < position[1] + size[1]
6165                                                {
6166                                                    if resource_panel.auto_shrink[1]
6167                                                        && basic_front_resource
6168                                                            .display_position_size_config()
6169                                                            .origin_size[1]
6170                                                            > position_size_config.origin_size[1]
6171                                                                - (basic_front_resource
6172                                                                    .display_position()[1]
6173                                                                    - position[1])
6174                                                                - bottom
6175                                                    {
6176                                                        position_size_config.origin_size[1]
6177                                                            - (basic_front_resource
6178                                                                .display_position()[1]
6179                                                                - position[1])
6180                                                            - bottom
6181                                                    } else if default_storage.0 {
6182                                                        if default_storage.1[1]
6183                                                            > position_size_config.origin_size[1]
6184                                                                - (basic_front_resource
6185                                                                    .display_position()[1]
6186                                                                    - position[1])
6187                                                                - bottom
6188                                                        {
6189                                                            position_size_config.origin_size[1]
6190                                                                - (basic_front_resource
6191                                                                    .display_position()[1]
6192                                                                    - position[1])
6193                                                                - bottom
6194                                                        } else {
6195                                                            default_storage.1[1]
6196                                                        }
6197                                                    } else {
6198                                                        basic_front_resource
6199                                                            .display_position_size_config()
6200                                                            .origin_size[1]
6201                                                    }
6202                                                } else {
6203                                                    0_f32
6204                                                },
6205                                            )
6206                                            .origin_position(real_x_position, real_y_position),
6207                                    );
6208                                    replace_resource_list.push((
6209                                        basic_front_resource.display_position_size_config(),
6210                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
6211                                    ));
6212                                    resource_point_list.push((
6213                                        [real_x_position - left, real_y_position - top],
6214                                        [
6215                                            real_x_position
6216                                                + basic_front_resource.display_size()[0]
6217                                                + right,
6218                                            real_y_position
6219                                                + basic_front_resource.display_size()[1]
6220                                                + bottom,
6221                                        ],
6222                                        enable_scrolling,
6223                                    ));
6224                                }
6225                                PanelMargin::Horizontal(
6226                                    [top, bottom, left, right],
6227                                    move_to_right,
6228                                ) => {
6229                                    let mut modify_x = 0_f32;
6230                                    let [default_x_position, default_y_position] =
6231                                        match resource_panel.layout.panel_location {
6232                                            PanelLocation::Absolute([x, y]) => {
6233                                                [position[0] + x, position[1] + y]
6234                                            }
6235                                            PanelLocation::Relative([x, y]) => [
6236                                                position[0] + (size[0] / x[1] as f32 * x[0] as f32),
6237                                                position[1] + (size[1] / y[1] as f32 * y[0] as f32),
6238                                            ],
6239                                        };
6240                                    let default_x_position = match basic_front_resource
6241                                        .display_position_size_config()
6242                                        .display_method
6243                                        .0
6244                                    {
6245                                        HorizontalAlign::Left => default_x_position,
6246                                        HorizontalAlign::Center => {
6247                                            default_x_position
6248                                                - basic_front_resource.display_size()[0] / 2.0
6249                                        }
6250                                        HorizontalAlign::Right => {
6251                                            default_x_position
6252                                                - basic_front_resource.display_size()[0]
6253                                        }
6254                                    };
6255                                    let default_y_position = match basic_front_resource
6256                                        .display_position_size_config()
6257                                        .display_method
6258                                        .1
6259                                    {
6260                                        VerticalAlign::Top => default_y_position,
6261                                        VerticalAlign::Center => {
6262                                            default_y_position
6263                                                - basic_front_resource.display_size()[1] / 2.0
6264                                        }
6265                                        VerticalAlign::Bottom => {
6266                                            default_y_position
6267                                                - basic_front_resource.display_size()[1]
6268                                        }
6269                                    };
6270                                    for point in &resource_point_list {
6271                                        if default_x_position - left + modify_x < point.1[0]
6272                                            && default_y_position - top < point.1[1]
6273                                            && default_x_position
6274                                                + basic_front_resource.display_size()[0]
6275                                                + right
6276                                                + modify_x
6277                                                > point.0[0]
6278                                            && default_y_position
6279                                                + basic_front_resource.display_size()[1]
6280                                                + bottom
6281                                                > point.0[1]
6282                                        {
6283                                            if move_to_right
6284                                                && point.1[0] - default_x_position + left > modify_x
6285                                            {
6286                                                modify_x = point.1[0] - default_x_position + left;
6287                                            } else if !move_to_right
6288                                                && point.0[0]
6289                                                    - default_x_position
6290                                                    - basic_front_resource.display_size()[0]
6291                                                    - right
6292                                                    < modify_x
6293                                            {
6294                                                modify_x = point.0[0]
6295                                                    - default_x_position
6296                                                    - basic_front_resource.display_size()[0]
6297                                                    - right;
6298                                            };
6299                                        };
6300                                    }
6301                                    let real_x_position = match basic_front_resource
6302                                        .display_position_size_config()
6303                                        .display_method
6304                                        .0
6305                                    {
6306                                        HorizontalAlign::Left => default_x_position + modify_x,
6307                                        HorizontalAlign::Center => {
6308                                            default_x_position
6309                                                + modify_x
6310                                                + basic_front_resource.display_size()[0] / 2.0
6311                                        }
6312                                        HorizontalAlign::Right => {
6313                                            default_x_position
6314                                                + modify_x
6315                                                + basic_front_resource.display_size()[0]
6316                                        }
6317                                    };
6318                                    let real_y_position = match basic_front_resource
6319                                        .display_position_size_config()
6320                                        .display_method
6321                                        .1
6322                                    {
6323                                        VerticalAlign::Top => default_y_position,
6324                                        VerticalAlign::Center => {
6325                                            default_y_position
6326                                                + basic_front_resource.display_size()[1] / 2.0
6327                                        }
6328                                        VerticalAlign::Bottom => {
6329                                            default_y_position
6330                                                + basic_front_resource.display_size()[1]
6331                                        }
6332                                    };
6333                                    let default_storage = if let Some(resource_storage) =
6334                                        resource_panel
6335                                            .resource_storage
6336                                            .iter()
6337                                            .find(|x| x.id == rcr.id)
6338                                    {
6339                                        (true, resource_storage.origin_size)
6340                                    } else {
6341                                        (false, [0_f32, 0_f32])
6342                                    };
6343                                    basic_front_resource.modify_position_size_config(
6344                                        basic_front_resource
6345                                            .display_position_size_config()
6346                                            .origin_size(
6347                                                if basic_front_resource.display_position()[0]
6348                                                    < position[0] + size[0]
6349                                                {
6350                                                    if resource_panel.auto_shrink[0]
6351                                                        && basic_front_resource
6352                                                            .display_position_size_config()
6353                                                            .origin_size[0]
6354                                                            > position_size_config.origin_size[0]
6355                                                                - (basic_front_resource
6356                                                                    .display_position()[0]
6357                                                                    - position[0])
6358                                                                - right
6359                                                    {
6360                                                        position_size_config.origin_size[0]
6361                                                            - (basic_front_resource
6362                                                                .display_position()[0]
6363                                                                - position[0])
6364                                                            - right
6365                                                    } else if default_storage.0 {
6366                                                        if default_storage.1[0]
6367                                                            > position_size_config.origin_size[0]
6368                                                                - (basic_front_resource
6369                                                                    .display_position()[0]
6370                                                                    - position[0])
6371                                                                - right
6372                                                        {
6373                                                            position_size_config.origin_size[0]
6374                                                                - (basic_front_resource
6375                                                                    .display_position()[0]
6376                                                                    - position[0])
6377                                                                - right
6378                                                        } else {
6379                                                            default_storage.1[0]
6380                                                        }
6381                                                    } else {
6382                                                        basic_front_resource
6383                                                            .display_position_size_config()
6384                                                            .origin_size[0]
6385                                                    }
6386                                                } else {
6387                                                    0_f32
6388                                                },
6389                                                if basic_front_resource.display_position()[1]
6390                                                    < position[1] + size[1]
6391                                                {
6392                                                    if resource_panel.auto_shrink[1]
6393                                                        && basic_front_resource
6394                                                            .display_position_size_config()
6395                                                            .origin_size[1]
6396                                                            > position_size_config.origin_size[1]
6397                                                                - (basic_front_resource
6398                                                                    .display_position()[1]
6399                                                                    - position[1])
6400                                                                - bottom
6401                                                    {
6402                                                        position_size_config.origin_size[1]
6403                                                            - (basic_front_resource
6404                                                                .display_position()[1]
6405                                                                - position[1])
6406                                                            - bottom
6407                                                    } else if default_storage.0 {
6408                                                        if default_storage.1[1]
6409                                                            > position_size_config.origin_size[1]
6410                                                                - (basic_front_resource
6411                                                                    .display_position()[1]
6412                                                                    - position[1])
6413                                                                - bottom
6414                                                        {
6415                                                            position_size_config.origin_size[1]
6416                                                                - (basic_front_resource
6417                                                                    .display_position()[1]
6418                                                                    - position[1])
6419                                                                - bottom
6420                                                        } else {
6421                                                            default_storage.1[1]
6422                                                        }
6423                                                    } else {
6424                                                        basic_front_resource
6425                                                            .display_position_size_config()
6426                                                            .origin_size[1]
6427                                                    }
6428                                                } else {
6429                                                    0_f32
6430                                                },
6431                                            )
6432                                            .origin_position(real_x_position, real_y_position),
6433                                    );
6434                                    replace_resource_list.push((
6435                                        basic_front_resource.display_position_size_config(),
6436                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
6437                                    ));
6438                                    resource_point_list.push((
6439                                        [real_x_position - left, real_y_position - top],
6440                                        [
6441                                            real_x_position
6442                                                + basic_front_resource.display_size()[0]
6443                                                + right,
6444                                            real_y_position
6445                                                + basic_front_resource.display_size()[1]
6446                                                + bottom,
6447                                        ],
6448                                        enable_scrolling,
6449                                    ));
6450                                }
6451                                PanelMargin::None([top, bottom, left, right], influence_layout) => {
6452                                    let [default_x_position, default_y_position] =
6453                                        match resource_panel.layout.panel_location {
6454                                            PanelLocation::Absolute([x, y]) => {
6455                                                [position[0] + x, position[1] + y]
6456                                            }
6457                                            PanelLocation::Relative([x, y]) => [
6458                                                position[0] + (size[0] / x[1] as f32 * x[0] as f32),
6459                                                position[1] + (size[1] / y[1] as f32 * y[0] as f32),
6460                                            ],
6461                                        };
6462                                    let default_storage = if let Some(resource_storage) =
6463                                        resource_panel
6464                                            .resource_storage
6465                                            .iter()
6466                                            .find(|x| x.id == rcr.id)
6467                                    {
6468                                        (true, resource_storage.origin_size)
6469                                    } else {
6470                                        (false, [0_f32, 0_f32])
6471                                    };
6472                                    basic_front_resource.modify_position_size_config(
6473                                        basic_front_resource
6474                                            .display_position_size_config()
6475                                            .origin_size(
6476                                                if basic_front_resource.display_position()[0]
6477                                                    < position[0] + size[0]
6478                                                {
6479                                                    if resource_panel.auto_shrink[0]
6480                                                        && basic_front_resource
6481                                                            .display_position_size_config()
6482                                                            .origin_size[0]
6483                                                            > position_size_config.origin_size[0]
6484                                                                - (basic_front_resource
6485                                                                    .display_position()[0]
6486                                                                    - position[0])
6487                                                                - right
6488                                                    {
6489                                                        position_size_config.origin_size[0]
6490                                                            - (basic_front_resource
6491                                                                .display_position()[0]
6492                                                                - position[0])
6493                                                            - right
6494                                                    } else if default_storage.0 {
6495                                                        if default_storage.1[0]
6496                                                            > position_size_config.origin_size[0]
6497                                                                - (basic_front_resource
6498                                                                    .display_position()[0]
6499                                                                    - position[0])
6500                                                                - right
6501                                                        {
6502                                                            position_size_config.origin_size[0]
6503                                                                - (basic_front_resource
6504                                                                    .display_position()[0]
6505                                                                    - position[0])
6506                                                                - right
6507                                                        } else {
6508                                                            default_storage.1[0]
6509                                                        }
6510                                                    } else {
6511                                                        basic_front_resource
6512                                                            .display_position_size_config()
6513                                                            .origin_size[0]
6514                                                    }
6515                                                } else {
6516                                                    0_f32
6517                                                },
6518                                                if basic_front_resource.display_position()[1]
6519                                                    < position[1] + size[1]
6520                                                {
6521                                                    if resource_panel.auto_shrink[1]
6522                                                        && basic_front_resource
6523                                                            .display_position_size_config()
6524                                                            .origin_size[1]
6525                                                            > position_size_config.origin_size[1]
6526                                                                - (basic_front_resource
6527                                                                    .display_position()[1]
6528                                                                    - position[1])
6529                                                                - bottom
6530                                                    {
6531                                                        position_size_config.origin_size[1]
6532                                                            - (basic_front_resource
6533                                                                .display_position()[1]
6534                                                                - position[1])
6535                                                            - bottom
6536                                                    } else if default_storage.0 {
6537                                                        if default_storage.1[1]
6538                                                            > position_size_config.origin_size[1]
6539                                                                - (basic_front_resource
6540                                                                    .display_position()[1]
6541                                                                    - position[1])
6542                                                                - bottom
6543                                                        {
6544                                                            position_size_config.origin_size[1]
6545                                                                - (basic_front_resource
6546                                                                    .display_position()[1]
6547                                                                    - position[1])
6548                                                                - bottom
6549                                                        } else {
6550                                                            default_storage.1[1]
6551                                                        }
6552                                                    } else {
6553                                                        basic_front_resource
6554                                                            .display_position_size_config()
6555                                                            .origin_size[1]
6556                                                    }
6557                                                } else {
6558                                                    0_f32
6559                                                },
6560                                            )
6561                                            .origin_position(
6562                                                default_x_position,
6563                                                default_y_position,
6564                                            ),
6565                                    );
6566                                    replace_resource_list.push((
6567                                        basic_front_resource.display_position_size_config(),
6568                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
6569                                    ));
6570                                    if influence_layout {
6571                                        resource_point_list.push((
6572                                            [default_x_position - left, default_y_position - top],
6573                                            [
6574                                                default_x_position
6575                                                    + basic_front_resource.display_size()[0]
6576                                                    + right,
6577                                                default_y_position
6578                                                    + basic_front_resource.display_size()[1]
6579                                                    + bottom,
6580                                            ],
6581                                            enable_scrolling,
6582                                        ));
6583                                    };
6584                                }
6585                            };
6586                        };
6587                    }
6588                    for (new_position_size_config, [name, discern_type]) in replace_resource_list {
6589                        let default_storage = if let Some(resource_storage) =
6590                            resource_panel.resource_storage.iter().find(|x| {
6591                                x.id == RustConstructorId {
6592                                    name: name.clone(),
6593                                    discern_type: discern_type.clone(),
6594                                }
6595                            }) {
6596                            [
6597                                true,
6598                                resource_storage.ignore_render_layer,
6599                                resource_storage.hidden,
6600                            ]
6601                        } else {
6602                            [false, true, true]
6603                        };
6604                        match &*discern_type {
6605                            "rust_constructor::CustomRect" => {
6606                                let mut custom_rect = self
6607                                    .get_resource::<CustomRect>(&name, &discern_type)?
6608                                    .clone();
6609                                custom_rect.basic_front_resource_config.position_size_config =
6610                                    new_position_size_config;
6611                                custom_rect.display_info.ignore_render_layer = if resource_panel
6612                                    .last_frame_mouse_status
6613                                    .is_some()
6614                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
6615                                {
6616                                    true
6617                                } else if default_storage[0] {
6618                                    default_storage[1]
6619                                } else {
6620                                    custom_rect.display_info.ignore_render_layer
6621                                };
6622                                custom_rect.basic_front_resource_config.clip_rect =
6623                                    Some(position_size_config);
6624                                custom_rect.display_info.hidden = if resource_panel.hidden {
6625                                    true
6626                                } else if default_storage[0] {
6627                                    default_storage[2]
6628                                } else {
6629                                    custom_rect.display_info.hidden
6630                                };
6631                                self.replace_resource(&name, custom_rect)?;
6632                            }
6633                            "rust_constructor::Image" => {
6634                                let mut image =
6635                                    self.get_resource::<Image>(&name, &discern_type)?.clone();
6636                                image.basic_front_resource_config.position_size_config =
6637                                    new_position_size_config;
6638                                image.display_info.ignore_render_layer = if resource_panel
6639                                    .last_frame_mouse_status
6640                                    .is_some()
6641                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
6642                                {
6643                                    true
6644                                } else if default_storage[0] {
6645                                    default_storage[1]
6646                                } else {
6647                                    image.display_info.ignore_render_layer
6648                                };
6649                                image.basic_front_resource_config.clip_rect =
6650                                    Some(position_size_config);
6651                                image.display_info.hidden = resource_panel.hidden;
6652                                self.replace_resource(&name, image)?;
6653                            }
6654                            "rust_constructor::Text" => {
6655                                let mut text =
6656                                    self.get_resource::<Text>(&name, &discern_type)?.clone();
6657                                text.basic_front_resource_config.position_size_config =
6658                                    new_position_size_config;
6659                                text.display_info.ignore_render_layer = if resource_panel
6660                                    .last_frame_mouse_status
6661                                    .is_some()
6662                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
6663                                {
6664                                    true
6665                                } else if default_storage[0] {
6666                                    default_storage[1]
6667                                } else {
6668                                    text.display_info.ignore_render_layer
6669                                };
6670                                text.auto_fit = [false, false];
6671                                text.basic_front_resource_config.clip_rect =
6672                                    Some(position_size_config);
6673                                text.display_info.hidden = resource_panel.hidden;
6674                                self.replace_resource(&name, text)?;
6675                            }
6676                            _ => unreachable!(),
6677                        }
6678                    }
6679                    for info in use_resource_list {
6680                        self.use_resource(&info[0], &info[1], ui, ctx)?;
6681                    }
6682                    if let Some(horizontal_scroll_length_method) =
6683                        resource_panel.scroll_length_method[0]
6684                    {
6685                        resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
6686                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6687                            ScrollLengthMethod::AutoFit(expand) => {
6688                                let mut length = -background_resource.display_size()[0];
6689                                match resource_panel.layout.panel_margin {
6690                                    PanelMargin::Horizontal(_, _) => {
6691                                        for storage in &resource_panel.resource_storage {
6692                                            length += storage.origin_size[0];
6693                                        }
6694                                    }
6695                                    PanelMargin::Vertical(_, _) | PanelMargin::None(_, _) => {
6696                                        for storage in &resource_panel.resource_storage {
6697                                            length = if storage.origin_size[0]
6698                                                - background_resource.display_size()[0]
6699                                                > length
6700                                            {
6701                                                storage.origin_size[0]
6702                                                    - background_resource.display_size()[0]
6703                                            } else {
6704                                                length
6705                                            };
6706                                        }
6707                                    }
6708                                }
6709                                if length >= 0_f32 {
6710                                    length + expand.abs()
6711                                } else {
6712                                    0_f32
6713                                }
6714                            }
6715                        };
6716                        if resource_panel.scroll_progress[0] > resource_panel.scroll_length[0] {
6717                            resource_panel.scroll_progress[0] = resource_panel.scroll_length[0];
6718                        };
6719                    };
6720                    if let Some(vertical_scroll_length_method) =
6721                        resource_panel.scroll_length_method[1]
6722                    {
6723                        resource_panel.scroll_length[1] = match vertical_scroll_length_method {
6724                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
6725                            ScrollLengthMethod::AutoFit(expand) => {
6726                                let mut length = -background_resource.display_size()[1];
6727                                match resource_panel.layout.panel_margin {
6728                                    PanelMargin::Vertical(_, _) => {
6729                                        for storage in &resource_panel.resource_storage {
6730                                            length += storage.origin_size[1];
6731                                        }
6732                                    }
6733                                    PanelMargin::Horizontal(_, _) | PanelMargin::None(_, _) => {
6734                                        for storage in &resource_panel.resource_storage {
6735                                            length = if storage.origin_size[1]
6736                                                - background_resource.display_size()[1]
6737                                                > length
6738                                            {
6739                                                storage.origin_size[1]
6740                                                    - background_resource.display_size()[1]
6741                                            } else {
6742                                                length
6743                                            };
6744                                        }
6745                                    }
6746                                }
6747                                if length >= 0_f32 {
6748                                    length + expand.abs()
6749                                } else {
6750                                    0_f32
6751                                }
6752                            }
6753                        };
6754                        if resource_panel.scroll_progress[1] > resource_panel.scroll_length[1] {
6755                            resource_panel.scroll_progress[1] = resource_panel.scroll_length[1];
6756                        };
6757                    };
6758                    match resource_panel.scroll_bar_display_method {
6759                        ScrollBarDisplayMethod::Always(ref config, margin, width) => {
6760                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6761                                (size[0] - margin[0] * 2_f32)
6762                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6763                            } else {
6764                                (size[0] - width - margin[1] - margin[0] * 2_f32)
6765                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6766                            };
6767                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6768                                position[0]
6769                                    + margin[0]
6770                                    + (size[0] - margin[0] * 2_f32 - line_length)
6771                                        * (resource_panel.scroll_progress[0]
6772                                            / resource_panel.scroll_length[0])
6773                            } else {
6774                                position[0]
6775                                    + margin[0]
6776                                    + (size[0]
6777                                        - margin[0] * 2_f32
6778                                        - width
6779                                        - margin[1]
6780                                        - line_length)
6781                                        * (resource_panel.scroll_progress[0]
6782                                            / resource_panel.scroll_length[0])
6783                            };
6784                            self.replace_resource(
6785                                &format!("{name}XScroll"),
6786                                background.clone().background_type(&match config.clone() {
6787                                    BackgroundType::CustomRect(config) => {
6788                                        BackgroundType::CustomRect(
6789                                            config
6790                                                .ignore_render_layer(Some(true))
6791                                                .hidden(Some(resource_panel.hidden))
6792                                                .position_size_config(Some(
6793                                                    PositionSizeConfig::default()
6794                                                        .display_method(
6795                                                            HorizontalAlign::Left,
6796                                                            VerticalAlign::Bottom,
6797                                                        )
6798                                                        .origin_position(
6799                                                            line_position,
6800                                                            position[1] + size[1] - margin[1],
6801                                                        )
6802                                                        .origin_size(line_length, width),
6803                                                )),
6804                                        )
6805                                    }
6806                                    BackgroundType::Image(config) => BackgroundType::Image(
6807                                        config
6808                                            .ignore_render_layer(Some(true))
6809                                            .hidden(Some(resource_panel.hidden))
6810                                            .position_size_config(Some(
6811                                                PositionSizeConfig::default()
6812                                                    .display_method(
6813                                                        HorizontalAlign::Left,
6814                                                        VerticalAlign::Bottom,
6815                                                    )
6816                                                    .origin_position(
6817                                                        line_position,
6818                                                        position[1] + size[1] - margin[1],
6819                                                    )
6820                                                    .origin_size(line_length, width),
6821                                            )),
6822                                    ),
6823                                }),
6824                            )?;
6825                            self.use_resource(
6826                                &format!("{name}XScroll"),
6827                                "rust_constructor::Background",
6828                                ui,
6829                                ctx,
6830                            )?;
6831                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
6832                                (size[1] - margin[0] * 2_f32)
6833                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6834                            } else {
6835                                (size[1] - width - margin[1] - margin[0] * 2_f32)
6836                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
6837                            };
6838                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
6839                                position[1]
6840                                    + margin[0]
6841                                    + (size[1] - margin[0] * 2_f32 - line_length)
6842                                        * (resource_panel.scroll_progress[1]
6843                                            / resource_panel.scroll_length[1])
6844                            } else {
6845                                position[1]
6846                                    + margin[0]
6847                                    + (size[1]
6848                                        - margin[0] * 2_f32
6849                                        - width
6850                                        - margin[1]
6851                                        - line_length)
6852                                        * (resource_panel.scroll_progress[1]
6853                                            / resource_panel.scroll_length[1])
6854                            };
6855                            self.replace_resource(
6856                                &format!("{name}YScroll"),
6857                                background.background_type(&match config.clone() {
6858                                    BackgroundType::CustomRect(config) => {
6859                                        BackgroundType::CustomRect(
6860                                            config
6861                                                .ignore_render_layer(Some(true))
6862                                                .hidden(Some(resource_panel.hidden))
6863                                                .position_size_config(Some(
6864                                                    PositionSizeConfig::default()
6865                                                        .display_method(
6866                                                            HorizontalAlign::Right,
6867                                                            VerticalAlign::Top,
6868                                                        )
6869                                                        .origin_position(
6870                                                            position[0] + size[0] - margin[1],
6871                                                            line_position,
6872                                                        )
6873                                                        .origin_size(width, line_length),
6874                                                )),
6875                                        )
6876                                    }
6877                                    BackgroundType::Image(config) => BackgroundType::Image(
6878                                        config
6879                                            .ignore_render_layer(Some(true))
6880                                            .hidden(Some(resource_panel.hidden))
6881                                            .position_size_config(Some(
6882                                                PositionSizeConfig::default()
6883                                                    .display_method(
6884                                                        HorizontalAlign::Right,
6885                                                        VerticalAlign::Top,
6886                                                    )
6887                                                    .origin_position(
6888                                                        position[0] + size[0] - margin[1],
6889                                                        line_position,
6890                                                    )
6891                                                    .origin_size(width, line_length),
6892                                            )),
6893                                    ),
6894                                }),
6895                            )?;
6896                            self.use_resource(
6897                                &format!("{name}YScroll"),
6898                                "rust_constructor::Background",
6899                                ui,
6900                                ctx,
6901                            )?;
6902                        }
6903                        ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
6904                            resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
6905                                self.reset_split_time(&format!("{name}ScrollBarXAlphaStart"))?;
6906                                255
6907                            } else if self.timer.now_time
6908                                - self.get_split_time(&format!("{name}ScrollBarXAlphaStart"))?[0]
6909                                >= 1_f32
6910                                && self.timer.now_time
6911                                    - self.get_split_time(&format!("{name}ScrollBarXAlpha"))?[0]
6912                                    >= self.tick_interval
6913                            {
6914                                self.reset_split_time(&format!("{name}ScrollBarXAlpha"))?;
6915                                resource_panel.scroll_bar_alpha[0].saturating_sub(10)
6916                            } else {
6917                                resource_panel.scroll_bar_alpha[0]
6918                            };
6919                            resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
6920                                self.reset_split_time(&format!("{name}ScrollBarYAlphaStart"))?;
6921                                255
6922                            } else if self.timer.now_time
6923                                - self.get_split_time(&format!("{name}ScrollBarYAlphaStart"))?[0]
6924                                >= 1_f32
6925                                && self.timer.now_time
6926                                    - self.get_split_time(&format!("{name}ScrollBarYAlpha"))?[0]
6927                                    >= self.tick_interval
6928                            {
6929                                self.reset_split_time(&format!("{name}ScrollBarYAlpha"))?;
6930                                resource_panel.scroll_bar_alpha[1].saturating_sub(10)
6931                            } else {
6932                                resource_panel.scroll_bar_alpha[1]
6933                            };
6934                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
6935                                (size[0] - margin[0] * 2_f32)
6936                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6937                            } else {
6938                                (size[0] - width - margin[1] - margin[0] * 2_f32)
6939                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
6940                            };
6941                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
6942                                position[0]
6943                                    + margin[0]
6944                                    + (size[0] - margin[0] * 2_f32 - line_length)
6945                                        * (resource_panel.scroll_progress[0]
6946                                            / resource_panel.scroll_length[0])
6947                            } else {
6948                                position[0]
6949                                    + margin[0]
6950                                    + (size[0]
6951                                        - margin[0] * 2_f32
6952                                        - width
6953                                        - margin[1]
6954                                        - line_length)
6955                                        * (resource_panel.scroll_progress[0]
6956                                            / resource_panel.scroll_length[0])
6957                            };
6958                            self.replace_resource(
6959                                &format!("{name}XScroll"),
6960                                background.clone().background_type(&match config.clone() {
6961                                    BackgroundType::CustomRect(config) => {
6962                                        BackgroundType::CustomRect(
6963                                            config
6964                                                .ignore_render_layer(Some(true))
6965                                                .hidden(Some(resource_panel.hidden))
6966                                                .position_size_config(Some(
6967                                                    PositionSizeConfig::default()
6968                                                        .display_method(
6969                                                            HorizontalAlign::Left,
6970                                                            VerticalAlign::Bottom,
6971                                                        )
6972                                                        .origin_position(
6973                                                            line_position,
6974                                                            position[1] + size[1] - margin[1],
6975                                                        )
6976                                                        .origin_size(line_length, width),
6977                                                ))
6978                                                .alpha(Some(resource_panel.scroll_bar_alpha[0]))
6979                                                .border_alpha(Some(
6980                                                    resource_panel.scroll_bar_alpha[0],
6981                                                )),
6982                                        )
6983                                    }
6984                                    BackgroundType::Image(config) => BackgroundType::Image(
6985                                        config
6986                                            .ignore_render_layer(Some(true))
6987                                            .hidden(Some(resource_panel.hidden))
6988                                            .position_size_config(Some(
6989                                                PositionSizeConfig::default()
6990                                                    .display_method(
6991                                                        HorizontalAlign::Left,
6992                                                        VerticalAlign::Bottom,
6993                                                    )
6994                                                    .origin_position(
6995                                                        line_position,
6996                                                        position[1] + size[1] - margin[1],
6997                                                    )
6998                                                    .origin_size(line_length, width),
6999                                            ))
7000                                            .alpha(Some(resource_panel.scroll_bar_alpha[0]))
7001                                            .background_alpha(Some(
7002                                                resource_panel.scroll_bar_alpha[0],
7003                                            ))
7004                                            .overlay_alpha(Some(
7005                                                resource_panel.scroll_bar_alpha[0],
7006                                            )),
7007                                    ),
7008                                }),
7009                            )?;
7010                            self.use_resource(
7011                                &format!("{name}XScroll"),
7012                                "rust_constructor::Background",
7013                                ui,
7014                                ctx,
7015                            )?;
7016                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
7017                                (size[1] - margin[0] * 2_f32)
7018                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
7019                            } else {
7020                                (size[1] - width - margin[1] - margin[0] * 2_f32)
7021                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
7022                            };
7023                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
7024                                position[1]
7025                                    + margin[0]
7026                                    + (size[1] - margin[0] * 2_f32 - line_length)
7027                                        * (resource_panel.scroll_progress[1]
7028                                            / resource_panel.scroll_length[1])
7029                            } else {
7030                                position[1]
7031                                    + margin[0]
7032                                    + (size[1]
7033                                        - margin[0] * 2_f32
7034                                        - width
7035                                        - margin[1]
7036                                        - line_length)
7037                                        * (resource_panel.scroll_progress[1]
7038                                            / resource_panel.scroll_length[1])
7039                            };
7040                            self.replace_resource(
7041                                &format!("{name}YScroll"),
7042                                background.clone().background_type(&match config.clone() {
7043                                    BackgroundType::CustomRect(config) => {
7044                                        BackgroundType::CustomRect(
7045                                            config
7046                                                .ignore_render_layer(Some(true))
7047                                                .hidden(Some(resource_panel.hidden))
7048                                                .position_size_config(Some(
7049                                                    PositionSizeConfig::default()
7050                                                        .display_method(
7051                                                            HorizontalAlign::Right,
7052                                                            VerticalAlign::Top,
7053                                                        )
7054                                                        .origin_position(
7055                                                            position[0] + size[0] - margin[1],
7056                                                            line_position,
7057                                                        )
7058                                                        .origin_size(width, line_length),
7059                                                ))
7060                                                .alpha(Some(resource_panel.scroll_bar_alpha[1]))
7061                                                .border_alpha(Some(
7062                                                    resource_panel.scroll_bar_alpha[1],
7063                                                )),
7064                                        )
7065                                    }
7066                                    BackgroundType::Image(config) => BackgroundType::Image(
7067                                        config
7068                                            .ignore_render_layer(Some(true))
7069                                            .hidden(Some(resource_panel.hidden))
7070                                            .position_size_config(Some(
7071                                                PositionSizeConfig::default()
7072                                                    .display_method(
7073                                                        HorizontalAlign::Right,
7074                                                        VerticalAlign::Top,
7075                                                    )
7076                                                    .origin_position(
7077                                                        position[0] + size[0] - margin[1],
7078                                                        line_position,
7079                                                    )
7080                                                    .origin_size(width, line_length),
7081                                            ))
7082                                            .alpha(Some(resource_panel.scroll_bar_alpha[1]))
7083                                            .background_alpha(Some(
7084                                                resource_panel.scroll_bar_alpha[1],
7085                                            ))
7086                                            .overlay_alpha(Some(
7087                                                resource_panel.scroll_bar_alpha[1],
7088                                            )),
7089                                    ),
7090                                }),
7091                            )?;
7092                            self.use_resource(
7093                                &format!("{name}YScroll"),
7094                                "rust_constructor::Background",
7095                                ui,
7096                                ctx,
7097                            )?;
7098                        }
7099                        ScrollBarDisplayMethod::Hidden => {}
7100                    };
7101                    self.replace_resource(name, resource_panel.clone())?;
7102                }
7103                _ => {}
7104            };
7105            Ok(())
7106        } else {
7107            Err(RustConstructorError {
7108                error_id: "ResourceNotFound".to_string(),
7109                description: format!("Resource \"{name}({discern_type})\" not found."),
7110            })
7111        }
7112    }
7113
7114    /// 切换页面。
7115    pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
7116        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
7117        page_data.enter_page_updated = false;
7118        self.timer.start_time = self.timer.total_time;
7119        self.current_page = name.to_string();
7120        self.update_timer();
7121        Ok(())
7122    }
7123
7124    /// 输出字体资源。
7125    pub fn get_font(&self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
7126        let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
7127        Ok(font.font_definitions.clone())
7128    }
7129
7130    /// 将所有已添加到RC的字体资源添加到egui中。
7131    pub fn register_all_fonts(&self, ctx: &Context) {
7132        let mut font_definitions_amount = FontDefinitions::default();
7133        let mut fonts = Vec::new();
7134        for i in 0..self.rust_constructor_resource.len() {
7135            if let Some(font) = self.rust_constructor_resource[i]
7136                .content
7137                .as_any()
7138                .downcast_ref::<Font>()
7139            {
7140                fonts.push((
7141                    self.rust_constructor_resource[i].id.name.clone(),
7142                    font.font_definitions.clone(),
7143                ));
7144            };
7145        }
7146        for i in &fonts {
7147            // 从 font_def 中提取对应字体的 Arc<FontData>
7148            if let Some(font_data) = i.1.font_data.get(&i.0) {
7149                font_definitions_amount
7150                    .font_data
7151                    .insert(i.0.clone(), Arc::clone(font_data));
7152                font_definitions_amount
7153                    .families
7154                    .entry(FontFamily::Name(i.0.clone().into()))
7155                    .or_default()
7156                    .push(i.0.clone());
7157            };
7158
7159            // 将字体添加到字体列表中
7160            font_definitions_amount
7161                .families
7162                .entry(FontFamily::Proportional)
7163                .or_default()
7164                .insert(0, i.0.to_owned());
7165
7166            font_definitions_amount
7167                .families
7168                .entry(FontFamily::Monospace)
7169                .or_default()
7170                .insert(0, i.0.to_owned());
7171        }
7172        ctx.set_fonts(font_definitions_amount);
7173    }
7174
7175    /// 处理最基本的位置计算。
7176    pub fn position_size_processor(
7177        &self,
7178        position_size_config: PositionSizeConfig,
7179        ctx: &Context,
7180    ) -> [[f32; 2]; 2] {
7181        let mut position = [0_f32, 0_f32];
7182        let mut size = [0_f32, 0_f32];
7183        size[0] = match position_size_config.x_size_grid[0] {
7184            0_f32 => position_size_config.origin_size[0],
7185            _ => {
7186                (ctx.available_rect().width() / position_size_config.x_size_grid[1]
7187                    * position_size_config.x_size_grid[0])
7188                    + position_size_config.origin_size[0]
7189            }
7190        };
7191        size[1] = match position_size_config.y_size_grid[0] {
7192            0_f32 => position_size_config.origin_size[1],
7193            _ => {
7194                (ctx.available_rect().height() / position_size_config.y_size_grid[1]
7195                    * position_size_config.y_size_grid[0])
7196                    + position_size_config.origin_size[1]
7197            }
7198        };
7199        position[0] = match position_size_config.x_location_grid[1] {
7200            0_f32 => position_size_config.origin_position[0],
7201            _ => {
7202                (ctx.available_rect().width() / position_size_config.x_location_grid[1]
7203                    * position_size_config.x_location_grid[0])
7204                    + position_size_config.origin_position[0]
7205            }
7206        };
7207        position[1] = match position_size_config.y_location_grid[1] {
7208            0_f32 => position_size_config.origin_position[1],
7209            _ => {
7210                (ctx.available_rect().height() / position_size_config.y_location_grid[1]
7211                    * position_size_config.y_location_grid[0])
7212                    + position_size_config.origin_position[1]
7213            }
7214        };
7215        match position_size_config.display_method.0 {
7216            HorizontalAlign::Left => {}
7217            HorizontalAlign::Center => position[0] -= size[0] / 2.0,
7218            HorizontalAlign::Right => position[0] -= size[0],
7219        };
7220        match position_size_config.display_method.1 {
7221            VerticalAlign::Top => {}
7222            VerticalAlign::Center => position[1] -= size[1] / 2.0,
7223            VerticalAlign::Bottom => position[1] -= size[1],
7224        };
7225        position[0] += position_size_config.offset[0];
7226        position[1] += position_size_config.offset[1];
7227        [position, size]
7228    }
7229
7230    /// 检查页面是否已完成首次加载。
7231    pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
7232        let page_data = self
7233            .get_resource::<PageData>(name, "rust_constructor::PageData")?
7234            .clone();
7235        if !page_data.change_page_updated {
7236            self.new_page_update(name)?;
7237        };
7238        Ok(page_data.change_page_updated)
7239    }
7240
7241    /// 检查页面是否已完成加载。
7242    pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
7243        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
7244        page_data.enter_page_updated = true;
7245        Ok(page_data.enter_page_updated)
7246    }
7247
7248    /// 进入新页面时的更新。
7249    pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
7250        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
7251        page_data.change_page_updated = true;
7252        self.timer.start_time = self.timer.total_time;
7253        self.update_timer();
7254        Ok(())
7255    }
7256
7257    /// 更新帧数。
7258    pub fn update_frame_stats(&mut self) {
7259        let current_time = self.timer.total_time;
7260        if let Some(last) = self.last_frame_time {
7261            let delta = current_time - last;
7262            self.frame_times.push(delta);
7263            const MAX_SAMPLES: usize = 120;
7264            if self.frame_times.len() > MAX_SAMPLES {
7265                let remove_count = self.frame_times.len() - MAX_SAMPLES;
7266                self.frame_times.drain(0..remove_count);
7267            }
7268        }
7269        self.last_frame_time = Some(current_time);
7270    }
7271
7272    /// 更新帧数显示。
7273    pub fn current_fps(&self) -> f32 {
7274        if self.frame_times.is_empty() {
7275            0.0
7276        } else {
7277            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
7278        }
7279    }
7280
7281    /// 重置分段时间。
7282    pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
7283        let new_time = [self.timer.now_time, self.timer.total_time];
7284        let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
7285        split_time.time = new_time;
7286        Ok(())
7287    }
7288
7289    /// 输出分段时间。
7290    pub fn get_split_time(&self, name: &str) -> Result<[f32; 2], RustConstructorError> {
7291        let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
7292        Ok(split_time.time)
7293    }
7294
7295    /// 更新计时器。
7296    pub fn update_timer(&mut self) {
7297        let elapsed = self.timer.timer.elapsed();
7298        let seconds = elapsed.as_secs();
7299        let milliseconds = elapsed.subsec_millis();
7300        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
7301        self.timer.now_time = self.timer.total_time - self.timer.start_time
7302    }
7303
7304    /// 修改变量资源。
7305    pub fn modify_variable<T: Debug + 'static>(
7306        &mut self,
7307        name: &str,
7308        value: Option<T>,
7309    ) -> Result<(), RustConstructorError> {
7310        let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
7311        variable.value = value;
7312        Ok(())
7313    }
7314
7315    /// 取出变量。
7316    pub fn get_variable<T: Debug + Clone + 'static>(
7317        &self,
7318        name: &str,
7319    ) -> Result<Option<T>, RustConstructorError> {
7320        if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
7321            Ok(variable.value.clone())
7322        } else if self
7323            .check_resource_exists(name, "rust_constructor::Variable")
7324            .is_none()
7325        {
7326            Err(RustConstructorError {
7327                error_id: "ResourceNotFound".to_string(),
7328                description: format!(
7329                    "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
7330                ),
7331            })
7332        } else {
7333            Err(RustConstructorError {
7334                error_id: "ResourceGenericMismatch".to_string(),
7335                description: format!(
7336                    "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
7337                ),
7338            })
7339        }
7340    }
7341
7342    /// 输出图片纹理。
7343    pub fn get_image_texture(
7344        &self,
7345        name: &str,
7346    ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
7347        let image_texture =
7348            self.get_resource::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
7349        Ok(image_texture.texture.clone())
7350    }
7351
7352    /// 重置图片纹理。
7353    pub fn reset_image_texture(
7354        &mut self,
7355        name: &str,
7356        path: &str,
7357        flip: [bool; 2],
7358        ctx: &Context,
7359    ) -> Result<(), RustConstructorError> {
7360        let image_texture =
7361            self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
7362        if let Ok(mut file) = File::open(path) {
7363            let mut buffer = Vec::new();
7364            file.read_to_end(&mut buffer).unwrap();
7365            let img_bytes = buffer;
7366            let img = image::load_from_memory(&img_bytes).unwrap();
7367            let color_data = match flip {
7368                [true, true] => img.fliph().flipv().into_rgba8(),
7369                [true, false] => img.fliph().into_rgba8(),
7370                [false, true] => img.flipv().into_rgba8(),
7371                _ => img.into_rgba8(),
7372            };
7373            let (w, h) = (color_data.width(), color_data.height());
7374            let raw_data: Vec<u8> = color_data.into_raw();
7375
7376            let color_image =
7377                ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
7378            let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
7379            image_texture.texture = Some(DebugTextureHandle::new(&texture));
7380            image_texture.cite_path = path.to_string();
7381        } else {
7382            return Err(RustConstructorError {
7383                error_id: "ImageLoadFailed".to_string(),
7384                description: format!(
7385                    "Failed to load an image from the path \"{}\".",
7386                    image_texture.cite_path
7387                ),
7388            });
7389        }
7390        Ok(())
7391    }
7392
7393    /// 修改开关的启用状态。
7394    pub fn set_switch_enable(
7395        &mut self,
7396        name: &str,
7397        enable: bool,
7398    ) -> Result<(), RustConstructorError> {
7399        let switch = self.get_resource_mut::<Switch>(name, "rust_constructor::Switch")?;
7400        switch.enable = enable;
7401        Ok(())
7402    }
7403
7404    /// 查找指定开关的常用判定字段集合。
7405    pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
7406        let switch = self.get_resource::<Switch>(name, "rust_constructor::Switch")?;
7407        Ok(SwitchData {
7408            switched: switch.switched,
7409            last_frame_clicked: switch.last_frame_clicked,
7410            state: switch.state,
7411        })
7412    }
7413}