Skip to main content

rust_constructor/
lib.rs

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