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, FontData, FontDefinitions, FontFamily, FontId, Galley, Id,
29    ImageSource, Key, OpenUrl, PointerButton, Pos2, Sense, StrokeKind, TextureHandle, Ui, Vec2,
30    text::CCursor,
31};
32use std::{
33    any::Any,
34    error::Error,
35    fmt::{Debug, Display, Formatter},
36    fs::{File, read},
37    io::Read,
38    sync::Arc,
39    time::Instant,
40    vec::Vec,
41};
42
43/// 核心特征,用于统一管理Rust Constructor资源。
44pub trait RustConstructorResource: Debug {
45    /// 返回资源名称。
46    fn name(&self) -> &str;
47
48    /// 返回资源类型。
49    fn expose_type(&self) -> &str;
50
51    /// 注册渲染的资源。
52    fn reg_render_resource(&self, render_list: &mut Vec<RenderResource>) {
53        render_list.push(RenderResource {
54            discern_type: self.expose_type().to_string(),
55            name: self.name().to_string(),
56        });
57    }
58
59    /// 用于不可变类型转换。
60    fn as_any(&self) -> &dyn Any;
61
62    /// 用于可变类型转换。
63    fn as_any_mut(&mut self) -> &mut dyn Any;
64}
65
66/// 标记并管理用于显示给用户的基本前端资源。
67pub trait BasicFrontResource: RustConstructorResource {
68    /// 获取资源尺寸。
69    fn size(&self) -> [f32; 2];
70
71    /// 获取资源位置。
72    fn position(&self) -> [f32; 2];
73
74    /// 修改资源尺寸。
75    fn modify_size(&mut self, width: f32, height: f32);
76
77    /// 修改资源位置。
78    fn modify_position(&mut self, x: f32, y: f32);
79
80    /// 通过加偏移量的方式修改资源位置。
81    fn modify_add_position(&mut self, add_x: f32, add_y: f32);
82}
83
84/// 用于配置资源位置的结构体。
85#[derive(Debug, Clone, PartialEq, PartialOrd)]
86pub struct PositionConfig {
87    /// 原始位置。
88    pub origin_position: [f32; 2],
89    /// 尺寸(可能某些资源不会使用)。
90    pub size: [f32; 2],
91    /// x轴的网格式定位。
92    pub x_grid: [u32; 2],
93    /// y轴的网格式定位(可能某些资源不会使用)。
94    pub y_grid: [u32; 2],
95    /// 对齐方法(可能某些方法不会使用)。
96    pub center_display: (HorizontalAlign, VerticalAlign),
97    /// 偏移量。
98    pub offset: [f32; 2],
99}
100
101impl Default for PositionConfig {
102    fn default() -> Self {
103        PositionConfig {
104            origin_position: [0_f32, 0_f32],
105            size: [100_f32, 100_f32],
106            x_grid: [0, 0],
107            y_grid: [0, 0],
108            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
109            offset: [0_f32, 0_f32],
110        }
111    }
112}
113
114impl PositionConfig {
115    pub fn from_image(image: Image) -> Self {
116        Self {
117            origin_position: image.origin_position,
118            size: image.size,
119            x_grid: image.x_grid,
120            y_grid: image.y_grid,
121            center_display: image.center_display,
122            offset: image.offset,
123        }
124    }
125
126    pub fn from_image_config(image_config: ImageConfig) -> Self {
127        Self {
128            origin_position: image_config.origin_position,
129            size: image_config.size,
130            x_grid: image_config.x_grid,
131            y_grid: image_config.y_grid,
132            center_display: image_config.center_display,
133            offset: image_config.offset,
134        }
135    }
136
137    pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
138        Self {
139            origin_position: custom_rect.origin_position,
140            size: custom_rect.size,
141            x_grid: custom_rect.x_grid,
142            y_grid: custom_rect.y_grid,
143            center_display: custom_rect.center_display,
144            offset: custom_rect.offset,
145        }
146    }
147
148    pub fn from_custom_rect_config(custom_rect_config: CustomRectConfig) -> Self {
149        Self {
150            origin_position: custom_rect_config.origin_position,
151            size: custom_rect_config.size,
152            x_grid: custom_rect_config.x_grid,
153            y_grid: custom_rect_config.y_grid,
154            center_display: custom_rect_config.center_display,
155            offset: custom_rect_config.offset,
156        }
157    }
158
159    pub fn from_text(text: Text) -> Self {
160        Self {
161            origin_position: text.origin_position,
162            size: text.size,
163            x_grid: text.x_grid,
164            y_grid: text.y_grid,
165            center_display: text.center_display,
166            offset: text.offset,
167        }
168    }
169
170    pub fn from_text_config(mut self, text_config: TextConfig) -> Self {
171        self.origin_position = text_config.origin_position;
172        self.size = text_config.size;
173        self.x_grid = text_config.x_grid;
174        self.y_grid = text_config.y_grid;
175        self.center_display = text_config.center_display;
176        self.offset = text_config.offset;
177        self
178    }
179
180    pub fn from_mouse_detector(mouse_detector: MouseDetector) -> Self {
181        Self {
182            origin_position: mouse_detector.origin_position,
183            size: mouse_detector.size,
184            x_grid: mouse_detector.x_grid,
185            y_grid: mouse_detector.y_grid,
186            center_display: mouse_detector.center_display,
187            offset: mouse_detector.offset,
188        }
189    }
190
191    #[inline]
192    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
193        self.origin_position = [x, y];
194        self
195    }
196
197    #[inline]
198    pub fn size(mut self, width: f32, height: f32) -> Self {
199        self.size = [width, height];
200        self
201    }
202
203    #[inline]
204    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
205        self.x_grid = [fetch, total];
206        self
207    }
208
209    #[inline]
210    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
211        self.y_grid = [fetch, total];
212        self
213    }
214
215    #[inline]
216    pub fn center_display(
217        mut self,
218        horizontal_align: HorizontalAlign,
219        vertical_align: VerticalAlign,
220    ) -> Self {
221        self.center_display = (horizontal_align, vertical_align);
222        self
223    }
224
225    #[inline]
226    pub fn offset(mut self, x: f32, y: f32) -> Self {
227        self.offset = [x, y];
228        self
229    }
230}
231
232/// 报告发生问题时的状态。
233#[derive(Debug, Clone, PartialEq, PartialOrd)]
234pub struct ReportState {
235    /// 问题发生时所在页面。
236    pub current_page: String,
237    /// 问题发生时程序总运行时间。
238    pub current_total_runtime: f32,
239    /// 问题发生时页面运行时间。
240    pub current_page_runtime: f32,
241}
242
243/// 出现问题时用于存储问题内容、状态及注释的结构体。
244#[derive(Debug, Clone, PartialEq, PartialOrd)]
245pub struct Problem {
246    /// 问题严重程度。
247    pub severity_level: SeverityLevel,
248    /// 问题描述。
249    pub problem: String,
250    /// 问题备注。
251    pub annotation: String,
252    /// 问题报告状态。
253    pub report_state: ReportState,
254    /// 问题类型。
255    pub problem_type: RustConstructorError,
256}
257
258/// 衡量问题的严重等级。
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
260pub enum SeverityLevel {
261    /// 弱警告:会影响程序正常执行,但一般情况下不会有严重后果。
262    MildWarning,
263    /// 强警告:会影响程序正常执行,且可能导致意外情况。
264    SevereWarning,
265    /// 错误:会导致程序无法运行。
266    Error,
267}
268
269/// 用于存储页面数据的RC资源。
270#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
271pub struct PageData {
272    pub discern_type: String,
273    pub name: String,
274    /// 是否强制在每帧都刷新页面。
275    pub forced_update: bool,
276    /// 是否已经加载完首次进入此页面所需内容。
277    pub change_page_updated: bool,
278    /// 是否已经加载完进入此页面所需内容。
279    pub enter_page_updated: bool,
280}
281
282impl RustConstructorResource for PageData {
283    fn name(&self) -> &str {
284        &self.name
285    }
286
287    fn expose_type(&self) -> &str {
288        &self.discern_type
289    }
290
291    fn as_any(&self) -> &dyn Any {
292        self
293    }
294
295    fn as_any_mut(&mut self) -> &mut dyn Any {
296        self
297    }
298}
299
300impl Default for PageData {
301    fn default() -> Self {
302        PageData {
303            discern_type: String::from("PageData"),
304            name: String::from("PageData"),
305            forced_update: true,
306            change_page_updated: false,
307            enter_page_updated: false,
308        }
309    }
310}
311
312impl PageData {
313    #[inline]
314    pub fn name(mut self, name: &str) -> Self {
315        self.name = name.to_string();
316        self
317    }
318
319    #[inline]
320    pub fn forced_update(mut self, forced_update: bool) -> Self {
321        self.forced_update = forced_update;
322        self
323    }
324}
325
326/// 用于存储运行时间的计时器。
327#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
328pub struct Timer {
329    /// 进入页面的时间。
330    pub start_time: f32,
331    /// 程序总运行时间。
332    pub total_time: f32,
333    /// 核心计时器。
334    pub timer: Instant,
335    /// 当前页面运行时间。
336    pub now_time: f32,
337}
338
339impl Default for Timer {
340    fn default() -> Self {
341        Timer {
342            start_time: 0_f32,
343            total_time: 0_f32,
344            timer: Instant::now(),
345            now_time: 0_f32,
346        }
347    }
348}
349
350/// 为图片纹理支持派生Debug特征。
351#[derive(Clone, PartialEq, Eq, Hash)]
352pub struct DebugTextureHandle(TextureHandle);
353
354impl Debug for DebugTextureHandle {
355    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
356        // 只输出类型信息,不输出具体纹理数据
357        f.debug_struct("DebugTextureHandle").finish()
358    }
359}
360
361impl DebugTextureHandle {
362    pub fn new(texture_handle: TextureHandle) -> Self {
363        Self(texture_handle)
364    }
365}
366
367/// 用于存储图片纹理的RC资源。
368#[derive(Debug, Clone, PartialEq, Eq, Hash)]
369pub struct ImageTexture {
370    pub discern_type: String,
371    pub name: String,
372    /// 图片纹理。
373    pub texture: Option<DebugTextureHandle>,
374    /// 图片路径。
375    pub cite_path: String,
376}
377
378impl RustConstructorResource for ImageTexture {
379    fn name(&self) -> &str {
380        &self.name
381    }
382
383    fn expose_type(&self) -> &str {
384        &self.discern_type
385    }
386
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
396impl Default for ImageTexture {
397    fn default() -> Self {
398        ImageTexture {
399            discern_type: String::from("ImageTexture"),
400            name: String::from("ImageTexture"),
401            texture: None,
402            cite_path: String::from(""),
403        }
404    }
405}
406
407impl ImageTexture {
408    #[inline]
409    pub fn name(mut self, name: &str) -> Self {
410        self.name = name.to_string();
411        self
412    }
413}
414
415/// 矩形的可配置项。
416#[derive(Debug, Clone, PartialEq, PartialOrd)]
417pub struct CustomRectConfig {
418    /// 尺寸。
419    pub size: [f32; 2],
420    /// 圆角。
421    pub rounding: f32,
422    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
423    pub x_grid: [u32; 2],
424    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
425    pub y_grid: [u32; 2],
426    /// 对齐方法。
427    pub center_display: (HorizontalAlign, VerticalAlign),
428    /// 偏移量。
429    pub offset: [f32; 2],
430    /// 颜色。
431    pub color: [u8; 4],
432    /// 边框宽度。
433    pub border_width: f32,
434    /// 边框颜色。
435    pub border_color: [u8; 4],
436    /// 原始位置。
437    pub origin_position: [f32; 2],
438}
439
440impl Default for CustomRectConfig {
441    fn default() -> Self {
442        Self {
443            size: [100_f32, 100_f32],
444            rounding: 2_f32,
445            x_grid: [0, 0],
446            y_grid: [0, 0],
447            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
448            offset: [0_f32, 0_f32],
449            color: [255, 255, 255, 255],
450            border_width: 2_f32,
451            border_color: [0, 0, 0, 255],
452            origin_position: [0_f32, 0_f32],
453        }
454    }
455}
456
457impl CustomRectConfig {
458    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
459        self.origin_position = position_config.origin_position;
460        self.size = position_config.size;
461        self.x_grid = position_config.x_grid;
462        self.y_grid = position_config.y_grid;
463        self.center_display = position_config.center_display;
464        self.offset = position_config.offset;
465        self
466    }
467
468    pub fn from_custom_rect(custom_rect: CustomRect) -> Self {
469        Self {
470            size: custom_rect.size,
471            rounding: custom_rect.rounding,
472            x_grid: custom_rect.x_grid,
473            y_grid: custom_rect.y_grid,
474            center_display: custom_rect.center_display,
475            offset: custom_rect.offset,
476            color: custom_rect.color,
477            border_width: custom_rect.border_width,
478            border_color: custom_rect.border_color,
479            origin_position: custom_rect.origin_position,
480        }
481    }
482
483    #[inline]
484    pub fn size(mut self, width: f32, height: f32) -> Self {
485        self.size = [width, height];
486        self
487    }
488
489    #[inline]
490    pub fn rounding(mut self, rounding: f32) -> Self {
491        self.rounding = rounding;
492        self
493    }
494
495    #[inline]
496    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
497        self.x_grid = [fetch, total];
498        self
499    }
500
501    #[inline]
502    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
503        self.y_grid = [fetch, total];
504        self
505    }
506
507    #[inline]
508    pub fn center_display(
509        mut self,
510        horizontal_align: HorizontalAlign,
511        vertical_align: VerticalAlign,
512    ) -> Self {
513        self.center_display = (horizontal_align, vertical_align);
514        self
515    }
516
517    #[inline]
518    pub fn offset(mut self, x: f32, y: f32) -> Self {
519        self.offset = [x, y];
520        self
521    }
522
523    #[inline]
524    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
525        self.color = [r, g, b, a];
526        self
527    }
528
529    #[inline]
530    pub fn border_width(mut self, border_width: f32) -> Self {
531        self.border_width = border_width;
532        self
533    }
534
535    #[inline]
536    pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
537        self.border_color = [r, g, b, a];
538        self
539    }
540
541    #[inline]
542    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
543        self.origin_position = [x, y];
544        self
545    }
546}
547
548/// RC的矩形资源。
549#[derive(Debug, Clone, PartialEq, PartialOrd)]
550pub struct CustomRect {
551    pub discern_type: String,
552    pub name: String,
553    /// 位置。
554    pub position: [f32; 2],
555    /// 尺寸。
556    pub size: [f32; 2],
557    /// 圆角。
558    pub rounding: f32,
559    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
560    pub x_grid: [u32; 2],
561    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
562    pub y_grid: [u32; 2],
563    /// 对齐方法。
564    pub center_display: (HorizontalAlign, VerticalAlign),
565    /// 偏移量。
566    pub offset: [f32; 2],
567    /// 颜色。
568    pub color: [u8; 4],
569    /// 边框宽度。
570    pub border_width: f32,
571    /// 边框颜色。
572    pub border_color: [u8; 4],
573    /// 原始位置。
574    pub origin_position: [f32; 2],
575}
576
577impl RustConstructorResource for CustomRect {
578    fn name(&self) -> &str {
579        &self.name
580    }
581
582    fn expose_type(&self) -> &str {
583        &self.discern_type
584    }
585
586    fn as_any(&self) -> &dyn Any {
587        self
588    }
589
590    fn as_any_mut(&mut self) -> &mut dyn Any {
591        self
592    }
593}
594
595impl BasicFrontResource for CustomRect {
596    fn position(&self) -> [f32; 2] {
597        self.position
598    }
599
600    fn size(&self) -> [f32; 2] {
601        self.size
602    }
603
604    fn modify_position(&mut self, x: f32, y: f32) {
605        self.origin_position = [x, y];
606    }
607
608    fn modify_size(&mut self, width: f32, height: f32) {
609        self.size = [width, height];
610    }
611
612    fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
613        self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
614    }
615}
616
617impl Default for CustomRect {
618    fn default() -> Self {
619        Self {
620            discern_type: String::from("CustomRect"),
621            name: String::from("CustomRect"),
622            position: [0_f32, 0_f32],
623            size: [100_f32, 100_f32],
624            rounding: 2_f32,
625            x_grid: [0, 0],
626            y_grid: [0, 0],
627            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
628            offset: [0_f32, 0_f32],
629            color: [255, 255, 255, 255],
630            border_width: 2_f32,
631            border_color: [0, 0, 0, 255],
632            origin_position: [0_f32, 0_f32],
633        }
634    }
635}
636
637impl CustomRect {
638    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
639        self.origin_position = position_config.origin_position;
640        self.size = position_config.size;
641        self.x_grid = position_config.x_grid;
642        self.y_grid = position_config.y_grid;
643        self.center_display = position_config.center_display;
644        self.offset = position_config.offset;
645        self
646    }
647
648    pub fn from_config(mut self, config: CustomRectConfig) -> Self {
649        self.size = config.size;
650        self.rounding = config.rounding;
651        self.x_grid = config.x_grid;
652        self.y_grid = config.y_grid;
653        self.center_display = config.center_display;
654        self.offset = config.offset;
655        self.color = config.color;
656        self.border_width = config.border_width;
657        self.border_color = config.border_color;
658        self.origin_position = config.origin_position;
659        self
660    }
661
662    #[inline]
663    pub fn name(mut self, name: &str) -> Self {
664        self.name = name.to_string();
665        self
666    }
667
668    #[inline]
669    pub fn size(mut self, width: f32, height: f32) -> Self {
670        self.size = [width, height];
671        self
672    }
673
674    #[inline]
675    pub fn rounding(mut self, rounding: f32) -> Self {
676        self.rounding = rounding;
677        self
678    }
679
680    #[inline]
681    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
682        self.x_grid = [fetch, total];
683        self
684    }
685
686    #[inline]
687    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
688        self.y_grid = [fetch, total];
689        self
690    }
691
692    #[inline]
693    pub fn center_display(
694        mut self,
695        horizontal_align: HorizontalAlign,
696        vertical_align: VerticalAlign,
697    ) -> Self {
698        self.center_display = (horizontal_align, vertical_align);
699        self
700    }
701
702    #[inline]
703    pub fn offset(mut self, x: f32, y: f32) -> Self {
704        self.offset = [x, y];
705        self
706    }
707
708    #[inline]
709    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
710        self.color = [r, g, b, a];
711        self
712    }
713
714    #[inline]
715    pub fn border_width(mut self, border_width: f32) -> Self {
716        self.border_width = border_width;
717        self
718    }
719
720    #[inline]
721    pub fn border_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
722        self.border_color = [r, g, b, a];
723        self
724    }
725
726    #[inline]
727    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
728        self.origin_position = [x, y];
729        self
730    }
731}
732
733/// 图片的可配置项。
734#[derive(Debug, Clone, PartialEq, PartialOrd)]
735pub struct ImageConfig {
736    /// 图片大小。
737    pub size: [f32; 2],
738    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
739    pub x_grid: [u32; 2],
740    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
741    pub y_grid: [u32; 2],
742    /// 对齐方法。
743    pub center_display: (HorizontalAlign, VerticalAlign),
744    /// 偏移量。
745    pub offset: [f32; 2],
746    /// 不透明度。
747    pub alpha: u8,
748    /// 叠加颜色。
749    pub overlay_color: [u8; 4],
750    /// 背景颜色。
751    pub background_color: [u8; 4],
752    /// 旋转角度(只能顺时针,建议搭配std::f32::PI使用)。
753    pub rotate_angle: f32,
754    /// 旋转中心。
755    pub rotate_center: [f32; 2],
756    /// 原始位置。
757    pub origin_position: [f32; 2],
758    /// 引用纹理名。
759    pub cite_texture: String,
760}
761
762impl Default for ImageConfig {
763    fn default() -> Self {
764        Self {
765            size: [100_f32, 100_f32],
766            x_grid: [0, 0],
767            y_grid: [0, 0],
768            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
769            offset: [0_f32, 0_f32],
770            alpha: 255,
771            overlay_color: [255, 255, 255, 255],
772            background_color: [0, 0, 0, 0],
773            rotate_angle: 0_f32,
774            rotate_center: [0_f32, 0_f32],
775            origin_position: [0_f32, 0_f32],
776            cite_texture: String::from("ImageTexture"),
777        }
778    }
779}
780
781impl ImageConfig {
782    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
783        self.origin_position = position_config.origin_position;
784        self.size = position_config.size;
785        self.x_grid = position_config.x_grid;
786        self.y_grid = position_config.y_grid;
787        self.center_display = position_config.center_display;
788        self.offset = position_config.offset;
789        self
790    }
791
792    pub fn from_image(image: Image) -> Self {
793        Self {
794            size: image.size,
795            x_grid: image.x_grid,
796            y_grid: image.y_grid,
797            center_display: image.center_display,
798            offset: image.offset,
799            alpha: image.alpha,
800            overlay_color: image.overlay_color,
801            background_color: image.background_color,
802            rotate_angle: image.rotate_angle,
803            rotate_center: image.rotate_center,
804            cite_texture: image.cite_texture,
805            origin_position: image.origin_position,
806        }
807    }
808
809    #[inline]
810    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
811        self.origin_position = [x, y];
812        self
813    }
814
815    #[inline]
816    pub fn size(mut self, width: f32, height: f32) -> Self {
817        self.size = [width, height];
818        self
819    }
820
821    #[inline]
822    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
823        self.x_grid = [fetch, total];
824        self
825    }
826
827    #[inline]
828    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
829        self.y_grid = [fetch, total];
830        self
831    }
832
833    #[inline]
834    pub fn center_display(
835        mut self,
836        horizontal_align: HorizontalAlign,
837        vertical_align: VerticalAlign,
838    ) -> Self {
839        self.center_display = (horizontal_align, vertical_align);
840        self
841    }
842
843    #[inline]
844    pub fn offset(mut self, x: f32, y: f32) -> Self {
845        self.offset = [x, y];
846        self
847    }
848
849    #[inline]
850    pub fn alpha(mut self, alpha: u8) -> Self {
851        self.alpha = alpha;
852        self
853    }
854
855    #[inline]
856    pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
857        self.overlay_color = [r, g, b, a];
858        self
859    }
860
861    #[inline]
862    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
863        self.background_color = [r, g, b, a];
864        self
865    }
866
867    #[inline]
868    pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
869        self.rotate_angle = rotate_angle;
870        self
871    }
872
873    #[inline]
874    pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
875        self.rotate_center = [x, y];
876        self
877    }
878}
879
880/// RC的图片资源。
881#[derive(Debug, Clone, PartialEq)]
882pub struct Image {
883    pub discern_type: String,
884    pub name: String,
885    /// 图片纹理。
886    pub texture: Option<DebugTextureHandle>,
887    /// 图片位置。
888    pub position: [f32; 2],
889    /// 图片大小。
890    pub size: [f32; 2],
891    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
892    pub x_grid: [u32; 2],
893    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
894    pub y_grid: [u32; 2],
895    /// 对齐方法。
896    pub center_display: (HorizontalAlign, VerticalAlign),
897    /// 偏移量。
898    pub offset: [f32; 2],
899    /// 不透明度。
900    pub alpha: u8,
901    /// 叠加颜色。
902    pub overlay_color: [u8; 4],
903    /// 背景颜色。
904    pub background_color: [u8; 4],
905    /// 旋转角度(只能顺时针,建议搭配std::f32::consts::PI使用)。
906    pub rotate_angle: f32,
907    /// 旋转中心。
908    pub rotate_center: [f32; 2],
909    /// 原始位置。
910    pub origin_position: [f32; 2],
911    /// 引用纹理名。
912    pub cite_texture: String,
913    /// 上一帧引用纹理名。
914    pub last_frame_cite_texture: String,
915}
916
917impl RustConstructorResource for Image {
918    fn name(&self) -> &str {
919        &self.name
920    }
921
922    fn expose_type(&self) -> &str {
923        &self.discern_type
924    }
925
926    fn as_any(&self) -> &dyn Any {
927        self
928    }
929
930    fn as_any_mut(&mut self) -> &mut dyn Any {
931        self
932    }
933}
934
935impl BasicFrontResource for Image {
936    fn position(&self) -> [f32; 2] {
937        self.position
938    }
939
940    fn size(&self) -> [f32; 2] {
941        self.size
942    }
943
944    fn modify_position(&mut self, x: f32, y: f32) {
945        self.origin_position = [x, y];
946    }
947
948    fn modify_size(&mut self, width: f32, height: f32) {
949        self.size = [width, height];
950    }
951
952    fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
953        self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
954    }
955}
956
957impl Default for Image {
958    fn default() -> Self {
959        Self {
960            discern_type: String::from("Image"),
961            name: String::from("Image"),
962            texture: None,
963            position: [0_f32, 0_f32],
964            size: [100_f32, 100_f32],
965            x_grid: [0, 0],
966            y_grid: [0, 0],
967            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
968            offset: [0_f32, 0_f32],
969            alpha: 255,
970            overlay_color: [255, 255, 255, 255],
971            background_color: [0, 0, 0, 0],
972            rotate_angle: 0_f32,
973            rotate_center: [0_f32, 0_f32],
974            origin_position: [0_f32, 0_f32],
975            cite_texture: String::from("ImageTexture"),
976            last_frame_cite_texture: String::from("ImageTexture"),
977        }
978    }
979}
980
981impl Image {
982    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
983        self.origin_position = position_config.origin_position;
984        self.size = position_config.size;
985        self.x_grid = position_config.x_grid;
986        self.y_grid = position_config.y_grid;
987        self.center_display = position_config.center_display;
988        self.offset = position_config.offset;
989        self
990    }
991
992    pub fn from_config(mut self, config: ImageConfig) -> Self {
993        self.size = config.size;
994        self.x_grid = config.x_grid;
995        self.y_grid = config.y_grid;
996        self.center_display = config.center_display;
997        self.offset = config.offset;
998        self.alpha = config.alpha;
999        self.overlay_color = config.overlay_color;
1000        self.background_color = config.background_color;
1001        self.rotate_angle = config.rotate_angle;
1002        self.rotate_center = config.rotate_center;
1003        self.origin_position = config.origin_position;
1004        self.cite_texture = config.cite_texture;
1005        self
1006    }
1007
1008    #[inline]
1009    pub fn name(mut self, name: &str) -> Self {
1010        self.name = name.to_string();
1011        self
1012    }
1013
1014    #[inline]
1015    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1016        self.origin_position = [x, y];
1017        self
1018    }
1019
1020    #[inline]
1021    pub fn size(mut self, width: f32, height: f32) -> Self {
1022        self.size = [width, height];
1023        self
1024    }
1025
1026    #[inline]
1027    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1028        self.x_grid = [fetch, total];
1029        self
1030    }
1031
1032    #[inline]
1033    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1034        self.y_grid = [fetch, total];
1035        self
1036    }
1037
1038    #[inline]
1039    pub fn center_display(
1040        mut self,
1041        horizontal_align: HorizontalAlign,
1042        vertical_align: VerticalAlign,
1043    ) -> Self {
1044        self.center_display = (horizontal_align, vertical_align);
1045        self
1046    }
1047
1048    #[inline]
1049    pub fn offset(mut self, x: f32, y: f32) -> Self {
1050        self.offset = [x, y];
1051        self
1052    }
1053
1054    #[inline]
1055    pub fn alpha(mut self, alpha: u8) -> Self {
1056        self.alpha = alpha;
1057        self
1058    }
1059
1060    #[inline]
1061    pub fn overlay_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1062        self.overlay_color = [r, g, b, a];
1063        self
1064    }
1065
1066    #[inline]
1067    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1068        self.background_color = [r, g, b, a];
1069        self
1070    }
1071
1072    #[inline]
1073    pub fn rotate_angle(mut self, rotate_angle: f32) -> Self {
1074        self.rotate_angle = rotate_angle;
1075        self
1076    }
1077
1078    #[inline]
1079    pub fn rotate_center(mut self, x: f32, y: f32) -> Self {
1080        self.rotate_center = [x, y];
1081        self
1082    }
1083}
1084
1085/// 控制超链接选取方法。
1086#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1087pub enum HyperlinkSelectMethod {
1088    /// 选取所有匹配项。
1089    All(String),
1090    /// 选取指定的匹配项。
1091    Segment(Vec<(usize, String)>),
1092}
1093
1094/// 文本的可配置项。
1095#[derive(Debug, Clone, PartialEq, PartialOrd)]
1096pub struct TextConfig {
1097    /// 文本内容。
1098    pub content: String,
1099    /// 字号。
1100    pub font_size: f32,
1101    /// 文本颜色。
1102    pub color: [u8; 4],
1103    /// 对齐方法。
1104    pub center_display: (HorizontalAlign, VerticalAlign),
1105    /// 偏移量。
1106    pub offset: [f32; 2],
1107    /// 单行宽度。
1108    pub wrap_width: f32,
1109    /// 背景颜色。
1110    pub background_color: [u8; 4],
1111    /// 圆角。
1112    pub background_rounding: f32,
1113    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1114    pub x_grid: [u32; 2],
1115    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1116    pub y_grid: [u32; 2],
1117    /// 原始位置。
1118    pub origin_position: [f32; 2],
1119    /// 字体。
1120    pub font: String,
1121    /// 是否可框选。
1122    pub selectable: bool,
1123    /// 超链接文本。
1124    pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1125    /// 文本大小。
1126    pub size: [f32; 2],
1127}
1128
1129impl Default for TextConfig {
1130    fn default() -> Self {
1131        Self {
1132            content: String::from("Hello world"),
1133            font_size: 16_f32,
1134            color: [255, 255, 255, 255],
1135            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1136            offset: [0_f32, 0_f32],
1137            wrap_width: 200_f32,
1138            background_color: [0, 0, 0, 0],
1139            background_rounding: 2_f32,
1140            x_grid: [0, 0],
1141            y_grid: [0, 0],
1142            origin_position: [0_f32, 0_f32],
1143            font: String::new(),
1144            selectable: true,
1145            hyperlink_text: Vec::new(),
1146            size: [0_f32, 0_f32],
1147        }
1148    }
1149}
1150
1151impl TextConfig {
1152    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1153        self.origin_position = position_config.origin_position;
1154        self.wrap_width = position_config.size[0];
1155        self.x_grid = position_config.x_grid;
1156        self.y_grid = position_config.y_grid;
1157        self.center_display = position_config.center_display;
1158        self.offset = position_config.offset;
1159        self.size = position_config.size;
1160        self
1161    }
1162
1163    pub fn from_text(text: Text) -> Self {
1164        Self {
1165            content: text.content,
1166            font_size: text.font_size,
1167            color: text.color,
1168            center_display: text.center_display,
1169            offset: text.offset,
1170            wrap_width: text.wrap_width,
1171            background_color: text.background_color,
1172            background_rounding: text.background_rounding,
1173            x_grid: text.x_grid,
1174            y_grid: text.y_grid,
1175            origin_position: text.origin_position,
1176            font: text.font,
1177            selectable: text.selectable,
1178            hyperlink_text: text.hyperlink_text,
1179            size: text.size,
1180        }
1181    }
1182
1183    #[inline]
1184    pub fn content(mut self, content: &str) -> Self {
1185        self.content = content.to_string();
1186        self
1187    }
1188
1189    #[inline]
1190    pub fn font_size(mut self, font_size: f32) -> Self {
1191        self.font_size = font_size;
1192        self
1193    }
1194
1195    #[inline]
1196    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1197        self.color = [r, g, b, a];
1198        self
1199    }
1200
1201    #[inline]
1202    pub fn center_display(
1203        mut self,
1204        horizontal_align: HorizontalAlign,
1205        vertical_align: VerticalAlign,
1206    ) -> Self {
1207        self.center_display = (horizontal_align, vertical_align);
1208        self
1209    }
1210
1211    #[inline]
1212    pub fn offset(mut self, x: f32, y: f32) -> Self {
1213        self.offset = [x, y];
1214        self
1215    }
1216
1217    #[inline]
1218    pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1219        self.wrap_width = wrap_width;
1220        self
1221    }
1222
1223    #[inline]
1224    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1225        self.background_color = [r, g, b, a];
1226        self
1227    }
1228
1229    #[inline]
1230    pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1231        self.background_rounding = background_rounding;
1232        self
1233    }
1234
1235    #[inline]
1236    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1237        self.x_grid = [fetch, total];
1238        self
1239    }
1240
1241    #[inline]
1242    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1243        self.y_grid = [fetch, total];
1244        self
1245    }
1246
1247    #[inline]
1248    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1249        self.origin_position = [x, y];
1250        self
1251    }
1252
1253    #[inline]
1254    pub fn font(mut self, font: &str) -> Self {
1255        self.font = font.to_string();
1256        self
1257    }
1258
1259    #[inline]
1260    pub fn selectable(mut self, selectable: bool) -> Self {
1261        self.selectable = selectable;
1262        self
1263    }
1264
1265    #[inline]
1266    pub fn hyperlink_text(
1267        mut self,
1268        target_text: &str,
1269        select_method: HyperlinkSelectMethod,
1270    ) -> Self {
1271        self.hyperlink_text
1272            .push((target_text.to_string(), select_method));
1273        self
1274    }
1275}
1276
1277/// RC的文本资源。
1278#[derive(Debug, Clone, PartialEq, PartialOrd)]
1279pub struct Text {
1280    pub discern_type: String,
1281    pub name: String,
1282    /// 文本内容。
1283    pub content: String,
1284    /// 字号。
1285    pub font_size: f32,
1286    /// 文本颜色。
1287    pub color: [u8; 4],
1288    /// 文本位置。
1289    pub position: [f32; 2],
1290    /// 对齐方法。
1291    pub center_display: (HorizontalAlign, VerticalAlign),
1292    /// 偏移量。
1293    pub offset: [f32; 2],
1294    /// 单行宽度。
1295    pub wrap_width: f32,
1296    /// 背景颜色。
1297    pub background_color: [u8; 4],
1298    /// 圆角。
1299    pub background_rounding: f32,
1300    /// x轴的网格式定位:窗口宽 / 第二项 * 第一项 = x轴的原始位置。
1301    pub x_grid: [u32; 2],
1302    /// y轴的网格式定位:窗口高 / 第二项 * 第一项 = y轴的原始位置。
1303    pub y_grid: [u32; 2],
1304    /// 原始位置。
1305    pub origin_position: [f32; 2],
1306    /// 字体。
1307    pub font: String,
1308    /// 框选选中的文本。
1309    pub selection: Option<(usize, usize)>,
1310    /// 是否可框选。
1311    pub selectable: bool,
1312    /// 超链接文本。
1313    pub hyperlink_text: Vec<(String, HyperlinkSelectMethod)>,
1314    /// 超链接选取索引值与链接。
1315    pub hyperlink_index: Vec<(usize, usize, String)>,
1316    /// 上一帧的文本内容(用于优化超链接文本选取)。
1317    pub last_frame_content: String,
1318    /// 文本大小。
1319    pub size: [f32; 2],
1320}
1321
1322impl RustConstructorResource for Text {
1323    fn name(&self) -> &str {
1324        &self.name
1325    }
1326
1327    fn expose_type(&self) -> &str {
1328        &self.discern_type
1329    }
1330
1331    fn as_any(&self) -> &dyn Any {
1332        self
1333    }
1334
1335    fn as_any_mut(&mut self) -> &mut dyn Any {
1336        self
1337    }
1338}
1339
1340impl BasicFrontResource for Text {
1341    fn position(&self) -> [f32; 2] {
1342        self.position
1343    }
1344
1345    fn size(&self) -> [f32; 2] {
1346        self.size
1347    }
1348
1349    fn modify_position(&mut self, x: f32, y: f32) {
1350        self.origin_position = [x, y];
1351    }
1352
1353    fn modify_size(&mut self, width: f32, height: f32) {
1354        self.wrap_width = width;
1355        self.size = [width, height];
1356    }
1357
1358    fn modify_add_position(&mut self, add_x: f32, add_y: f32) {
1359        self.origin_position = [self.position[0] + add_x, self.position[1] + add_y];
1360    }
1361}
1362
1363impl Default for Text {
1364    fn default() -> Self {
1365        Self {
1366            discern_type: String::from("Text"),
1367            name: String::from("Text"),
1368            content: String::from("Hello world"),
1369            font_size: 16_f32,
1370            color: [255, 255, 255, 255],
1371            position: [0_f32, 0_f32],
1372            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
1373            offset: [0_f32, 0_f32],
1374            wrap_width: 200_f32,
1375            background_color: [0, 0, 0, 0],
1376            background_rounding: 2_f32,
1377            x_grid: [0, 0],
1378            y_grid: [0, 0],
1379            origin_position: [0_f32, 0_f32],
1380            font: String::new(),
1381            selection: None,
1382            selectable: true,
1383            hyperlink_text: Vec::new(),
1384            hyperlink_index: Vec::new(),
1385            last_frame_content: String::from(""),
1386            size: [0_f32, 0_f32],
1387        }
1388    }
1389}
1390
1391impl Text {
1392    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
1393        self.origin_position = position_config.origin_position;
1394        self.wrap_width = position_config.size[0];
1395        self.x_grid = position_config.x_grid;
1396        self.y_grid = position_config.y_grid;
1397        self.center_display = position_config.center_display;
1398        self.offset = position_config.offset;
1399        self.size = position_config.size;
1400        self
1401    }
1402
1403    pub fn from_config(mut self, config: TextConfig) -> Self {
1404        self.content = config.content;
1405        self.font_size = config.font_size;
1406        self.color = config.color;
1407        self.center_display = config.center_display;
1408        self.offset = config.offset;
1409        self.wrap_width = config.wrap_width;
1410        self.background_color = config.background_color;
1411        self.background_rounding = config.background_rounding;
1412        self.x_grid = config.x_grid;
1413        self.y_grid = config.y_grid;
1414        self.origin_position = config.origin_position;
1415        self.font = config.font;
1416        self.selectable = config.selectable;
1417        self.hyperlink_text = config.hyperlink_text;
1418        self.size = config.size;
1419        self
1420    }
1421
1422    #[inline]
1423    pub fn name(mut self, name: &str) -> Self {
1424        self.name = name.to_string();
1425        self
1426    }
1427
1428    #[inline]
1429    pub fn content(mut self, content: &str) -> Self {
1430        self.content = content.to_string();
1431        self
1432    }
1433
1434    #[inline]
1435    pub fn font_size(mut self, font_size: f32) -> Self {
1436        self.font_size = font_size;
1437        self
1438    }
1439
1440    #[inline]
1441    pub fn color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1442        self.color = [r, g, b, a];
1443        self
1444    }
1445
1446    #[inline]
1447    pub fn center_display(
1448        mut self,
1449        horizontal_align: HorizontalAlign,
1450        vertical_align: VerticalAlign,
1451    ) -> Self {
1452        self.center_display = (horizontal_align, vertical_align);
1453        self
1454    }
1455
1456    #[inline]
1457    pub fn offset(mut self, x: f32, y: f32) -> Self {
1458        self.offset = [x, y];
1459        self
1460    }
1461
1462    #[inline]
1463    pub fn wrap_width(mut self, wrap_width: f32) -> Self {
1464        self.wrap_width = wrap_width;
1465        self
1466    }
1467
1468    #[inline]
1469    pub fn background_color(mut self, r: u8, g: u8, b: u8, a: u8) -> Self {
1470        self.background_color = [r, g, b, a];
1471        self
1472    }
1473
1474    #[inline]
1475    pub fn background_rounding(mut self, background_rounding: f32) -> Self {
1476        self.background_rounding = background_rounding;
1477        self
1478    }
1479
1480    #[inline]
1481    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
1482        self.x_grid = [fetch, total];
1483        self
1484    }
1485
1486    #[inline]
1487    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
1488        self.y_grid = [fetch, total];
1489        self
1490    }
1491
1492    #[inline]
1493    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
1494        self.origin_position = [x, y];
1495        self
1496    }
1497
1498    #[inline]
1499    pub fn font(mut self, font: &str) -> Self {
1500        self.font = font.to_string();
1501        self
1502    }
1503
1504    #[inline]
1505    pub fn selectable(mut self, selectable: bool) -> Self {
1506        self.selectable = selectable;
1507        self
1508    }
1509
1510    #[inline]
1511    pub fn hyperlink_text(
1512        mut self,
1513        target_text: &str,
1514        select_method: HyperlinkSelectMethod,
1515    ) -> Self {
1516        self.hyperlink_text
1517            .push((target_text.to_string(), select_method));
1518        self
1519    }
1520}
1521
1522/// RC的变量资源。
1523#[derive(Debug, Clone, PartialEq, PartialOrd)]
1524pub struct Variable<T> {
1525    pub discern_type: String,
1526    pub name: String,
1527    /// 变量的值。
1528    pub value: Option<T>,
1529}
1530
1531impl<T: Debug + 'static> RustConstructorResource for Variable<T> {
1532    fn name(&self) -> &str {
1533        &self.name
1534    }
1535
1536    fn expose_type(&self) -> &str {
1537        &self.discern_type
1538    }
1539
1540    fn as_any(&self) -> &dyn Any {
1541        self
1542    }
1543
1544    fn as_any_mut(&mut self) -> &mut dyn Any {
1545        self
1546    }
1547}
1548
1549impl<T> Default for Variable<T> {
1550    fn default() -> Self {
1551        Variable {
1552            discern_type: String::from("Variable"),
1553            name: String::from("Variable"),
1554            value: None,
1555        }
1556    }
1557}
1558
1559impl<T> Variable<T> {
1560    #[inline]
1561    pub fn name(mut self, name: &str) -> Self {
1562        self.name = name.to_string();
1563        self
1564    }
1565
1566    #[inline]
1567    pub fn value(mut self, value: Option<T>) -> Self {
1568        self.value = value;
1569        self
1570    }
1571}
1572
1573/// RC的字体资源。
1574#[derive(Debug, Clone, PartialEq)]
1575pub struct Font {
1576    pub name: String,
1577    pub discern_type: String,
1578    /// 字体定义。
1579    pub font_definitions: FontDefinitions,
1580    /// 字体路径。
1581    pub path: String,
1582}
1583
1584impl RustConstructorResource for Font {
1585    fn name(&self) -> &str {
1586        &self.name
1587    }
1588
1589    fn expose_type(&self) -> &str {
1590        &self.discern_type
1591    }
1592
1593    fn as_any(&self) -> &dyn Any {
1594        self
1595    }
1596
1597    fn as_any_mut(&mut self) -> &mut dyn Any {
1598        self
1599    }
1600}
1601
1602impl Default for Font {
1603    fn default() -> Self {
1604        Self {
1605            discern_type: String::from("Font"),
1606            name: String::from("Font"),
1607            font_definitions: FontDefinitions::default(),
1608            path: String::from(""),
1609        }
1610    }
1611}
1612
1613impl Font {
1614    #[inline]
1615    pub fn name(mut self, name: &str) -> Self {
1616        self.name = name.to_string();
1617        self
1618    }
1619
1620    #[inline]
1621    pub fn path(mut self, path: &str) -> Self {
1622        self.path = path.to_string();
1623        self
1624    }
1625}
1626
1627/// RC的时间分段资源。
1628#[derive(Debug, Clone, PartialEq, PartialOrd)]
1629pub struct SplitTime {
1630    pub discern_type: String,
1631    pub name: String,
1632    /// 时间点(第一个值为页面运行时间,第二个值为总运行时间)。
1633    pub time: [f32; 2],
1634}
1635
1636impl RustConstructorResource for SplitTime {
1637    fn name(&self) -> &str {
1638        &self.name
1639    }
1640
1641    fn expose_type(&self) -> &str {
1642        &self.discern_type
1643    }
1644
1645    fn as_any(&self) -> &dyn Any {
1646        self
1647    }
1648
1649    fn as_any_mut(&mut self) -> &mut dyn Any {
1650        self
1651    }
1652}
1653
1654impl Default for SplitTime {
1655    fn default() -> Self {
1656        Self {
1657            discern_type: String::from("SplitTime"),
1658            name: String::from("SplitTime"),
1659            time: [0_f32, 0_f32],
1660        }
1661    }
1662}
1663
1664impl SplitTime {
1665    #[inline]
1666    pub fn name(mut self, name: &str) -> Self {
1667        self.name = name.to_string();
1668        self
1669    }
1670}
1671
1672/// 开关的外观。
1673#[derive(Debug, Clone, PartialEq, PartialOrd)]
1674pub struct SwitchAppearance {
1675    /// 当填充资源为图片时的配置项。
1676    pub image_config: ImageConfig,
1677    /// 当填充资源为矩形时的配置项。
1678    pub custom_rect_config: CustomRectConfig,
1679    /// 当启用文本时,文本的配置项。
1680    pub text_config: TextConfig,
1681    /// 当填充资源为图片时,开关的纹理。
1682    pub texture: String,
1683    /// 开关上的提示文本。
1684    pub hint_text: String,
1685}
1686
1687/// 开关的点击方法。
1688#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1689pub struct SwitchClickAction {
1690    /// 开关的点击方法。
1691    pub click_method: PointerButton,
1692    /// 点击后是否改变开关状态。
1693    pub action: bool,
1694}
1695
1696/// 用于开关资源判定的一些字段集合。
1697#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1698pub struct SwitchData {
1699    /// 是否点击切换状态。
1700    pub switched: bool,
1701    /// 点击的方法。
1702    pub last_time_clicked_index: usize,
1703    /// 开关状态。
1704    pub state: u32,
1705}
1706
1707/// RC的开关资源。
1708#[derive(Debug, Clone, PartialEq)]
1709pub struct Switch {
1710    pub discern_type: String,
1711    pub name: String,
1712    /// 外观(包括各类资源配置项,数量为开启的内容数量*开关状态总数)。
1713    pub appearance: Vec<SwitchAppearance>,
1714    /// 开关使用的填充资源名称。
1715    pub fill_resource_name: String,
1716    /// 开关使用的填充资源类型。
1717    pub fill_resource_type: String,
1718    /// 是否启用鼠标悬浮和点击时的显示内容。
1719    pub enable_hover_click_fill_resource: [bool; 2],
1720    /// 开关当前状态。
1721    pub state: u32,
1722    /// 可以用于点击开关的方法(包含点击方式和是否改变开关状态两个参数)。
1723    pub click_method: Vec<SwitchClickAction>,
1724    /// 上一次渲染是否有鼠标悬浮。
1725    pub last_time_hovered: bool,
1726    /// 上一次渲染是否被鼠标点击。
1727    pub last_time_clicked: bool,
1728    /// 上一次点击对应的点击方法的索引。
1729    pub last_time_clicked_index: usize,
1730    /// 动画总数。
1731    pub animation_count: u32,
1732    /// 提示文本资源名。
1733    pub hint_text_name: String,
1734    /// 开关上的文本资源名称(不需要可留空)。
1735    pub text_name: String,
1736    /// 开关文本资源的原始位置。
1737    pub text_origin_position: [f32; 2],
1738    /// 是否切换了开关状态。
1739    pub switched: bool,
1740}
1741
1742impl RustConstructorResource for Switch {
1743    fn name(&self) -> &str {
1744        &self.name
1745    }
1746
1747    fn expose_type(&self) -> &str {
1748        &self.discern_type
1749    }
1750
1751    fn as_any(&self) -> &dyn Any {
1752        self
1753    }
1754
1755    fn as_any_mut(&mut self) -> &mut dyn Any {
1756        self
1757    }
1758}
1759
1760impl Default for Switch {
1761    fn default() -> Self {
1762        Self {
1763            discern_type: String::from("Switch"),
1764            name: String::from("Switch"),
1765            appearance: vec![],
1766            fill_resource_name: String::from("FillResource"),
1767            fill_resource_type: String::from("Image"),
1768            enable_hover_click_fill_resource: [false, false],
1769            state: 0,
1770            click_method: vec![],
1771            last_time_hovered: false,
1772            last_time_clicked: false,
1773            last_time_clicked_index: 5,
1774            animation_count: 0,
1775            hint_text_name: String::from("HintText"),
1776            text_name: String::from("Text"),
1777            text_origin_position: [0_f32, 0_f32],
1778            switched: false,
1779        }
1780    }
1781}
1782
1783impl Switch {
1784    #[inline]
1785    pub fn name(mut self, name: &str) -> Self {
1786        self.name = name.to_string();
1787        self
1788    }
1789
1790    #[inline]
1791    pub fn appearance(mut self, appearance: Vec<SwitchAppearance>) -> Self {
1792        self.appearance = appearance;
1793        self
1794    }
1795
1796    #[inline]
1797    pub fn enable_hover_click_fill_resource(
1798        mut self,
1799        enable_hover_fill_resource: bool,
1800        enable_click_fill_resource: bool,
1801    ) -> Self {
1802        self.enable_hover_click_fill_resource =
1803            [enable_hover_fill_resource, enable_click_fill_resource];
1804        self
1805    }
1806
1807    #[inline]
1808    pub fn click_method(mut self, click_method: Vec<SwitchClickAction>) -> Self {
1809        self.click_method = click_method;
1810        self
1811    }
1812}
1813
1814/// 渲染的RC资源。
1815#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1816pub struct RenderResource {
1817    pub discern_type: String,
1818    pub name: String,
1819}
1820
1821/// RC的消息框资源。
1822#[derive(Debug, Clone, PartialEq, PartialOrd)]
1823pub struct MessageBox {
1824    pub discern_type: String,
1825    pub name: String,
1826    /// 消息框大小。
1827    pub size: [f32; 2],
1828    /// 框内内容资源名。
1829    pub content_name: String,
1830    /// 框内标题资源名。
1831    pub title_name: String,
1832    /// 框内图片资源名。
1833    pub image_name: String,
1834    /// 消息框是否持续存在。
1835    pub keep_existing: bool,
1836    /// 如果不持续存在,消息框的持续时间。
1837    pub existing_time: f32,
1838    /// 消息框是否存在(不等于是否显示)。
1839    pub exist: bool,
1840    /// 消息框移动速度。
1841    pub speed: f32,
1842    /// 消息框补位速度。
1843    pub restore_speed: f32,
1844    /// 消息框上一次渲染时的y轴偏移量(用于实现补位动画)。
1845    pub memory_offset: f32,
1846}
1847
1848impl RustConstructorResource for MessageBox {
1849    fn name(&self) -> &str {
1850        &self.name
1851    }
1852
1853    fn expose_type(&self) -> &str {
1854        &self.discern_type
1855    }
1856
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
1866impl Default for MessageBox {
1867    fn default() -> Self {
1868        Self {
1869            discern_type: String::from("MessageBox"),
1870            name: String::from("MessageBox"),
1871            size: [100_f32, 100_f32],
1872            content_name: String::from("Content"),
1873            title_name: String::from("Title"),
1874            image_name: String::from("Image"),
1875            keep_existing: false,
1876            existing_time: 3_f32,
1877            exist: true,
1878            speed: 30_f32,
1879            restore_speed: 10_f32,
1880            memory_offset: 0_f32,
1881        }
1882    }
1883}
1884
1885impl MessageBox {
1886    #[inline]
1887    pub fn name(mut self, name: &str) -> Self {
1888        self.name = name.to_string();
1889        self
1890    }
1891
1892    #[inline]
1893    pub fn size(mut self, width: f32, height: f32) -> Self {
1894        self.size = [width, height];
1895        self
1896    }
1897
1898    #[inline]
1899    pub fn keep_existing(mut self, keep_existing: bool) -> Self {
1900        self.keep_existing = keep_existing;
1901        self
1902    }
1903
1904    #[inline]
1905    pub fn existing_time(mut self, existing_time: f32) -> Self {
1906        self.existing_time = existing_time;
1907        self
1908    }
1909
1910    #[inline]
1911    pub fn speed(mut self, speed: f32) -> Self {
1912        self.speed = speed;
1913        self
1914    }
1915
1916    #[inline]
1917    pub fn restore_speed(mut self, restore_speed: f32) -> Self {
1918        self.restore_speed = restore_speed;
1919        self
1920    }
1921}
1922
1923/// 鼠标检测器单次检测等级。
1924#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1925pub enum MouseDetectorLevel {
1926    /// 精简模式,只进行最基础的检测。
1927    Lite,
1928    /// 标准模式,检测大部分常用鼠标行为。
1929    #[default]
1930    Default,
1931    /// 完整模式,检测所有鼠标行为。
1932    Pro,
1933}
1934
1935/// 鼠标检测器检测结果。
1936#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1937pub struct MouseDetectResult {
1938    /// 是否点击。
1939    pub clicked: bool,
1940    /// 鼠标是否在检测范围内。
1941    pub contains_pointer: bool,
1942    /// 是否点击右键。
1943    pub secondary_clicked: Option<bool>,
1944    /// 是否点击中键。
1945    pub middle_clicked: Option<bool>,
1946    /// 是否点击扩展按键。
1947    pub clicked_by_extra_button: Option<[bool; 2]>,
1948    /// 是否长时间触屏。
1949    pub long_touched: Option<bool>,
1950    /// 是否双击。
1951    pub double_clicked: Option<bool>,
1952    /// 是否三击。
1953    pub triple_clicked: Option<bool>,
1954    /// 双击的方法。
1955    pub double_clicked_by: Option<[bool; 5]>,
1956    /// 三击的方法。
1957    pub triple_clicked_by: Option<[bool; 5]>,
1958    /// 是否在检测范围外点击。
1959    pub clicked_elsewhere: Option<bool>,
1960    /// 是否悬挂在检测范围内。
1961    pub hovered: Option<bool>,
1962    /// 是否开始拖动。
1963    pub drag_started: Option<bool>,
1964    /// 开始拖动的方法。
1965    pub drag_started_by: Option<[bool; 5]>,
1966    /// 是否正在拖动。
1967    pub dragged: Option<bool>,
1968    /// 拖动方法。
1969    pub dragged_by: Option<[bool; 5]>,
1970    /// 是否结束拖动。
1971    pub drag_stopped: Option<bool>,
1972    /// 结束拖动方法。
1973    pub deag_stopped_by: Option<[bool; 5]>,
1974    /// 上一帧拖动经过了多少格像素。
1975    pub drag_delta: Option<[f32; 2]>,
1976    /// 一次拖动中总共经过了多少格像素。
1977    pub total_drag_delta: Option<Option<[f32; 2]>>,
1978    /// 鼠标上一帧拖动了多远。
1979    pub drag_motion: Option<[f32; 2]>,
1980    /// 鼠标交互的位置。
1981    pub interact_pointer_pos: Option<Option<[f32; 2]>>,
1982    /// 鼠标悬挂的位置。
1983    pub hover_pos: Option<Option<[f32; 2]>>,
1984    /// 鼠标是否按下按键。
1985    pub is_pointer_button_down_on: Option<bool>,
1986}
1987
1988/// RC的鼠标检测器资源。
1989#[derive(Debug, Clone, PartialEq, PartialOrd)]
1990pub struct MouseDetector {
1991    pub discern_type: String,
1992    pub name: String,
1993    /// 位置。
1994    pub position: [f32; 2],
1995    /// 原始位置。
1996    pub origin_position: [f32; 2],
1997    /// 尺寸。
1998    pub size: [f32; 2],
1999    /// x轴的网格式定位。
2000    pub x_grid: [u32; 2],
2001    /// y轴的网格式定位。
2002    pub y_grid: [u32; 2],
2003    /// 对齐方法。
2004    pub center_display: (HorizontalAlign, VerticalAlign),
2005    /// 偏移量。
2006    pub offset: [f32; 2],
2007    /// 鼠标检测结果。
2008    pub detect_result: MouseDetectResult,
2009}
2010
2011impl RustConstructorResource for MouseDetector {
2012    fn name(&self) -> &str {
2013        &self.name
2014    }
2015
2016    fn expose_type(&self) -> &str {
2017        &self.discern_type
2018    }
2019
2020    fn as_any(&self) -> &dyn Any {
2021        self
2022    }
2023
2024    fn as_any_mut(&mut self) -> &mut dyn Any {
2025        self
2026    }
2027}
2028
2029impl Default for MouseDetector {
2030    fn default() -> Self {
2031        Self {
2032            discern_type: String::from("MouseDetector"),
2033            name: String::from("MouseDetector"),
2034            position: [0_f32, 0_f32],
2035            origin_position: [0_f32, 0_f32],
2036            size: [100_f32, 100_f32],
2037            x_grid: [0, 0],
2038            y_grid: [0, 0],
2039            center_display: (HorizontalAlign::default(), VerticalAlign::default()),
2040            offset: [0_f32, 0_f32],
2041            detect_result: MouseDetectResult::default(),
2042        }
2043    }
2044}
2045
2046impl MouseDetector {
2047    pub fn from_position_config(mut self, position_config: PositionConfig) -> Self {
2048        self.origin_position = position_config.origin_position;
2049        self.size = position_config.size;
2050        self.x_grid = position_config.x_grid;
2051        self.y_grid = position_config.y_grid;
2052        self.center_display = position_config.center_display;
2053        self.offset = position_config.offset;
2054        self
2055    }
2056
2057    #[inline]
2058    pub fn name(mut self, name: &str) -> Self {
2059        self.name = name.to_string();
2060        self
2061    }
2062
2063    #[inline]
2064    pub fn origin_position(mut self, x: f32, y: f32) -> Self {
2065        self.origin_position = [x, y];
2066        self
2067    }
2068
2069    #[inline]
2070    pub fn size(mut self, width: f32, height: f32) -> Self {
2071        self.size = [width, height];
2072        self
2073    }
2074
2075    #[inline]
2076    pub fn x_grid(mut self, fetch: u32, total: u32) -> Self {
2077        self.x_grid = [fetch, total];
2078        self
2079    }
2080
2081    #[inline]
2082    pub fn y_grid(mut self, fetch: u32, total: u32) -> Self {
2083        self.y_grid = [fetch, total];
2084        self
2085    }
2086
2087    #[inline]
2088    pub fn center_display(
2089        mut self,
2090        horizontal_align: HorizontalAlign,
2091        vertical_align: VerticalAlign,
2092    ) -> Self {
2093        self.center_display = (horizontal_align, vertical_align);
2094        self
2095    }
2096
2097    #[inline]
2098    pub fn offset(mut self, x: f32, y: f32) -> Self {
2099        self.offset = [x, y];
2100        self
2101    }
2102}
2103
2104/// RC资源最基本的错误处理。
2105#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2106pub enum RustConstructorError {
2107    /// 图片获取失败。
2108    ImageGetFailed { image_path: String },
2109    /// 图片未找到。
2110    ImageNotFound { image_name: String },
2111    /// 图片纹理未找到。
2112    ImageTextureNotFound { image_texture_name: String },
2113    /// 文本未找到。
2114    TextNotFound { text_name: String },
2115    /// 变量未找到。
2116    VariableNotFound { variable_name: String },
2117    /// 由于输入类型错误,变量值无法匹配。
2118    VariableTypeMismatch { variable_name: String },
2119    /// 分段时间未找到。
2120    SplitTimeNotFound { split_time_name: String },
2121    /// 开关外观数量不匹配。
2122    SwitchAppearanceMismatch { switch_name: String, differ: u32 },
2123    /// 开关填充资源类型不匹配。
2124    SwitchFillResourceMismatch {
2125        switch_name: String,
2126        fill_resource_name: String,
2127        fill_resource_type: String,
2128    },
2129    /// 开关未找到。
2130    SwitchNotFound { switch_name: String },
2131    /// 消息框已存在。
2132    MessageBoxAlreadyExists { message_box_name: String },
2133    /// 鼠标检测器未找到。
2134    MouseDetectorNotFound { mouse_detector_name: String },
2135    /// 获取字体失败。
2136    FontGetFailed { font_path: String },
2137    /// 字体未找到。
2138    FontNotFound { font_name: String },
2139    /// 矩形未找到。
2140    RectNotFound { rect_name: String },
2141    /// 资源未找到。
2142    ResourceNotFound {
2143        resource_name: String,
2144        resource_type: String,
2145    },
2146    /// 页面未找到。
2147    PageNotFound { page_name: String },
2148    /// 自定义错误。
2149    CustomError {
2150        error_name: String,
2151        error_message: String,
2152        error_annotation: String,
2153    },
2154}
2155
2156impl Display for RustConstructorError {
2157    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2158        Debug::fmt(self, f)
2159    }
2160}
2161
2162impl Error for RustConstructorError {}
2163
2164impl Default for RustConstructorError {
2165    fn default() -> Self {
2166        RustConstructorError::ImageGetFailed {
2167            image_path: "".to_string(),
2168        }
2169    }
2170}
2171
2172/// 水平对齐方法。
2173#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2174pub enum HorizontalAlign {
2175    /// 左对齐。
2176    #[default]
2177    Left,
2178    /// 居中对齐。
2179    Center,
2180    /// 右对齐。
2181    Right,
2182}
2183
2184/// 垂直对齐方法。
2185#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2186pub enum VerticalAlign {
2187    /// 顶部对齐。
2188    #[default]
2189    Top,
2190    /// 居中对齐。
2191    Center,
2192    /// 底部对齐。
2193    Bottom,
2194}
2195
2196/// 程序主体。
2197#[derive(Debug)]
2198pub struct App {
2199    /// 配置项,用于控制出现问题时是否panic。
2200    pub strict_mode: bool,
2201    /// 配置项,用于全局控制是否在调用资源时检查资源是否存在。
2202    pub safe_mode: bool,
2203    /// RC资源。
2204    pub rust_constructor_resource: Vec<Box<dyn RustConstructorResource>>,
2205    /// 渲染资源列表。
2206    pub render_resource_list: Vec<RenderResource>,
2207    /// 问题列表。
2208    pub problem_list: Vec<Problem>,
2209    /// RC资源刷新率。
2210    pub tick_interval: f32,
2211    /// 当前页面。
2212    pub current_page: String,
2213    /// 计时器。
2214    pub timer: Timer,
2215    /// 帧时间。
2216    pub frame_times: Vec<f32>,
2217    /// 上一帧时间。
2218    pub last_frame_time: Option<f64>,
2219}
2220
2221impl Default for App {
2222    fn default() -> Self {
2223        App {
2224            strict_mode: false,
2225            safe_mode: true,
2226            rust_constructor_resource: Vec::new(),
2227            render_resource_list: Vec::new(),
2228            problem_list: Vec::new(),
2229            tick_interval: 0.05,
2230            current_page: String::new(),
2231            timer: Timer::default(),
2232            frame_times: Vec::new(),
2233            last_frame_time: None,
2234        }
2235    }
2236}
2237
2238impl App {
2239    #[inline]
2240    pub fn strict_mode(mut self, strict_mode: bool) -> Self {
2241        self.strict_mode = strict_mode;
2242        self
2243    }
2244
2245    #[inline]
2246    pub fn safe_mode(mut self, safe_mode: bool) -> Self {
2247        self.safe_mode = safe_mode;
2248        self
2249    }
2250
2251    #[inline]
2252    pub fn tick_interval(mut self, tick_interval: f32) -> Self {
2253        self.tick_interval = tick_interval;
2254        self
2255    }
2256
2257    #[inline]
2258    pub fn current_page(mut self, current_page: &str) -> Self {
2259        self.current_page = current_page.to_string();
2260        self
2261    }
2262
2263    /// 整合所有页面需要一次性处理的功能。
2264    pub fn page_handler(&mut self, ctx: &Context) {
2265        // 更新帧数
2266        self.update_frame_stats(ctx);
2267        // 更新渲染资源列表
2268        self.render_resource_list = Vec::new();
2269        // 更新计时器
2270        self.update_timer();
2271        if let Ok(Some(pd)) = self.get_resource::<PageData>(&self.current_page.clone(), "PageData")
2272            && pd.forced_update
2273        {
2274            // 请求重新绘制界面
2275            ctx.request_repaint();
2276        };
2277    }
2278
2279    /// 运行时添加新页面。
2280    pub fn add_page(&mut self, mut page_data: PageData) {
2281        page_data.change_page_updated = false;
2282        page_data.enter_page_updated = false;
2283        self.rust_constructor_resource.push(Box::new(page_data));
2284    }
2285
2286    /// 切换页面。
2287    pub fn switch_page(
2288        &mut self,
2289        name: &str,
2290        safe_mode: Option<bool>,
2291    ) -> Result<(), RustConstructorError> {
2292        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2293            && !self.check_resource_exists(name, "PageData")
2294        {
2295            self.problem_report_custom(
2296                RustConstructorError::PageNotFound {
2297                    page_name: name.to_string(),
2298                },
2299                SeverityLevel::SevereWarning,
2300                self.problem_list.clone(),
2301            );
2302            return Err(RustConstructorError::PageNotFound {
2303                page_name: name.to_string(),
2304            });
2305        };
2306        self.current_page = name.to_string();
2307        let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2308        pd.enter_page_updated = false;
2309        self.timer.start_time = self.timer.total_time;
2310        self.update_timer();
2311        Ok(())
2312    }
2313
2314    /// 从指定列表中替换资源。
2315    pub fn replace_resource_custom<T>(
2316        &self,
2317        name: &str,
2318        discern_type: &str,
2319        resource: T,
2320        mut target: Vec<Box<dyn RustConstructorResource>>,
2321    ) -> Result<(), RustConstructorError>
2322    where
2323        T: RustConstructorResource + 'static,
2324    {
2325        if let Some(index) = self
2326            .rust_constructor_resource
2327            .iter()
2328            .position(|x| x.name() == name && x.expose_type() == discern_type)
2329        {
2330            target[index] = Box::new(resource);
2331            Ok(())
2332        } else {
2333            self.problem_report_custom(
2334                RustConstructorError::ResourceNotFound {
2335                    resource_name: name.to_string(),
2336                    resource_type: discern_type.to_string(),
2337                },
2338                SeverityLevel::SevereWarning,
2339                self.problem_list.clone(),
2340            );
2341            Err(RustConstructorError::ResourceNotFound {
2342                resource_name: name.to_string(),
2343                resource_type: discern_type.to_string(),
2344            })
2345        }
2346    }
2347
2348    /// 从列表中替换资源。
2349    pub fn replace_resource<T>(
2350        &mut self,
2351        name: &str,
2352        discern_type: &str,
2353        resource: T,
2354    ) -> Result<(), RustConstructorError>
2355    where
2356        T: RustConstructorResource + 'static,
2357    {
2358        if let Some(index) = self
2359            .rust_constructor_resource
2360            .iter()
2361            .position(|x| x.name() == name && x.expose_type() == discern_type)
2362        {
2363            self.rust_constructor_resource[index] = Box::new(resource);
2364            Ok(())
2365        } else {
2366            self.problem_report_custom(
2367                RustConstructorError::ResourceNotFound {
2368                    resource_name: name.to_string(),
2369                    resource_type: discern_type.to_string(),
2370                },
2371                SeverityLevel::SevereWarning,
2372                self.problem_list.clone(),
2373            );
2374            Err(RustConstructorError::ResourceNotFound {
2375                resource_name: name.to_string(),
2376                resource_type: discern_type.to_string(),
2377            })
2378        }
2379    }
2380
2381    /// 从列表中获取不可变资源。
2382    pub fn get_resource<T>(
2383        &self,
2384        name: &str,
2385        discern_type: &str,
2386    ) -> Result<Option<&T>, RustConstructorError>
2387    where
2388        T: RustConstructorResource + 'static,
2389    {
2390        if self.check_resource_exists(name, discern_type) {
2391            Ok(self
2392                .rust_constructor_resource
2393                .iter()
2394                .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2395                .and_then(|resource| resource.as_any().downcast_ref::<T>()))
2396        } else {
2397            self.problem_report_custom(
2398                RustConstructorError::ResourceNotFound {
2399                    resource_name: name.to_string(),
2400                    resource_type: discern_type.to_string(),
2401                },
2402                SeverityLevel::SevereWarning,
2403                self.problem_list.clone(),
2404            );
2405            Err(RustConstructorError::ResourceNotFound {
2406                resource_name: name.to_string(),
2407                resource_type: discern_type.to_string(),
2408            })
2409        }
2410    }
2411
2412    /// 从列表中获取可变资源。
2413    pub fn get_resource_mut<T>(
2414        &mut self,
2415        name: &str,
2416        discern_type: &str,
2417    ) -> Result<&mut T, RustConstructorError>
2418    where
2419        T: RustConstructorResource + 'static,
2420    {
2421        if self.check_resource_exists(name, discern_type) {
2422            Ok(self
2423                .rust_constructor_resource
2424                .iter_mut()
2425                .find(|resource| resource.name() == name && resource.expose_type() == discern_type)
2426                .and_then(|resource| resource.as_any_mut().downcast_mut::<T>())
2427                .unwrap())
2428        } else {
2429            self.problem_report_custom(
2430                RustConstructorError::ResourceNotFound {
2431                    resource_name: name.to_string(),
2432                    resource_type: discern_type.to_string(),
2433                },
2434                SeverityLevel::SevereWarning,
2435                self.problem_list.clone(),
2436            );
2437            Err(RustConstructorError::ResourceNotFound {
2438                resource_name: name.to_string(),
2439                resource_type: discern_type.to_string(),
2440            })
2441        }
2442    }
2443
2444    /// 检查是否存在特定资源。
2445    pub fn check_resource_exists(&self, name: &str, discern_type: &str) -> bool {
2446        self.rust_constructor_resource
2447            .iter()
2448            .any(|x| x.name() == name && x.expose_type() == discern_type)
2449    }
2450
2451    /// 添加字体资源。
2452    pub fn add_fonts(&mut self, mut font: Font) -> Result<(), RustConstructorError> {
2453        let mut fonts = FontDefinitions::default();
2454        if let Ok(font_read_data) = read(font.path.clone()) {
2455            let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
2456            fonts.font_data.insert(
2457                font.name.to_owned(),
2458                Arc::new(FontData::from_owned(
2459                    Arc::try_unwrap(font_data).ok().unwrap(),
2460                )),
2461            );
2462
2463            // 将字体添加到字体列表中
2464            fonts
2465                .families
2466                .entry(FontFamily::Proportional)
2467                .or_default()
2468                .insert(0, font.name.to_owned());
2469
2470            fonts
2471                .families
2472                .entry(FontFamily::Monospace)
2473                .or_default()
2474                .insert(0, font.name.to_owned());
2475
2476            font.font_definitions = fonts;
2477            self.rust_constructor_resource.push(Box::new(font));
2478            Ok(())
2479        } else {
2480            self.problem_report_custom(
2481                RustConstructorError::FontGetFailed {
2482                    font_path: font.path.to_string(),
2483                },
2484                SeverityLevel::SevereWarning,
2485                self.problem_list.clone(),
2486            );
2487            Err(RustConstructorError::FontGetFailed {
2488                font_path: font.path.to_string(),
2489            })
2490        }
2491    }
2492
2493    /// 输出字体资源。
2494    pub fn font(
2495        &mut self,
2496        name: &str,
2497        safe_mode: Option<bool>,
2498    ) -> Result<FontDefinitions, RustConstructorError> {
2499        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2500            && !self.check_resource_exists(name, "Font")
2501        {
2502            self.problem_report_custom(
2503                RustConstructorError::FontNotFound {
2504                    font_name: name.to_string(),
2505                },
2506                SeverityLevel::SevereWarning,
2507                self.problem_list.clone(),
2508            );
2509            return Err(RustConstructorError::FontNotFound {
2510                font_name: name.to_string(),
2511            });
2512        };
2513        let f = self.get_resource::<Font>(name, "Font").unwrap().unwrap();
2514        Ok(f.font_definitions.clone())
2515    }
2516
2517    /// 将所有已添加到RC的字体资源添加到egui中。
2518    pub fn register_all_fonts(&mut self, ctx: &Context, safe_mode: Option<bool>) {
2519        let mut font_definitions = FontDefinitions::default();
2520        let mut font_resources = Vec::new();
2521        for i in 0..self.rust_constructor_resource.len() {
2522            if let Some(f) = self.rust_constructor_resource[i]
2523                .as_any()
2524                .downcast_ref::<Font>()
2525            {
2526                font_resources.push(f.clone());
2527            };
2528        }
2529        for i in &font_resources {
2530            let font_name = i.name.clone();
2531            // 获取字体数据(返回 FontDefinitions)
2532            if let Ok(font_def) = self.font(&font_name, safe_mode) {
2533                // 从 font_def 中提取对应字体的 Arc<FontData>
2534                if let Some(font_data) = font_def.font_data.get(&font_name) {
2535                    font_definitions
2536                        .font_data
2537                        .insert(font_name.clone(), Arc::clone(font_data));
2538                    font_definitions
2539                        .families
2540                        .entry(FontFamily::Name(font_name.clone().into()))
2541                        .or_default()
2542                        .push(font_name.clone());
2543                };
2544
2545                // 将字体添加到字体列表中
2546                font_definitions
2547                    .families
2548                    .entry(FontFamily::Proportional)
2549                    .or_default()
2550                    .insert(0, font_name.to_owned());
2551
2552                font_definitions
2553                    .families
2554                    .entry(FontFamily::Monospace)
2555                    .or_default()
2556                    .insert(0, font_name.to_owned());
2557            };
2558        }
2559        ctx.set_fonts(font_definitions);
2560    }
2561
2562    /// 处理错误。
2563    fn problem_processor(
2564        &self,
2565        problem_type: RustConstructorError,
2566        severity_level: SeverityLevel,
2567    ) -> (String, String) {
2568        let (problem, annotation) = match problem_type.clone() {
2569            RustConstructorError::FontGetFailed { font_path } => (
2570                format!("Font get failed({:?}): {}", severity_level, font_path,),
2571                "Please check if the font file exists and the path is correct.".to_string(),
2572            ),
2573            RustConstructorError::FontNotFound { font_name } => (
2574                format!("Font not found({:?}): {}", severity_level, font_name,),
2575                "Please check whether the font has been added.".to_string(),
2576            ),
2577            RustConstructorError::ImageGetFailed { image_path } => (
2578                format!("Image get failed({:?}): {}", severity_level, image_path,),
2579                "Please check whether the image path is correct and whether the image has been added.".to_string(),
2580            ),
2581            RustConstructorError::ImageNotFound { image_name } => (
2582                format!("Image not found({:?}): {}", severity_level, image_name,),
2583                "Please check whether the image has been added.".to_string(),
2584            ),
2585            RustConstructorError::ImageTextureNotFound { image_texture_name } => (
2586                format!("Image texture not found({:?}): {}", severity_level, image_texture_name,),
2587                "Please check whether the image texture has been added.".to_string(),
2588            ),
2589            RustConstructorError::TextNotFound { text_name } => (
2590                format!("Text not found({:?}): {}", severity_level, text_name,),
2591                "Please check whether the text has been added.".to_string(),
2592            ),
2593            RustConstructorError::MessageBoxAlreadyExists { message_box_name } => (
2594                format!("Message box already exists({:?}): {}", severity_level, message_box_name,),
2595                "Please check whether the code for generating the message box has been accidentally called multiple times.".to_string(),
2596            ),
2597            RustConstructorError::MouseDetectorNotFound { mouse_detector_name } => (
2598                format!("Mouse detector not found({:?}): {}", severity_level, mouse_detector_name,),
2599                "Please check whether the mouse detector has been added.".to_string(),
2600            ),
2601            RustConstructorError::SplitTimeNotFound { split_time_name } => (
2602                format!("Split time not found({:?}): {}", severity_level, split_time_name,),
2603                "Please check whether the split time has been added.".to_string(),
2604            ),
2605            RustConstructorError::SwitchAppearanceMismatch {
2606                switch_name,
2607                differ,
2608            } => (
2609                format!(
2610                    "Switch appearance list's number of items is large / small {} more({:?}): {}",
2611                    differ, severity_level, switch_name
2612                ),
2613                "Please check whether the number of appearance list items matches the number of enabled animations.".to_string(),
2614            ),
2615            RustConstructorError::SwitchNotFound { switch_name } => (
2616                format!("Switch not found({:?}): {}", severity_level, switch_name,),
2617                "Please check whether the switch has been added.".to_string(),
2618            ),
2619            RustConstructorError::SwitchFillResourceMismatch { switch_name, fill_resource_name, fill_resource_type } => (
2620                format!("Switch fill resource mismatch({:?}): Resource {} of switch {} is not of type {}", severity_level, fill_resource_name, switch_name, fill_resource_type,),
2621                "Please check whether the imported fill resource is correctly typed.".to_string(),
2622            ),
2623            RustConstructorError::PageNotFound { page_name } => (
2624                format!("Page not found({:?}): {}", severity_level, page_name,),
2625                "Please check whether the page has been added.".to_string(),
2626            ),
2627            RustConstructorError::VariableNotFound { variable_name } => (
2628                format!("Variable not found({:?}): {}", severity_level, variable_name,),
2629                "Please check whether the variable has been added.".to_string(),
2630            ),
2631            RustConstructorError::VariableTypeMismatch { variable_name } => (
2632                format!("Variable type mismatch({:?}): {}", severity_level, variable_name,),
2633                "Please check whether the generics used for matching are filled correctly.".to_string(),
2634            ),
2635            RustConstructorError::RectNotFound { rect_name } => (
2636                format!("Rect not found({:?}): {}", severity_level, rect_name,),
2637                "Please check whether the rect has been added.".to_string(),
2638            ),
2639            RustConstructorError::ResourceNotFound {
2640                resource_name,
2641                resource_type,
2642            } => (
2643                format!(
2644                    "Resource not found({:?}): {}(\"{}\")",
2645                    severity_level, resource_type, resource_name,
2646                ),
2647                "Please check whether the resource has been added.".to_string(),
2648            ),
2649            RustConstructorError::CustomError { error_name, error_message, error_annotation } => (
2650                format!("Custom error({}, {:?}): {}", error_name, severity_level, error_message),
2651                error_annotation
2652            )
2653        };
2654        // 如果处于严格模式下,则直接崩溃!
2655        if self.strict_mode {
2656            panic!(
2657                "Rust Constructor Error({:?}): {}\nnote: {}",
2658                problem_type, problem, annotation
2659            );
2660        };
2661        (problem, annotation)
2662    }
2663
2664    /// 发生问题时推送报告。
2665    pub fn problem_report(
2666        &mut self,
2667        problem_type: RustConstructorError,
2668        severity_level: SeverityLevel,
2669    ) {
2670        let (problem, annotation) =
2671            self.problem_processor(problem_type.clone(), severity_level);
2672        self.problem_list.push(Problem {
2673            severity_level,
2674            problem,
2675            annotation,
2676            report_state: ReportState {
2677                current_page: self.current_page.clone(),
2678                current_total_runtime: self.timer.total_time,
2679                current_page_runtime: self.timer.now_time,
2680            },
2681            problem_type: problem_type.clone(),
2682        });
2683    }
2684
2685    /// 发生问题时向指定列表推送报告。
2686    pub fn problem_report_custom(
2687        &self,
2688        problem_type: RustConstructorError,
2689        severity_level: SeverityLevel,
2690        mut problem_storage: Vec<Problem>,
2691    ) {
2692        let (problem, annotation) =
2693            self.problem_processor(problem_type.clone(), severity_level);
2694        problem_storage.push(Problem {
2695            severity_level,
2696            problem,
2697            annotation,
2698            report_state: ReportState {
2699                current_page: self.current_page.clone(),
2700                current_total_runtime: self.timer.total_time,
2701                current_page_runtime: self.timer.now_time,
2702            },
2703            problem_type: problem_type.clone(),
2704        });
2705    }
2706
2707    /// 检查页面是否已完成首次加载。
2708    pub fn check_updated(
2709        &mut self,
2710        name: &str,
2711        safe_mode: Option<bool>,
2712    ) -> Result<bool, RustConstructorError> {
2713        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2714            && !self.check_resource_exists(name, "PageData")
2715        {
2716            self.problem_report_custom(
2717                RustConstructorError::PageNotFound {
2718                    page_name: name.to_string(),
2719                },
2720                SeverityLevel::SevereWarning,
2721                self.problem_list.clone(),
2722            );
2723            return Err(RustConstructorError::PageNotFound {
2724                page_name: name.to_string(),
2725            });
2726        };
2727        let pd = self
2728            .get_resource::<PageData>(name, "PageData")
2729            .unwrap()
2730            .unwrap()
2731            .clone();
2732        if !pd.change_page_updated {
2733            self.new_page_update(name, safe_mode).unwrap();
2734        };
2735        Ok(pd.change_page_updated)
2736    }
2737
2738    /// 检查页面是否已完成加载。
2739    pub fn check_enter_updated(
2740        &mut self,
2741        name: &str,
2742        safe_mode: Option<bool>,
2743    ) -> Result<bool, RustConstructorError> {
2744        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2745            && !self.check_resource_exists(name, "PageData")
2746        {
2747            self.problem_report_custom(
2748                RustConstructorError::PageNotFound {
2749                    page_name: name.to_string(),
2750                },
2751                SeverityLevel::SevereWarning,
2752                self.problem_list.clone(),
2753            );
2754            return Err(RustConstructorError::PageNotFound {
2755                page_name: name.to_string(),
2756            });
2757        };
2758        let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2759        let return_value = pd.enter_page_updated;
2760        pd.enter_page_updated = true;
2761        Ok(return_value)
2762    }
2763
2764    /// 进入新页面时的更新。
2765    pub fn new_page_update(
2766        &mut self,
2767        name: &str,
2768        safe_mode: Option<bool>,
2769    ) -> Result<(), RustConstructorError> {
2770        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2771            && !self.check_resource_exists(name, "PageData")
2772        {
2773            self.problem_report_custom(
2774                RustConstructorError::PageNotFound {
2775                    page_name: name.to_string(),
2776                },
2777                SeverityLevel::SevereWarning,
2778                self.problem_list.clone(),
2779            );
2780            return Err(RustConstructorError::PageNotFound {
2781                page_name: name.to_string(),
2782            });
2783        }
2784        self.timer.start_time = self.timer.total_time;
2785        self.update_timer();
2786        let pd = self.get_resource_mut::<PageData>(name, "PageData").unwrap();
2787        pd.change_page_updated = true;
2788        Ok(())
2789    }
2790
2791    /// 更新帧数。
2792    pub fn update_frame_stats(&mut self, ctx: &Context) {
2793        let current_time = ctx.input(|i| i.time);
2794        if let Some(last) = self.last_frame_time {
2795            let delta = (current_time - last) as f32;
2796            self.frame_times.push(delta);
2797            const MAX_SAMPLES: usize = 120;
2798            if self.frame_times.len() > MAX_SAMPLES {
2799                let remove_count = self.frame_times.len() - MAX_SAMPLES;
2800                self.frame_times.drain(0..remove_count);
2801            }
2802        }
2803        self.last_frame_time = Some(current_time);
2804    }
2805
2806    /// 更新帧数显示。
2807    pub fn current_fps(&self) -> f32 {
2808        if self.frame_times.is_empty() {
2809            0.0
2810        } else {
2811            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
2812        }
2813    }
2814
2815    /// 添加分段时间。
2816    pub fn add_split_time(&mut self, mut split_time: SplitTime) {
2817        split_time.time = [self.timer.now_time, self.timer.total_time];
2818        self.rust_constructor_resource.push(Box::new(split_time));
2819    }
2820
2821    /// 重置分段时间。
2822    pub fn reset_split_time(
2823        &mut self,
2824        name: &str,
2825        safe_mode: Option<bool>,
2826    ) -> Result<(), RustConstructorError> {
2827        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2828            && !self.check_resource_exists(name, "SplitTime")
2829        {
2830            self.problem_report_custom(
2831                RustConstructorError::SplitTimeNotFound {
2832                    split_time_name: name.to_string(),
2833                },
2834                SeverityLevel::SevereWarning,
2835                self.problem_list.clone(),
2836            );
2837            return Err(RustConstructorError::SplitTimeNotFound {
2838                split_time_name: name.to_string(),
2839            });
2840        };
2841        let new_time = [self.timer.now_time, self.timer.total_time];
2842        let st = self
2843            .get_resource_mut::<SplitTime>(name, "SplitTime")
2844            .unwrap();
2845        st.time = new_time;
2846        Ok(())
2847    }
2848
2849    /// 输出分段时间。
2850    pub fn split_time(
2851        &self,
2852        name: &str,
2853        safe_mode: Option<bool>,
2854    ) -> Result<[f32; 2], RustConstructorError> {
2855        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2856            && !self.check_resource_exists(name, "SplitTime")
2857        {
2858            self.problem_report_custom(
2859                RustConstructorError::SplitTimeNotFound {
2860                    split_time_name: name.to_string(),
2861                },
2862                SeverityLevel::SevereWarning,
2863                self.problem_list.clone(),
2864            );
2865            return Err(RustConstructorError::SplitTimeNotFound {
2866                split_time_name: name.to_string(),
2867            });
2868        };
2869        let st = self
2870            .get_resource::<SplitTime>(name, "SplitTime")
2871            .unwrap()
2872            .unwrap();
2873        Ok(st.time)
2874    }
2875
2876    /// 更新计时器。
2877    pub fn update_timer(&mut self) {
2878        let elapsed = self.timer.timer.elapsed();
2879        let seconds = elapsed.as_secs();
2880        let milliseconds = elapsed.subsec_millis();
2881        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
2882        self.timer.now_time = self.timer.total_time - self.timer.start_time
2883    }
2884
2885    /// 添加矩形资源。
2886    pub fn add_custom_rect(&mut self, custom_rect: CustomRect) {
2887        self.rust_constructor_resource.push(Box::new(custom_rect));
2888    }
2889
2890    /// 显示矩形资源。
2891    pub fn custom_rect(
2892        &mut self,
2893        name: &str,
2894        ui: &mut Ui,
2895        ctx: &Context,
2896        safe_mode: Option<bool>,
2897    ) -> Result<(), RustConstructorError> {
2898        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2899            && !self.check_resource_exists(name, "CustomRect")
2900        {
2901            self.problem_report_custom(
2902                RustConstructorError::RectNotFound {
2903                    rect_name: name.to_string(),
2904                },
2905                SeverityLevel::SevereWarning,
2906                self.problem_list.clone(),
2907            );
2908            return Err(RustConstructorError::RectNotFound {
2909                rect_name: name.to_string(),
2910            });
2911        };
2912        let render_resource_list = &mut self.render_resource_list.clone();
2913        let cr = self
2914            .get_resource_mut::<CustomRect>(name, "CustomRect")
2915            .unwrap();
2916        cr.reg_render_resource(render_resource_list);
2917        cr.position[0] = match cr.x_grid[1] {
2918            0 => cr.origin_position[0],
2919            _ => {
2920                (ctx.available_rect().width() as f64 / cr.x_grid[1] as f64 * cr.x_grid[0] as f64)
2921                    as f32
2922                    + cr.origin_position[0]
2923            }
2924        };
2925        cr.position[1] = match cr.y_grid[1] {
2926            0 => cr.origin_position[1],
2927            _ => {
2928                (ctx.available_rect().height() as f64 / cr.y_grid[1] as f64 * cr.y_grid[0] as f64)
2929                    as f32
2930                    + cr.origin_position[1]
2931            }
2932        };
2933        match cr.center_display.0 {
2934            HorizontalAlign::Left => {}
2935            HorizontalAlign::Center => cr.position[0] -= cr.size[0] / 2.0,
2936            HorizontalAlign::Right => cr.position[0] -= cr.size[0],
2937        };
2938        match cr.center_display.1 {
2939            VerticalAlign::Top => {}
2940            VerticalAlign::Center => cr.position[1] -= cr.size[1] / 2.0,
2941            VerticalAlign::Bottom => cr.position[1] -= cr.size[1],
2942        };
2943        cr.position[0] += cr.offset[0];
2944        cr.position[1] += cr.offset[1];
2945        ui.painter().rect(
2946            Rect::from_min_max(
2947                Pos2::new(cr.position[0], cr.position[1]),
2948                Pos2::new(cr.position[0] + cr.size[0], cr.position[1] + cr.size[1]),
2949            ),
2950            cr.rounding,
2951            Color32::from_rgba_unmultiplied(cr.color[0], cr.color[1], cr.color[2], cr.color[3]),
2952            Stroke {
2953                width: cr.border_width,
2954                color: Color32::from_rgba_unmultiplied(
2955                    cr.border_color[0],
2956                    cr.border_color[1],
2957                    cr.border_color[2],
2958                    cr.border_color[3],
2959                ),
2960            },
2961            StrokeKind::Inside,
2962        );
2963        Ok(())
2964    }
2965
2966    /// 添加文本资源。
2967    pub fn add_text(&mut self, text: Text) {
2968        self.rust_constructor_resource.push(Box::new(text));
2969    }
2970
2971    /// 显示文本资源。
2972    pub fn text(
2973        &mut self,
2974        name: &str,
2975        ui: &mut Ui,
2976        ctx: &Context,
2977        safe_mode: Option<bool>,
2978    ) -> Result<(), RustConstructorError> {
2979        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
2980            && !self.check_resource_exists(name, "Text")
2981        {
2982            self.problem_report_custom(
2983                RustConstructorError::TextNotFound {
2984                    text_name: name.to_string(),
2985                },
2986                SeverityLevel::SevereWarning,
2987                self.problem_list.clone(),
2988            );
2989            return Err(RustConstructorError::TextNotFound {
2990                text_name: name.to_string(),
2991            });
2992        };
2993        let mut t = self
2994            .get_resource::<Text>(name, "Text")
2995            .unwrap()
2996            .unwrap()
2997            .clone();
2998        t.reg_render_resource(&mut self.render_resource_list);
2999        // 计算文本大小
3000        let galley: Arc<Galley> = ui.fonts_mut(|f| {
3001            f.layout(
3002                t.content.to_string(),
3003                if !t.font.is_empty() {
3004                    if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3005                        && !self.check_resource_exists(&t.font.clone(), "Font")
3006                    {
3007                        self.problem_report_custom(
3008                            RustConstructorError::FontNotFound {
3009                                font_name: t.font.clone(),
3010                            },
3011                            SeverityLevel::MildWarning,
3012                            self.problem_list.clone(),
3013                        );
3014                        FontId::new(t.font_size, FontFamily::Name(t.font.clone().into()))
3015                    } else {
3016                        FontId::proportional(t.font_size)
3017                    }
3018                } else {
3019                    FontId::proportional(t.font_size)
3020                },
3021                Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]),
3022                t.wrap_width,
3023            )
3024        });
3025        t.size = [galley.size().x, galley.size().y];
3026        t.position[0] = match t.x_grid[1] {
3027            0 => t.origin_position[0],
3028            _ => {
3029                (ctx.available_rect().width() as f64 / t.x_grid[1] as f64 * t.x_grid[0] as f64)
3030                    as f32
3031                    + t.origin_position[0]
3032            }
3033        };
3034        t.position[1] = match t.y_grid[1] {
3035            0 => t.origin_position[1],
3036            _ => {
3037                (ctx.available_rect().height() as f64 / t.y_grid[1] as f64 * t.y_grid[0] as f64)
3038                    as f32
3039                    + t.origin_position[1]
3040            }
3041        };
3042        let pos_x = match t.center_display.0 {
3043            HorizontalAlign::Left => t.position[0],
3044            HorizontalAlign::Center => t.position[0] - t.size[0] / 2.0,
3045            HorizontalAlign::Right => t.position[0] - t.size[0],
3046        };
3047        let pos_y = match t.center_display.1 {
3048            VerticalAlign::Top => t.position[1],
3049            VerticalAlign::Center => t.position[1] - t.size[1] / 2.0,
3050            VerticalAlign::Bottom => t.position[1] - t.size[1],
3051        };
3052        t.position[0] += t.offset[0];
3053        t.position[1] += t.offset[1];
3054        // 使用绝对定位放置文本
3055        let position = Pos2::new(pos_x, pos_y);
3056
3057        let rect = Rect::from_min_size(position, t.size.into());
3058        // 绘制背景颜色
3059        ui.painter().rect_filled(
3060            rect,
3061            t.background_rounding,
3062            Color32::from_rgba_unmultiplied(
3063                t.background_color[0],
3064                t.background_color[1],
3065                t.background_color[2],
3066                t.background_color[3],
3067            ),
3068        ); // 背景色
3069        // 绘制文本
3070        ui.painter().galley(
3071            position,
3072            galley.clone(),
3073            Color32::from_rgba_unmultiplied(
3074                t.color[0], t.color[1], t.color[2], t.color[3], // 应用透明度
3075            ),
3076        );
3077
3078        // 查找超链接索引值
3079        if t.last_frame_content != t.content {
3080            t.hyperlink_index.clear();
3081
3082            // 创建字节索引到字符索引的映射
3083            let byte_to_char_map: std::collections::HashMap<usize, usize> = t
3084                .content
3085                .char_indices()
3086                .enumerate()
3087                .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
3088                .collect();
3089
3090            for (text, method) in &t.hyperlink_text {
3091                let matches: Vec<(usize, &str)> = t.content.match_indices(text).collect();
3092                let text_char_count = text.chars().count();
3093
3094                if let HyperlinkSelectMethod::All(url) = method {
3095                    for (byte_index, _) in matches {
3096                        if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3097                            t.hyperlink_index.push((
3098                                start_char_index,
3099                                start_char_index + text_char_count,
3100                                url.clone(),
3101                            ));
3102                        };
3103                    }
3104                } else if let HyperlinkSelectMethod::Segment(list) = method {
3105                    for (index, url) in list {
3106                        if *index >= matches.len() {
3107                            continue;
3108                        };
3109                        let (byte_index, _) = matches[*index];
3110                        if let Some(&start_char_index) = byte_to_char_map.get(&byte_index) {
3111                            t.hyperlink_index.push((
3112                                start_char_index,
3113                                start_char_index + text_char_count,
3114                                url.clone(),
3115                            ));
3116                        };
3117                    }
3118                };
3119            }
3120        };
3121
3122        // 绘制超链接
3123        for (start, end, _) in &t.hyperlink_index {
3124            // 获取超链接文本的范围
3125            let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3126            let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3127
3128            let start_pos = start_cursor.left_top();
3129            let end_pos = end_cursor.right_top();
3130            // 绘制超链接下划线
3131            // 检查超链接是否跨行
3132            if start_cursor.min.y == end_cursor.min.y {
3133                // 单行超链接
3134                let underline_y =
3135                    position.y + start_pos.y + galley.rows.first().map_or(14.0, |row| row.height())
3136                        - 2.0;
3137
3138                // 绘制下划线
3139                let color =
3140                    Color32::from_rgba_unmultiplied(t.color[0], t.color[1], t.color[2], t.color[3]);
3141
3142                ui.painter().line_segment(
3143                    [
3144                        Pos2::new(position.x + start_pos.x, underline_y),
3145                        Pos2::new(position.x + end_pos.x, underline_y),
3146                    ],
3147                    Stroke::new(t.font_size / 10_f32, color),
3148                );
3149            } else {
3150                // 多行超链接
3151                let row_height = galley.rows.first().map_or(14.0, |row| row.height()); // 默认行高14.0
3152
3153                // 计算起始行和结束行的索引
3154                let start_row = (start_pos.y / row_height).round() as usize;
3155                let end_row = (end_pos.y / row_height).round() as usize;
3156
3157                for row in start_row..=end_row {
3158                    let row_y = position.y + row as f32 * row_height + row_height - 2.0; // 行底部稍微上移一点绘制下划线
3159
3160                    // 获取当前行的矩形范围
3161                    if let Some(current_row) = galley.rows.get(row) {
3162                        let row_rect = current_row.rect();
3163
3164                        let color = Color32::from_rgba_unmultiplied(
3165                            t.color[0], t.color[1], t.color[2], t.color[3],
3166                        );
3167
3168                        if row == start_row {
3169                            // 第一行从文本开始位置到行尾
3170                            ui.painter().line_segment(
3171                                [
3172                                    Pos2::new(position.x + start_pos.x, row_y),
3173                                    Pos2::new(position.x + row_rect.max.x, row_y),
3174                                ],
3175                                Stroke::new(t.font_size / 10_f32, color),
3176                            );
3177                        } else if row == end_row {
3178                            // 最后一行从行首到文本结束位置
3179                            ui.painter().line_segment(
3180                                [
3181                                    Pos2::new(position.x + row_rect.min.x, row_y),
3182                                    Pos2::new(position.x + end_pos.x, row_y),
3183                                ],
3184                                Stroke::new(t.font_size / 10_f32, color),
3185                            );
3186                        } else {
3187                            // 中间整行下划线
3188                            ui.painter().line_segment(
3189                                [
3190                                    Pos2::new(position.x + row_rect.min.x, row_y),
3191                                    Pos2::new(position.x + row_rect.max.x, row_y),
3192                                ],
3193                                Stroke::new(t.font_size / 10_f32, color),
3194                            );
3195                        };
3196                    };
3197                }
3198            };
3199        }
3200
3201        if t.selectable {
3202            if !self.check_resource_exists(&t.name, "MouseDetector") {
3203                self.add_mouse_detector(
3204                    MouseDetector::default()
3205                        .name(&t.name)
3206                        .from_position_config(PositionConfig::from_text(t.clone()))
3207                        .offset(-20_f32, -5_f32)
3208                        .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3209                );
3210            } else {
3211                self.replace_resource(
3212                    &t.name,
3213                    "MouseDetector",
3214                    MouseDetector::default()
3215                        .name(&t.name)
3216                        .from_position_config(PositionConfig::from_text(t.clone()))
3217                        .offset(-20_f32, -5_f32)
3218                        .size(t.size[0] + 40_f32, t.size[1] + 10_f32),
3219                )
3220                .unwrap();
3221            };
3222
3223            // 处理选择逻辑
3224            let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
3225                let relative_pos = pointer_pos - position.to_vec2();
3226                let cursor = galley.cursor_from_pos(relative_pos);
3227                cursor.index
3228            };
3229
3230            self.mouse_detector(&t.name, ui, ctx, MouseDetectorLevel::Default, safe_mode)
3231                .unwrap();
3232            let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
3233            let detect_result = self.check_mouse_detect_result(&t.name, safe_mode).unwrap();
3234            if !detect_result.clicked
3235                && (fullscreen_detect_result.any_click() || fullscreen_detect_result.any_pressed())
3236            {
3237                t.selection = None;
3238            };
3239
3240            if (detect_result.clicked || detect_result.drag_started.unwrap())
3241                && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3242            {
3243                let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3244                t.selection = Some((cursor, cursor));
3245            };
3246
3247            if detect_result.dragged.unwrap()
3248                && t.selection.is_some()
3249                && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3250            {
3251                let cursor = cursor_at_pointer(pointer_pos.to_vec2());
3252                if let Some((start, _)) = t.selection {
3253                    t.selection = Some((start, cursor));
3254                };
3255            };
3256
3257            if t.selection.is_some()
3258                && ui.input(|input| input.key_released(Key::A) && input.modifiers.command)
3259            {
3260                t.selection = Some((0, t.content.chars().count()));
3261            };
3262
3263            // 处理复制操作
3264            let copy_triggered = ui.input(|input| {
3265                let c_released = input.key_released(Key::C);
3266                let cmd_pressed = input.modifiers.command;
3267                c_released && cmd_pressed
3268            });
3269            if copy_triggered && let Some((start, end)) = t.selection {
3270                let (start, end) = (start.min(end), start.max(end));
3271                let chars: Vec<char> = t.content.chars().collect();
3272                if start <= chars.len() && end <= chars.len() && start < end {
3273                    let selected_text: String = chars[start..end].iter().collect();
3274                    ui.ctx().copy_text(selected_text);
3275                };
3276            };
3277
3278            // 绘制选择区域背景
3279            if let Some((start, end)) = t.selection {
3280                let (start, end) = (start.min(end), start.max(end));
3281                if start != end {
3282                    // 获取选择区域的范围
3283                    let start_cursor = galley.pos_from_cursor(CCursor::new(start));
3284                    let end_cursor = galley.pos_from_cursor(CCursor::new(end));
3285
3286                    let start_pos = start_cursor.left_top();
3287                    let end_pos = end_cursor.right_top();
3288                    // 选择框绘制
3289                    if start_pos.y == end_pos.y {
3290                        // 单行选择
3291                        let rows = &galley.rows;
3292                        let row_height = if !rows.is_empty() {
3293                            // 获取实际行的高度
3294                            if let Some(row) = rows.first() {
3295                                row.height()
3296                            } else {
3297                                t.size[1] / t.content.lines().count() as f32
3298                            }
3299                        } else {
3300                            t.size[1] / t.content.lines().count() as f32
3301                        };
3302
3303                        let selection_rect = Rect::from_min_max(
3304                            Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3305                            Pos2::new(
3306                                position.x + end_pos.x,
3307                                position.y + start_pos.y + row_height,
3308                            ),
3309                        );
3310                        ui.painter().rect_filled(
3311                            selection_rect,
3312                            0.0,
3313                            Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3314                        );
3315                    } else {
3316                        // 多行选择 - 为每行创建精确的矩形
3317                        let rows = &galley.rows;
3318                        let row_height = if !rows.is_empty() {
3319                            rows[0].height()
3320                        } else {
3321                            t.size[1] / t.content.lines().count() as f32
3322                        };
3323
3324                        // 计算选择的上下边界
3325                        let selection_top = position.y + start_pos.y.min(end_pos.y);
3326                        let selection_bottom = position.y + start_pos.y.max(end_pos.y);
3327
3328                        // 确定起始行和结束行的索引
3329                        let start_row_index = (start_pos.y / row_height).floor() as usize;
3330                        let end_row_index = (end_pos.y / row_height).floor() as usize;
3331                        let (first_row_index, last_row_index) = if start_row_index <= end_row_index
3332                        {
3333                            (start_row_index, end_row_index)
3334                        } else {
3335                            (end_row_index, start_row_index)
3336                        };
3337
3338                        for (i, row) in rows.iter().enumerate() {
3339                            let row_y = position.y + row_height * i as f32;
3340                            let row_bottom = row_y + row_height;
3341                            // 检查当前行是否与选择区域相交
3342                            if row_bottom > selection_top && row_y <= selection_bottom {
3343                                let left = if i == first_row_index {
3344                                    // 首行 - 从选择开始位置开始
3345                                    position.x + start_pos.x
3346                                } else {
3347                                    // 非首行 - 从行首开始
3348                                    position.x + row.rect().min.x
3349                                };
3350
3351                                let right = if i == last_row_index {
3352                                    // 尾行 - 到选择结束位置结束
3353                                    position.x + end_pos.x
3354                                } else {
3355                                    // 非尾行 - 到行尾结束
3356                                    position.x + row.rect().max.x
3357                                };
3358
3359                                let selection_rect = Rect::from_min_max(
3360                                    Pos2::new(left, row_y),
3361                                    Pos2::new(right, row_bottom),
3362                                );
3363
3364                                // 确保矩形有效
3365                                if selection_rect.width() > 0.0 && selection_rect.height() > 0.0 {
3366                                    ui.painter().rect_filled(
3367                                        selection_rect,
3368                                        0.0,
3369                                        Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3370                                    );
3371                                };
3372                            };
3373                        }
3374                    };
3375                };
3376            };
3377        };
3378
3379        // 处理超链接操作
3380        for (start, end, url) in &t.hyperlink_index {
3381            // 获取超链接文本的范围
3382            let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
3383            let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
3384
3385            let start_pos = start_cursor.left_top();
3386            let end_pos = end_cursor.right_top();
3387
3388            let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3389
3390            // 为超链接创建交互响应对象
3391            let link_responses = if start_cursor.min.y == end_cursor.min.y {
3392                // 单行超链接
3393                let link_rect = Rect::from_min_max(
3394                    Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3395                    Pos2::new(
3396                        position.x + end_pos.x,
3397                        position.y + start_pos.y + row_height,
3398                    ),
3399                );
3400                vec![ui.interact(
3401                    link_rect,
3402                    egui::Id::new(format!("link_{}_{}_{}", t.name, start, end)),
3403                    egui::Sense::click(),
3404                )]
3405            } else {
3406                // 多行超链接
3407                let start_row = (start_pos.y / row_height).round() as usize;
3408                let end_row = (end_pos.y / row_height).round() as usize;
3409                let mut responses = Vec::new();
3410
3411                for row in start_row..=end_row {
3412                    if let Some(current_row) = galley.rows.get(row) {
3413                        let row_rect = current_row.rect();
3414                        let row_y = position.y + row as f32 * row_height;
3415
3416                        let link_rect = if row == start_row {
3417                            // 第一行从文本开始位置到行尾
3418                            Rect::from_min_max(
3419                                Pos2::new(position.x + start_pos.x, row_y),
3420                                Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3421                            )
3422                        } else if row == end_row {
3423                            // 最后一行从行首到文本结束位置
3424                            Rect::from_min_max(
3425                                Pos2::new(position.x + row_rect.min.x, row_y),
3426                                Pos2::new(position.x + end_pos.x, row_y + row_height),
3427                            )
3428                        } else {
3429                            // 中间整行
3430                            Rect::from_min_max(
3431                                Pos2::new(position.x + row_rect.min.x, row_y),
3432                                Pos2::new(position.x + row_rect.max.x, row_y + row_height),
3433                            )
3434                        };
3435
3436                        responses.push(ui.interact(
3437                            link_rect,
3438                            Id::new(format!("link_{}_{}_{}_row_{}", t.name, start, end, row)),
3439                            Sense::click(),
3440                        ));
3441                    };
3442                }
3443                responses
3444            };
3445
3446            // 检查是否正在点击这个超链接
3447            let mut is_pressing_link = false;
3448            for link_response in &link_responses {
3449                if link_response.is_pointer_button_down_on() && !link_response.drag_started() {
3450                    t.selection = None;
3451                    if let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos()) {
3452                        let relative_pos = pointer_pos - position.to_vec2();
3453                        let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3454                        if cursor.index >= *start && cursor.index <= *end {
3455                            is_pressing_link = true;
3456                            break;
3457                        };
3458                    };
3459                };
3460            }
3461
3462            // 检查是否释放了鼠标(点击完成)
3463            let mut clicked_on_link = false;
3464            for link_response in &link_responses {
3465                if link_response.clicked()
3466                    && let Some(pointer_pos) = ui.input(|i| i.pointer.interact_pos())
3467                {
3468                    let relative_pos = pointer_pos - position.to_vec2();
3469                    let cursor = galley.cursor_from_pos(relative_pos.to_vec2());
3470                    if cursor.index >= *start && cursor.index <= *end {
3471                        clicked_on_link = true;
3472                        break;
3473                    };
3474                };
3475            }
3476
3477            if clicked_on_link {
3478                // 执行超链接跳转
3479                if !url.is_empty() {
3480                    ui.ctx().open_url(OpenUrl::new_tab(url));
3481                };
3482            };
3483
3484            // 绘制超链接高亮(如果正在点击或悬停)
3485            if is_pressing_link {
3486                if start_cursor.min.y == end_cursor.min.y {
3487                    // 单行超链接高亮
3488                    let selection_rect = Rect::from_min_max(
3489                        Pos2::new(position.x + start_pos.x, position.y + start_pos.y),
3490                        Pos2::new(
3491                            position.x + end_pos.x,
3492                            position.y
3493                                + start_pos.y
3494                                + galley.rows.first().map_or(14.0, |row| row.height()),
3495                        ),
3496                    );
3497                    ui.painter().rect_filled(
3498                        selection_rect,
3499                        0.0,
3500                        Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3501                    );
3502                } else {
3503                    // 多行超链接高亮
3504                    let row_height = galley.rows.first().map_or(14.0, |row| row.height());
3505                    let start_row = (start_pos.y / row_height).round() as usize;
3506                    let end_row = (end_pos.y / row_height).round() as usize;
3507
3508                    for row in start_row..=end_row {
3509                        if let Some(current_row) = galley.rows.get(row) {
3510                            let row_rect = current_row.rect();
3511
3512                            if row == start_row {
3513                                // 第一行从文本开始位置到行尾
3514                                let selection_rect = Rect::from_min_max(
3515                                    Pos2::new(
3516                                        position.x + start_pos.x,
3517                                        position.y + row as f32 * row_height,
3518                                    ),
3519                                    Pos2::new(
3520                                        position.x + row_rect.max.x,
3521                                        position.y + row as f32 * row_height + row_height,
3522                                    ),
3523                                );
3524                                ui.painter().rect_filled(
3525                                    selection_rect,
3526                                    0.0,
3527                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3528                                );
3529                            } else if row == end_row {
3530                                // 最后一行从行首到文本结束位置
3531                                let selection_rect = Rect::from_min_max(
3532                                    Pos2::new(
3533                                        position.x + row_rect.min.x,
3534                                        position.y + row as f32 * row_height,
3535                                    ),
3536                                    Pos2::new(
3537                                        position.x + end_pos.x,
3538                                        position.y + row as f32 * row_height + row_height,
3539                                    ),
3540                                );
3541                                ui.painter().rect_filled(
3542                                    selection_rect,
3543                                    0.0,
3544                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3545                                );
3546                            } else {
3547                                // 中间整行高亮
3548                                let selection_rect = Rect::from_min_max(
3549                                    Pos2::new(
3550                                        position.x + row_rect.min.x,
3551                                        position.y + row as f32 * row_height,
3552                                    ),
3553                                    Pos2::new(
3554                                        position.x + row_rect.max.x,
3555                                        position.y + row as f32 * row_height + row_height,
3556                                    ),
3557                                );
3558                                ui.painter().rect_filled(
3559                                    selection_rect,
3560                                    0.0,
3561                                    Color32::from_rgba_unmultiplied(0, 120, 255, 100),
3562                                );
3563                            };
3564                        };
3565                    }
3566                };
3567            };
3568        }
3569        t.last_frame_content = t.content.clone();
3570        self.replace_resource(name, "Text", t).unwrap();
3571        Ok(())
3572    }
3573
3574    /// 添加变量资源。
3575    pub fn add_var<T: Debug + 'static>(&mut self, variable: Variable<T>) {
3576        self.rust_constructor_resource.push(Box::new(variable));
3577    }
3578
3579    /// 修改变量资源。
3580    pub fn modify_var<T: Debug + 'static>(
3581        &mut self,
3582        name: &str,
3583        value: Option<T>,
3584        safe_mode: Option<bool>,
3585    ) -> Result<(), RustConstructorError> {
3586        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3587            && !self.check_resource_exists(name, "Variable")
3588        {
3589            self.problem_report_custom(
3590                RustConstructorError::VariableNotFound {
3591                    variable_name: name.to_string(),
3592                },
3593                SeverityLevel::SevereWarning,
3594                self.problem_list.clone(),
3595            );
3596            return Err(RustConstructorError::VariableNotFound {
3597                variable_name: name.to_string(),
3598            });
3599        };
3600        let v = self
3601            .get_resource_mut::<Variable<T>>(name, "Variable")
3602            .unwrap();
3603        v.value = value;
3604        Ok(())
3605    }
3606
3607    /// 取出变量。
3608    pub fn var<T: Debug + 'static>(
3609        &self,
3610        name: &str,
3611        safe_mode: Option<bool>,
3612    ) -> Result<Option<&T>, RustConstructorError> {
3613        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
3614            if !self.check_resource_exists(name, "Variable") {
3615                self.problem_report_custom(
3616                    RustConstructorError::VariableNotFound {
3617                        variable_name: name.to_string(),
3618                    },
3619                    SeverityLevel::SevereWarning,
3620                    self.problem_list.clone(),
3621                );
3622                return Err(RustConstructorError::VariableNotFound {
3623                    variable_name: name.to_string(),
3624                });
3625            };
3626            if self
3627                .get_resource::<Variable<T>>(name, "Variable")
3628                .unwrap()
3629                .is_none()
3630            {
3631                self.problem_report_custom(
3632                    RustConstructorError::VariableTypeMismatch {
3633                        variable_name: name.to_string(),
3634                    },
3635                    SeverityLevel::SevereWarning,
3636                    self.problem_list.clone(),
3637                );
3638                return Err(RustConstructorError::VariableTypeMismatch {
3639                    variable_name: name.to_string(),
3640                });
3641            };
3642        };
3643        let v = self
3644            .get_resource::<Variable<T>>(name, "Variable")
3645            .unwrap()
3646            .unwrap();
3647        Ok(v.value.as_ref())
3648    }
3649
3650    /// 添加图片纹理资源。
3651    pub fn add_image_texture(
3652        &mut self,
3653        mut image_texture: ImageTexture,
3654        path: &str,
3655        flip: [bool; 2],
3656        ctx: &Context,
3657    ) {
3658        if let Ok(mut file) = File::open(path) {
3659            let mut buffer = Vec::new();
3660            file.read_to_end(&mut buffer).unwrap();
3661            let img_bytes = buffer;
3662            let img = image::load_from_memory(&img_bytes).unwrap();
3663            let color_data = match flip {
3664                [true, true] => img.fliph().flipv().into_rgba8(),
3665                [true, false] => img.fliph().into_rgba8(),
3666                [false, true] => img.flipv().into_rgba8(),
3667                _ => img.into_rgba8(),
3668            };
3669            let (w, h) = (color_data.width(), color_data.height());
3670            let raw_data: Vec<u8> = color_data.into_raw();
3671
3672            let color_image =
3673                ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3674            let loaded_image_texture = ctx.load_texture(
3675                image_texture.name.clone(),
3676                color_image,
3677                TextureOptions::LINEAR,
3678            );
3679            image_texture.texture = Some(DebugTextureHandle::new(loaded_image_texture));
3680            image_texture.cite_path = path.to_string();
3681            self.rust_constructor_resource.push(Box::new(image_texture));
3682        } else {
3683            self.problem_report_custom(
3684                RustConstructorError::ImageGetFailed {
3685                    image_path: path.to_string(),
3686                },
3687                SeverityLevel::SevereWarning,
3688                self.problem_list.clone(),
3689            );
3690        };
3691    }
3692
3693    /// 输出图片纹理。
3694    pub fn image_texture(
3695        &self,
3696        name: &str,
3697        safe_mode: Option<bool>,
3698    ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3699        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3700            && !self.check_resource_exists(name, "ImageTexture")
3701        {
3702            self.problem_report_custom(
3703                RustConstructorError::ImageNotFound {
3704                    image_name: name.to_string(),
3705                },
3706                SeverityLevel::SevereWarning,
3707                self.problem_list.clone(),
3708            );
3709            return Err(RustConstructorError::ImageNotFound {
3710                image_name: name.to_string(),
3711            });
3712        };
3713        let it = self
3714            .get_resource::<ImageTexture>(name, "ImageTexture")
3715            .unwrap()
3716            .unwrap();
3717        Ok(it.texture.clone())
3718    }
3719
3720    /// 重置图片纹理。
3721    pub fn reset_image_texture(
3722        &mut self,
3723        name: &str,
3724        path: &str,
3725        flip: [bool; 2],
3726        ctx: &Context,
3727        safe_mode: Option<bool>,
3728    ) -> Result<(), RustConstructorError> {
3729        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3730            && !self.check_resource_exists(name, "ImageTexture")
3731        {
3732            self.problem_report_custom(
3733                RustConstructorError::ImageTextureNotFound {
3734                    image_texture_name: name.to_string(),
3735                },
3736                SeverityLevel::SevereWarning,
3737                self.problem_list.clone(),
3738            );
3739            return Err(RustConstructorError::ImageTextureNotFound {
3740                image_texture_name: name.to_string(),
3741            });
3742        };
3743        let it = self
3744            .get_resource_mut::<ImageTexture>(name, "ImageTexture")
3745            .unwrap();
3746        if let Ok(mut file) = File::open(path) {
3747            let mut buffer = Vec::new();
3748            file.read_to_end(&mut buffer).unwrap();
3749            let img_bytes = buffer;
3750            let img = image::load_from_memory(&img_bytes).unwrap();
3751            let color_data = match flip {
3752                [true, true] => img.fliph().flipv().into_rgba8(),
3753                [true, false] => img.fliph().into_rgba8(),
3754                [false, true] => img.flipv().into_rgba8(),
3755                _ => img.into_rgba8(),
3756            };
3757            let (w, h) = (color_data.width(), color_data.height());
3758            let raw_data: Vec<u8> = color_data.into_raw();
3759
3760            let color_image =
3761                ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3762            let image_texture =
3763                ctx.load_texture(it.name.clone(), color_image, TextureOptions::LINEAR);
3764            it.texture = Some(DebugTextureHandle::new(image_texture));
3765            it.cite_path = path.to_string();
3766        } else {
3767            self.problem_report_custom(
3768                RustConstructorError::ImageGetFailed {
3769                    image_path: path.to_string(),
3770                },
3771                SeverityLevel::SevereWarning,
3772                self.problem_list.clone(),
3773            );
3774        };
3775        Ok(())
3776    }
3777
3778    /// 添加图片资源。
3779    pub fn add_image(
3780        &mut self,
3781        mut image: Image,
3782        image_texture_name: &str,
3783        safe_mode: Option<bool>,
3784    ) -> Result<(), RustConstructorError> {
3785        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3786            && !self.check_resource_exists(image_texture_name, "ImageTexture")
3787        {
3788            self.problem_report_custom(
3789                RustConstructorError::ImageTextureNotFound {
3790                    image_texture_name: image_texture_name.to_string(),
3791                },
3792                SeverityLevel::SevereWarning,
3793                self.problem_list.clone(),
3794            );
3795            return Err(RustConstructorError::ImageTextureNotFound {
3796                image_texture_name: image_texture_name.to_string(),
3797            });
3798        };
3799        let it = self
3800            .get_resource::<ImageTexture>(image_texture_name, "ImageTexture")
3801            .unwrap()
3802            .unwrap();
3803        image.texture = it.texture.clone();
3804        image.cite_texture = it.name.clone();
3805        image.last_frame_cite_texture = it.name.clone();
3806        self.rust_constructor_resource.push(Box::new(image));
3807        Ok(())
3808    }
3809
3810    /// 显示图片资源。
3811    pub fn image(
3812        &mut self,
3813        name: &str,
3814        ui: &mut Ui,
3815        ctx: &Context,
3816        safe_mode: Option<bool>,
3817    ) -> Result<(), RustConstructorError> {
3818        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3819            && !self.check_resource_exists(name, "Image")
3820        {
3821            self.problem_report_custom(
3822                RustConstructorError::ImageNotFound {
3823                    image_name: name.to_string(),
3824                },
3825                SeverityLevel::SevereWarning,
3826                self.problem_list.clone(),
3827            );
3828            return Err(RustConstructorError::ImageNotFound {
3829                image_name: name.to_string(),
3830            });
3831        };
3832        let mut im = self
3833            .get_resource_mut::<Image>(name, "Image")
3834            .unwrap()
3835            .clone();
3836        if im.cite_texture != im.last_frame_cite_texture {
3837            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3838                && !self.check_resource_exists(&im.cite_texture, "ImageTexture")
3839            {
3840                self.problem_report_custom(
3841                    RustConstructorError::ImageTextureNotFound {
3842                        image_texture_name: im.cite_texture.clone(),
3843                    },
3844                    SeverityLevel::MildWarning,
3845                    self.problem_list.clone(),
3846                );
3847            } else {
3848                let it = self
3849                    .get_resource::<ImageTexture>(&im.cite_texture, "ImageTexture")
3850                    .unwrap()
3851                    .unwrap();
3852                im.texture = it.texture.clone();
3853            };
3854        };
3855        im.reg_render_resource(&mut self.render_resource_list);
3856        im.position[0] = match im.x_grid[1] {
3857            0 => im.origin_position[0],
3858            _ => {
3859                (ctx.available_rect().width() as f64 / im.x_grid[1] as f64 * im.x_grid[0] as f64)
3860                    as f32
3861                    + im.origin_position[0]
3862            }
3863        };
3864        im.position[1] = match im.y_grid[1] {
3865            0 => im.origin_position[1],
3866            _ => {
3867                (ctx.available_rect().height() as f64 / im.y_grid[1] as f64 * im.y_grid[0] as f64)
3868                    as f32
3869                    + im.origin_position[1]
3870            }
3871        };
3872        match im.center_display.0 {
3873            HorizontalAlign::Left => {}
3874            HorizontalAlign::Center => im.position[0] -= im.size[0] / 2.0,
3875            HorizontalAlign::Right => im.position[0] -= im.size[0],
3876        };
3877        match im.center_display.1 {
3878            VerticalAlign::Top => {}
3879            VerticalAlign::Center => im.position[1] -= im.size[1] / 2.0,
3880            VerticalAlign::Bottom => im.position[1] -= im.size[1],
3881        };
3882        im.position[0] += im.offset[0];
3883        im.position[1] += im.offset[1];
3884        if let Some(texture) = &im.texture {
3885            let rect = Rect::from_min_size(
3886                Pos2::new(im.position[0], im.position[1]),
3887                Vec2::new(im.size[0], im.size[1]),
3888            );
3889
3890            // 直接绘制图片
3891            egui::Image::new(ImageSource::Texture((&texture.0).into()))
3892                .tint(Color32::from_rgba_unmultiplied(
3893                    im.overlay_color[0],
3894                    im.overlay_color[1],
3895                    im.overlay_color[2],
3896                    // 将图片透明度与覆盖颜色透明度相乘
3897                    (im.alpha as f32 * im.overlay_color[3] as f32 / 255.0) as u8,
3898                ))
3899                .bg_fill(Color32::from_rgba_unmultiplied(
3900                    im.background_color[0],
3901                    im.background_color[1],
3902                    im.background_color[2],
3903                    im.background_color[3],
3904                ))
3905                .rotate(
3906                    im.rotate_angle,
3907                    [
3908                        im.rotate_center[0] / im.size[0],
3909                        im.rotate_center[1] / im.size[1],
3910                    ]
3911                    .into(),
3912                )
3913                .paint_at(ui, rect)
3914        };
3915        im.last_frame_cite_texture = im.cite_texture.clone();
3916        self.replace_resource(name, "Image", im).unwrap();
3917        Ok(())
3918    }
3919
3920    /// 添加消息框资源。
3921    #[allow(clippy::too_many_arguments)]
3922    pub fn add_message_box(
3923        &mut self,
3924        mut message_box: MessageBox,
3925        title_name: &str,
3926        content_name: &str,
3927        image_name: &str,
3928        close_switch_fill_resource_name: &str,
3929        close_switch_fill_resource_type: &str,
3930        safe_mode: Option<bool>,
3931    ) -> Result<(), RustConstructorError> {
3932        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3933            && self.check_resource_exists(&message_box.name, "MessageBox")
3934        {
3935            self.problem_report_custom(
3936                RustConstructorError::MessageBoxAlreadyExists {
3937                    message_box_name: message_box.name.to_string(),
3938                },
3939                SeverityLevel::SevereWarning,
3940                self.problem_list.clone(),
3941            );
3942            return Err(RustConstructorError::MessageBoxAlreadyExists {
3943                message_box_name: message_box.name.to_string(),
3944            });
3945        };
3946        message_box.exist = true;
3947        message_box.memory_offset = 0_f32;
3948
3949        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3950            && !self.check_resource_exists(image_name, "Image")
3951        {
3952            self.problem_report_custom(
3953                RustConstructorError::ImageNotFound {
3954                    image_name: image_name.to_string(),
3955                },
3956                SeverityLevel::SevereWarning,
3957                self.problem_list.clone(),
3958            );
3959            return Err(RustConstructorError::ImageNotFound {
3960                image_name: image_name.to_string(),
3961            });
3962        };
3963        let im = self.get_resource_mut::<Image>(image_name, "Image").unwrap();
3964        im.size = [message_box.size[1] - 15_f32, message_box.size[1] - 15_f32];
3965        im.center_display = (HorizontalAlign::Left, VerticalAlign::Center);
3966        im.x_grid = [1, 1];
3967        im.y_grid = [0, 1];
3968        im.name = format!("MessageBox{}", im.name);
3969        message_box.image_name = im.name.to_string();
3970
3971        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3972            && !self.check_resource_exists(title_name, "Text")
3973        {
3974            self.problem_report_custom(
3975                RustConstructorError::TextNotFound {
3976                    text_name: title_name.to_string(),
3977                },
3978                SeverityLevel::SevereWarning,
3979                self.problem_list.clone(),
3980            );
3981            return Err(RustConstructorError::TextNotFound {
3982                text_name: title_name.to_string(),
3983            });
3984        };
3985        let t = self.get_resource_mut::<Text>(title_name, "Text").unwrap();
3986        t.x_grid = [1, 1];
3987        t.y_grid = [0, 1];
3988        t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
3989        t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
3990        t.name = format!("MessageBox{}", t.name);
3991        message_box.title_name = t.name.to_string();
3992
3993        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
3994            && !self.check_resource_exists(content_name, "Text")
3995        {
3996            self.problem_report_custom(
3997                RustConstructorError::TextNotFound {
3998                    text_name: content_name.to_string(),
3999                },
4000                SeverityLevel::SevereWarning,
4001                self.problem_list.clone(),
4002            );
4003            return Err(RustConstructorError::TextNotFound {
4004                text_name: content_name.to_string(),
4005            });
4006        };
4007        let t = self.get_resource_mut::<Text>(content_name, "Text").unwrap();
4008        t.center_display = (HorizontalAlign::Left, VerticalAlign::Top);
4009        t.x_grid = [1, 1];
4010        t.y_grid = [0, 1];
4011        t.wrap_width = message_box.size[0] - message_box.size[1] + 5_f32;
4012        t.name = format!("MessageBox{}", t.name);
4013        message_box.content_name = t.name.to_string();
4014
4015        if !message_box.keep_existing {
4016            self.add_split_time(
4017                SplitTime::default().name(&format!("MessageBox{}", message_box.name)),
4018            );
4019        };
4020
4021        self.add_split_time(
4022            SplitTime::default().name(&format!("MessageBox{}Animation", message_box.name)),
4023        );
4024
4025        self.add_custom_rect(
4026            CustomRect::default()
4027                .name(&format!("MessageBox{}", message_box.name))
4028                .origin_position(0_f32, 0_f32)
4029                .size(message_box.size[0], message_box.size[1])
4030                .rounding(20_f32)
4031                .x_grid(1, 1)
4032                .y_grid(0, 1)
4033                .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4034                .color(100, 100, 100, 125)
4035                .border_width(0_f32),
4036        );
4037
4038        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4039            match close_switch_fill_resource_type {
4040                "Image" | "CustomRect" => {}
4041                &_ => {
4042                    self.problem_report_custom(
4043                        RustConstructorError::SwitchFillResourceMismatch {
4044                            switch_name: format!("MessageBox{}Close", message_box.name),
4045                            fill_resource_name: close_switch_fill_resource_name.to_string(),
4046                            fill_resource_type: close_switch_fill_resource_type.to_string(),
4047                        },
4048                        SeverityLevel::SevereWarning,
4049                        self.problem_list.clone(),
4050                    );
4051                    return Err(RustConstructorError::SwitchFillResourceMismatch {
4052                        switch_name: format!("MessageBox{}Close", message_box.name),
4053                        fill_resource_name: close_switch_fill_resource_name.to_string(),
4054                        fill_resource_type: close_switch_fill_resource_type.to_string(),
4055                    });
4056                }
4057            };
4058        };
4059
4060        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4061            && !self.check_resource_exists(
4062                close_switch_fill_resource_name,
4063                close_switch_fill_resource_type,
4064            )
4065        {
4066            self.problem_report_custom(
4067                RustConstructorError::ResourceNotFound {
4068                    resource_name: close_switch_fill_resource_name.to_string(),
4069                    resource_type: close_switch_fill_resource_type.to_string(),
4070                },
4071                SeverityLevel::SevereWarning,
4072                self.problem_list.clone(),
4073            );
4074            return Err(RustConstructorError::ResourceNotFound {
4075                resource_name: close_switch_fill_resource_name.to_string(),
4076                resource_type: close_switch_fill_resource_type.to_string(),
4077            });
4078        };
4079
4080        let (texture, image_config, custom_rect_config, color, border_color) =
4081            match close_switch_fill_resource_type {
4082                "Image" => {
4083                    let im = self
4084                        .get_resource_mut::<Image>(close_switch_fill_resource_name, "Image")
4085                        .unwrap();
4086                    im.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4087                    (
4088                        im.cite_texture.clone(),
4089                        ImageConfig::from_image(im.clone())
4090                            .size(30_f32, 30_f32)
4091                            .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4092                        CustomRectConfig::default(),
4093                        im.overlay_color,
4094                        [0, 0, 0, 0],
4095                    )
4096                }
4097                "CustomRect" => {
4098                    let cr = self
4099                        .get_resource_mut::<CustomRect>(
4100                            close_switch_fill_resource_name,
4101                            "CustomRect",
4102                        )
4103                        .unwrap();
4104                    cr.name = format!("MessageBox{}Close", close_switch_fill_resource_name);
4105                    (
4106                        String::new(),
4107                        ImageConfig::default(),
4108                        CustomRectConfig::from_custom_rect(cr.clone())
4109                            .size(30_f32, 30_f32)
4110                            .center_display(HorizontalAlign::Center, VerticalAlign::Center),
4111                        cr.color,
4112                        cr.border_color,
4113                    )
4114                }
4115                &_ => {
4116                    self.problem_report_custom(
4117                        RustConstructorError::SwitchFillResourceMismatch {
4118                            switch_name: format!("MessageBox{}Close", message_box.name),
4119                            fill_resource_name: close_switch_fill_resource_name.to_string(),
4120                            fill_resource_type: close_switch_fill_resource_type.to_string(),
4121                        },
4122                        SeverityLevel::SevereWarning,
4123                        self.problem_list.clone(),
4124                    );
4125                    return Err(RustConstructorError::SwitchFillResourceMismatch {
4126                        switch_name: format!("MessageBox{}Close", message_box.name),
4127                        fill_resource_name: close_switch_fill_resource_name.to_string(),
4128                        fill_resource_type: close_switch_fill_resource_type.to_string(),
4129                    });
4130                }
4131            };
4132
4133        self.add_switch(
4134            Switch::default()
4135                .name(&format!("MessageBox{}Close", message_box.name))
4136                .appearance(vec![
4137                    SwitchAppearance {
4138                        image_config: image_config
4139                            .clone()
4140                            .overlay_color(color[0], color[1], color[2], 0),
4141                        custom_rect_config: custom_rect_config
4142                            .clone()
4143                            .color(color[0], color[1], color[2], 0)
4144                            .border_color(border_color[0], border_color[1], border_color[2], 0),
4145                        text_config: TextConfig::default(),
4146                        texture: texture.clone(),
4147                        hint_text: String::new(),
4148                    },
4149                    SwitchAppearance {
4150                        image_config: image_config.clone().overlay_color(
4151                            (color[0] as u32 * 180 / 255) as u8,
4152                            (color[1] as u32 * 180 / 255) as u8,
4153                            (color[2] as u32 * 180 / 255) as u8,
4154                            255,
4155                        ),
4156                        custom_rect_config: custom_rect_config
4157                            .clone()
4158                            .color(
4159                                (color[0] as u32 * 180 / 255) as u8,
4160                                (color[1] as u32 * 180 / 255) as u8,
4161                                (color[2] as u32 * 180 / 255) as u8,
4162                                255,
4163                            )
4164                            .border_color(
4165                                (border_color[0] as u32 * 180 / 255) as u8,
4166                                (border_color[1] as u32 * 180 / 255) as u8,
4167                                (border_color[2] as u32 * 180 / 255) as u8,
4168                                255,
4169                            ),
4170                        text_config: TextConfig::default(),
4171                        texture: texture.clone(),
4172                        hint_text: String::new(),
4173                    },
4174                    SwitchAppearance {
4175                        image_config: image_config.clone().overlay_color(0, 0, 0, 0),
4176                        custom_rect_config: custom_rect_config
4177                            .clone()
4178                            .color(0, 0, 0, 0)
4179                            .border_color(0, 0, 0, 0),
4180                        text_config: TextConfig::default(),
4181                        texture: texture.clone(),
4182                        hint_text: String::new(),
4183                    },
4184                    SwitchAppearance {
4185                        image_config: image_config.overlay_color(0, 0, 0, 0),
4186                        custom_rect_config: custom_rect_config
4187                            .color(0, 0, 0, 0)
4188                            .border_color(0, 0, 0, 0),
4189                        text_config: TextConfig::default(),
4190                        texture,
4191                        hint_text: String::new(),
4192                    },
4193                ])
4194                .enable_hover_click_fill_resource(false, true)
4195                .click_method(vec![SwitchClickAction {
4196                    click_method: PointerButton::Primary,
4197                    action: true,
4198                }]),
4199            &format!("MessageBox{}Close", close_switch_fill_resource_name),
4200            close_switch_fill_resource_type,
4201            "",
4202        )
4203        .unwrap();
4204        self.rust_constructor_resource
4205            .push(Box::new(message_box.clone()));
4206        Ok(())
4207    }
4208
4209    /// 处理所有已添加的消息框资源。
4210    pub fn message_box_display(&mut self, ctx: &Context, ui: &mut Ui, safe_mode: Option<bool>) {
4211        let mut offset = 0_f32;
4212        let mut delete_count = 0;
4213        let mut index_list = Vec::new();
4214        for i in 0..self.rust_constructor_resource.len() {
4215            if self.rust_constructor_resource[i]
4216                .as_any()
4217                .downcast_ref::<MessageBox>()
4218                .is_some()
4219            {
4220                index_list.push(i);
4221            };
4222        }
4223        for u in 0..index_list.len() {
4224            let mut deleted = false;
4225            let i = u - delete_count;
4226            let mut mb = self.rust_constructor_resource[index_list[i]]
4227                .as_any()
4228                .downcast_ref::<MessageBox>()
4229                .unwrap()
4230                .clone();
4231            if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4232                if !self.check_resource_exists(&mb.image_name, "Image") {
4233                    self.problem_report_custom(
4234                        RustConstructorError::ImageNotFound {
4235                            image_name: mb.image_name,
4236                        },
4237                        SeverityLevel::SevereWarning,
4238                        self.problem_list.clone(),
4239                    );
4240                    continue;
4241                };
4242                if !self.check_resource_exists(&format!("MessageBox{}", mb.name), "CustomRect") {
4243                    self.problem_report_custom(
4244                        RustConstructorError::RectNotFound {
4245                            rect_name: format!("MessageBox{}", mb.name),
4246                        },
4247                        SeverityLevel::SevereWarning,
4248                        self.problem_list.clone(),
4249                    );
4250                    continue;
4251                };
4252                if !self.check_resource_exists(&mb.title_name, "Text") {
4253                    self.problem_report_custom(
4254                        RustConstructorError::TextNotFound {
4255                            text_name: mb.title_name,
4256                        },
4257                        SeverityLevel::SevereWarning,
4258                        self.problem_list.clone(),
4259                    );
4260                    continue;
4261                };
4262                if !self.check_resource_exists(&mb.content_name, "Text") {
4263                    self.problem_report_custom(
4264                        RustConstructorError::TextNotFound {
4265                            text_name: mb.content_name,
4266                        },
4267                        SeverityLevel::SevereWarning,
4268                        self.problem_list.clone(),
4269                    );
4270                    continue;
4271                };
4272                if !self.check_resource_exists(&format!("MessageBox{}Close", mb.name), "Switch") {
4273                    self.problem_report_custom(
4274                        RustConstructorError::SwitchNotFound {
4275                            switch_name: format!("MessageBox{}Close", mb.name),
4276                        },
4277                        SeverityLevel::SevereWarning,
4278                        self.problem_list.clone(),
4279                    );
4280                    continue;
4281                };
4282                if !self
4283                    .check_resource_exists(&format!("MessageBox{}Animation", mb.name), "SplitTime")
4284                {
4285                    self.problem_report_custom(
4286                        RustConstructorError::SplitTimeNotFound {
4287                            split_time_name: format!("MessageBox{}Animation", mb.name),
4288                        },
4289                        SeverityLevel::SevereWarning,
4290                        self.problem_list.clone(),
4291                    );
4292                    continue;
4293                };
4294                if !mb.keep_existing
4295                    && !self.check_resource_exists(&format!("MessageBox{}", mb.name), "SplitTime")
4296                {
4297                    self.problem_report_custom(
4298                        RustConstructorError::SplitTimeNotFound {
4299                            split_time_name: format!("MessageBox{}", mb.name),
4300                        },
4301                        SeverityLevel::SevereWarning,
4302                        self.problem_list.clone(),
4303                    );
4304                    continue;
4305                };
4306            };
4307            let mut im1 = self
4308                .get_resource::<Image>(&mb.image_name, "Image")
4309                .unwrap()
4310                .unwrap()
4311                .clone();
4312            let mut cr = self
4313                .get_resource::<CustomRect>(&format!("MessageBox{}", mb.name), "CustomRect")
4314                .unwrap()
4315                .unwrap()
4316                .clone();
4317            let mut t1 = self
4318                .get_resource::<Text>(&mb.title_name, "Text")
4319                .unwrap()
4320                .unwrap()
4321                .clone();
4322            let mut t2 = self
4323                .get_resource::<Text>(&mb.content_name, "Text")
4324                .unwrap()
4325                .unwrap()
4326                .clone();
4327            let mut s = self
4328                .get_resource::<Switch>(&format!("MessageBox{}Close", mb.name), "Switch")
4329                .unwrap()
4330                .unwrap()
4331                .clone();
4332            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4333                && !self.check_resource_exists(&s.fill_resource_name, &s.fill_resource_type)
4334            {
4335                self.problem_report_custom(
4336                    RustConstructorError::ResourceNotFound {
4337                        resource_name: s.fill_resource_name,
4338                        resource_type: s.fill_resource_type,
4339                    },
4340                    SeverityLevel::SevereWarning,
4341                    self.problem_list.clone(),
4342                );
4343                continue;
4344            };
4345            let fr: Box<dyn BasicFrontResource> = match s.fill_resource_type.as_str() {
4346                "Image" => Box::new(
4347                    self.get_resource::<Image>(&s.fill_resource_name, "Image")
4348                        .unwrap()
4349                        .unwrap()
4350                        .clone(),
4351                ),
4352                "CustomRect" => Box::new(
4353                    self.get_resource::<CustomRect>(&s.fill_resource_name, "CustomRect")
4354                        .unwrap()
4355                        .unwrap()
4356                        .clone(),
4357                ),
4358                &_ => {
4359                    self.problem_report_custom(
4360                        RustConstructorError::SwitchFillResourceMismatch {
4361                            switch_name: s.name,
4362                            fill_resource_name: s.fill_resource_name,
4363                            fill_resource_type: s.fill_resource_type,
4364                        },
4365                        SeverityLevel::SevereWarning,
4366                        self.problem_list.clone(),
4367                    );
4368                    continue;
4369                }
4370            };
4371            mb.reg_render_resource(&mut self.render_resource_list.clone());
4372            if mb.size[1] < t1.size[1] + t2.size[1] + 10_f32 {
4373                mb.size[1] = t1.size[1] + t2.size[1] + 10_f32;
4374                cr.size[1] = mb.size[1];
4375                im1.size = [mb.size[1] - 15_f32, mb.size[1] - 15_f32];
4376                t1.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4377                t2.wrap_width = mb.size[0] - mb.size[1] + 5_f32;
4378            };
4379            if self.timer.total_time
4380                - self
4381                    .split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4382                    .unwrap()[1]
4383                >= self.tick_interval
4384            {
4385                self.reset_split_time(&format!("MessageBox{}Animation", mb.name), safe_mode)
4386                    .unwrap();
4387                if offset != mb.memory_offset {
4388                    if mb.memory_offset < offset {
4389                        if mb.memory_offset + mb.restore_speed >= offset {
4390                            mb.memory_offset = offset;
4391                        } else {
4392                            mb.memory_offset += mb.restore_speed;
4393                        };
4394                    } else if mb.memory_offset - mb.restore_speed <= offset {
4395                        mb.memory_offset = offset;
4396                    } else {
4397                        mb.memory_offset -= mb.restore_speed;
4398                    };
4399                };
4400                if cr.origin_position[0] != -mb.size[0] - 5_f32 {
4401                    if mb.exist {
4402                        if cr.origin_position[0] - mb.speed <= -mb.size[0] - 5_f32 {
4403                            cr.origin_position[0] = -mb.size[0] - 5_f32;
4404                            if self.check_resource_exists(
4405                                &format!("MessageBox{}", mb.name),
4406                                "SplitTime",
4407                            ) {
4408                                self.reset_split_time(&format!("MessageBox{}", mb.name), safe_mode)
4409                                    .unwrap();
4410                            };
4411                        } else {
4412                            cr.origin_position[0] -= mb.speed;
4413                        };
4414                    } else if cr.origin_position[0] + mb.speed >= 15_f32 {
4415                        cr.origin_position[0] = 15_f32;
4416                        delete_count += 1;
4417                        deleted = true;
4418                    } else {
4419                        cr.origin_position[0] += mb.speed;
4420                    };
4421                };
4422            };
4423            cr.origin_position[1] = mb.memory_offset + 20_f32;
4424            im1.origin_position = [
4425                cr.origin_position[0] + 5_f32,
4426                cr.origin_position[1] + mb.size[1] / 2_f32,
4427            ];
4428            t1.origin_position = [
4429                im1.origin_position[0] + im1.size[0] + 5_f32,
4430                cr.origin_position[1] + 5_f32,
4431            ];
4432            t2.origin_position = [
4433                im1.origin_position[0] + im1.size[0] + 5_f32,
4434                t1.origin_position[1] + t1.size[1],
4435            ];
4436            for sd in &mut s.appearance {
4437                sd.image_config.origin_position = cr.position;
4438                sd.custom_rect_config.origin_position = cr.position;
4439            }
4440            if !mb.keep_existing
4441                && self.timer.total_time
4442                    - self
4443                        .split_time(&format!("MessageBox{}", mb.name), safe_mode)
4444                        .unwrap()[1]
4445                    >= mb.existing_time
4446                && cr.origin_position[0] == -mb.size[0] - 5_f32
4447            {
4448                mb.exist = false;
4449                if cr.origin_position[0] + mb.speed >= 15_f32 {
4450                    cr.origin_position[0] = 15_f32;
4451                } else {
4452                    cr.origin_position[0] += mb.speed;
4453                };
4454            };
4455            if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4456                let rect = Rect::from_min_size(
4457                    Pos2 {
4458                        x: fr.position()[0],
4459                        y: fr.position()[1],
4460                    },
4461                    Vec2 {
4462                        x: cr.size[0] + 15_f32,
4463                        y: cr.size[1] + 15_f32,
4464                    },
4465                );
4466                if rect.contains(mouse_pos) {
4467                    s.appearance[0].image_config.overlay_color[3] = 255;
4468                    s.appearance[0].custom_rect_config.color[3] = 255;
4469                    s.appearance[0].custom_rect_config.border_color[3] = 255;
4470                } else {
4471                    s.appearance[0].image_config.overlay_color[3] = 0;
4472                    s.appearance[0].custom_rect_config.color[3] = 0;
4473                    s.appearance[0].custom_rect_config.border_color[3] = 0;
4474                };
4475            };
4476            self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4477            self.replace_resource(&mb.image_name, "Image", im1.clone())
4478                .unwrap();
4479            self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4480                .unwrap();
4481            self.replace_resource(&mb.title_name, "Text", t1.clone())
4482                .unwrap();
4483            self.replace_resource(&mb.content_name, "Text", t2.clone())
4484                .unwrap();
4485            self.replace_resource(&format!("MessageBox{}Close", mb.name), "Switch", s.clone())
4486                .unwrap();
4487            match s.fill_resource_type.as_str() {
4488                "Image" => {
4489                    self.replace_resource(
4490                        &s.fill_resource_name,
4491                        &s.fill_resource_type,
4492                        fr.as_any().downcast_ref::<Image>().unwrap().clone(),
4493                    )
4494                    .unwrap();
4495                }
4496                "CustomRect" => {
4497                    self.replace_resource(
4498                        &s.fill_resource_name,
4499                        &s.fill_resource_type,
4500                        fr.as_any().downcast_ref::<CustomRect>().unwrap().clone(),
4501                    )
4502                    .unwrap();
4503                }
4504                &_ => {
4505                    self.problem_report_custom(
4506                        RustConstructorError::SwitchFillResourceMismatch {
4507                            switch_name: s.name,
4508                            fill_resource_name: s.fill_resource_name,
4509                            fill_resource_type: s.fill_resource_type,
4510                        },
4511                        SeverityLevel::SevereWarning,
4512                        self.problem_list.clone(),
4513                    );
4514                    continue;
4515                }
4516            };
4517            self.custom_rect(&format!("MessageBox{}", mb.name), ui, ctx, safe_mode)
4518                .unwrap();
4519            self.image(&mb.image_name.clone(), ui, ctx, safe_mode)
4520                .unwrap();
4521            self.text(&t1.name.clone(), ui, ctx, safe_mode).unwrap();
4522            self.text(&t2.name.clone(), ui, ctx, safe_mode).unwrap();
4523            self.switch(
4524                &format!("MessageBox{}Close", mb.name),
4525                ui,
4526                ctx,
4527                s.state == 0 && mb.exist,
4528                safe_mode,
4529            )
4530            .unwrap();
4531            let switch_data = self
4532                .check_switch_data(&format!("MessageBox{}Close", mb.name), safe_mode)
4533                .unwrap();
4534            if switch_data.last_time_clicked_index == 0
4535                && switch_data.state == 1
4536                && switch_data.switched
4537            {
4538                mb.exist = false;
4539                if cr.origin_position[0] + mb.speed >= 15_f32 {
4540                    cr.origin_position[0] = 15_f32;
4541                } else {
4542                    cr.origin_position[0] += mb.speed;
4543                };
4544                self.rust_constructor_resource[index_list[i]] = Box::new(mb.clone());
4545                self.replace_resource(&format!("MessageBox{}", mb.name), "CustomRect", cr.clone())
4546                    .unwrap();
4547            };
4548            if deleted {
4549                self.rust_constructor_resource.remove(
4550                    self.rust_constructor_resource
4551                        .iter()
4552                        .position(|x| x.expose_type() == "Image" && x.name() == mb.image_name)
4553                        .unwrap(),
4554                );
4555                self.rust_constructor_resource.remove(
4556                    self.rust_constructor_resource
4557                        .iter()
4558                        .position(|x| {
4559                            x.expose_type() == "CustomRect"
4560                                && x.name() == format!("MessageBox{}", mb.name)
4561                        })
4562                        .unwrap(),
4563                );
4564                self.rust_constructor_resource.remove(
4565                    self.rust_constructor_resource
4566                        .iter()
4567                        .position(|x| x.expose_type() == "Text" && x.name() == mb.title_name)
4568                        .unwrap(),
4569                );
4570                self.rust_constructor_resource.remove(
4571                    self.rust_constructor_resource
4572                        .iter()
4573                        .position(|x| x.expose_type() == "Text" && x.name() == mb.content_name)
4574                        .unwrap(),
4575                );
4576                self.rust_constructor_resource.remove(
4577                    self.rust_constructor_resource
4578                        .iter()
4579                        .position(|x| {
4580                            x.expose_type() == "Switch"
4581                                && x.name() == format!("MessageBox{}Close", mb.name)
4582                        })
4583                        .unwrap(),
4584                );
4585                self.rust_constructor_resource.remove(
4586                    self.rust_constructor_resource
4587                        .iter()
4588                        .position(|x| {
4589                            x.expose_type() == s.fill_resource_type
4590                                && x.name() == s.fill_resource_name
4591                        })
4592                        .unwrap(),
4593                );
4594                self.rust_constructor_resource.remove(
4595                    self.rust_constructor_resource
4596                        .iter()
4597                        .position(|x| {
4598                            x.expose_type() == "SplitTime"
4599                                && x.name() == format!("MessageBox{}Animation", mb.name)
4600                        })
4601                        .unwrap(),
4602                );
4603                if !mb.keep_existing {
4604                    self.rust_constructor_resource.remove(
4605                        self.rust_constructor_resource
4606                            .iter()
4607                            .position(|x| {
4608                                x.expose_type() == "SplitTime"
4609                                    && x.name() == format!("MessageBox{}", mb.name)
4610                            })
4611                            .unwrap(),
4612                    );
4613                };
4614                self.rust_constructor_resource.remove(
4615                    self.rust_constructor_resource
4616                        .iter()
4617                        .position(|x| x.expose_type() == "MessageBox" && x.name() == mb.name)
4618                        .unwrap(),
4619                );
4620                self.rust_constructor_resource.remove(
4621                    self.rust_constructor_resource
4622                        .iter()
4623                        .position(|x| x.expose_type() == "MouseDetector" && x.name() == t1.name)
4624                        .unwrap(),
4625                );
4626                self.rust_constructor_resource.remove(
4627                    self.rust_constructor_resource
4628                        .iter()
4629                        .position(|x| x.expose_type() == "MouseDetector" && x.name() == t2.name)
4630                        .unwrap(),
4631                );
4632            } else {
4633                offset += mb.size[1] + 15_f32;
4634            };
4635        }
4636    }
4637
4638    /// 添加开关资源。
4639    pub fn add_switch(
4640        &mut self,
4641        mut switch: Switch,
4642        fill_resource_name: &str,
4643        fill_resource_type: &str,
4644        text_name: &str,
4645    ) -> Result<(), RustConstructorError> {
4646        let mut count = 1;
4647        if switch.enable_hover_click_fill_resource[0] {
4648            count += 1;
4649        };
4650        if switch.enable_hover_click_fill_resource[1] {
4651            count += 1;
4652        };
4653        if switch.appearance.len() < count {
4654            self.problem_report_custom(
4655                RustConstructorError::SwitchAppearanceMismatch {
4656                    switch_name: switch.name.clone(),
4657                    differ: count as u32 - switch.appearance.len() as u32,
4658                },
4659                SeverityLevel::SevereWarning,
4660                self.problem_list.clone(),
4661            );
4662            return Err(RustConstructorError::SwitchAppearanceMismatch {
4663                switch_name: switch.name.clone(),
4664                differ: count as u32 - switch.appearance.len() as u32,
4665            });
4666        };
4667        for _ in 0..switch.appearance.len() % count {
4668            switch.appearance.pop();
4669        }
4670        switch.text_name = "".to_string();
4671        if self.check_resource_exists(text_name, "Text") {
4672            let t = self.get_resource_mut::<Text>(text_name, "Text").unwrap();
4673            switch.text_name = text_name.to_string();
4674            switch.text_origin_position = t.origin_position;
4675            t.center_display = (HorizontalAlign::Center, VerticalAlign::Center);
4676            t.x_grid = [0, 0];
4677            t.y_grid = [0, 0];
4678        } else if !text_name.is_empty() {
4679            self.problem_report_custom(
4680                RustConstructorError::TextNotFound {
4681                    text_name: text_name.to_string(),
4682                },
4683                SeverityLevel::SevereWarning,
4684                self.problem_list.clone(),
4685            );
4686        };
4687        if self.check_resource_exists(fill_resource_name, fill_resource_type) {
4688            match fill_resource_type {
4689                "Image" | "CustomRect" => {
4690                    switch.fill_resource_name = fill_resource_name.to_string();
4691                    switch.fill_resource_type = fill_resource_type.to_string();
4692                }
4693                &_ => {
4694                    self.problem_report_custom(
4695                        RustConstructorError::SwitchFillResourceMismatch {
4696                            switch_name: switch.name.clone(),
4697                            fill_resource_name: fill_resource_name.to_string(),
4698                            fill_resource_type: fill_resource_type.to_string(),
4699                        },
4700                        SeverityLevel::SevereWarning,
4701                        self.problem_list.clone(),
4702                    );
4703                    return Err(RustConstructorError::SwitchFillResourceMismatch {
4704                        switch_name: switch.name.clone(),
4705                        fill_resource_name: fill_resource_name.to_string(),
4706                        fill_resource_type: fill_resource_type.to_string(),
4707                    });
4708                }
4709            };
4710        } else {
4711            self.problem_report_custom(
4712                RustConstructorError::ResourceNotFound {
4713                    resource_name: fill_resource_name.to_string(),
4714                    resource_type: fill_resource_type.to_string(),
4715                },
4716                SeverityLevel::SevereWarning,
4717                self.problem_list.clone(),
4718            );
4719            return Err(RustConstructorError::ResourceNotFound {
4720                resource_name: fill_resource_name.to_string(),
4721                resource_type: fill_resource_type.to_string(),
4722            });
4723        };
4724        switch.hint_text_name = String::new();
4725        if switch
4726            .appearance
4727            .iter()
4728            .filter(|x| !x.hint_text.is_empty())
4729            .count()
4730            > 0
4731        {
4732            switch.hint_text_name = format!("{}Hint", switch.name);
4733            self.add_text(
4734                Text::default()
4735                    .name(&format!("{}Hint", switch.name))
4736                    .content("")
4737                    .origin_position(0_f32, 0_f32)
4738                    .font_size(25_f32)
4739                    .wrap_width(300_f32)
4740                    .background_rounding(10_f32)
4741                    .color(255, 255, 255, 0)
4742                    .background_color(0, 0, 0, 255)
4743                    .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4744                    .selectable(false),
4745            );
4746            self.add_split_time(
4747                SplitTime::default().name(&format!("{}StartHoverTime", switch.name)),
4748            );
4749            self.add_split_time(
4750                SplitTime::default().name(&format!("{}HintFadeAnimation", switch.name)),
4751            );
4752        };
4753        switch.state = 0;
4754        switch.animation_count = count as u32;
4755        self.rust_constructor_resource.push(Box::new(switch));
4756        Ok(())
4757    }
4758
4759    /// 显示开关资源。
4760    pub fn switch(
4761        &mut self,
4762        name: &str,
4763        ui: &mut Ui,
4764        ctx: &Context,
4765        enable: bool,
4766        safe_mode: Option<bool>,
4767    ) -> Result<(), RustConstructorError> {
4768        let mut appearance_count = 0;
4769        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4770            && !self.check_resource_exists(name, "Switch")
4771        {
4772            self.problem_report_custom(
4773                RustConstructorError::SwitchNotFound {
4774                    switch_name: name.to_string(),
4775                },
4776                SeverityLevel::SevereWarning,
4777                self.problem_list.clone(),
4778            );
4779            return Err(RustConstructorError::SwitchNotFound {
4780                switch_name: name.to_string(),
4781            });
4782        };
4783        let mut s = self
4784            .get_resource::<Switch>(name, "Switch")
4785            .unwrap()
4786            .unwrap()
4787            .clone();
4788        s.switched = false;
4789        if safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode {
4790            if !self.check_resource_exists(&s.fill_resource_name.clone(), &s.fill_resource_type) {
4791                self.problem_report_custom(
4792                    RustConstructorError::ResourceNotFound {
4793                        resource_name: s.fill_resource_name.clone(),
4794                        resource_type: s.fill_resource_type.clone(),
4795                    },
4796                    SeverityLevel::SevereWarning,
4797                    self.problem_list.clone(),
4798                );
4799                return Err(RustConstructorError::ResourceNotFound {
4800                    resource_name: s.fill_resource_name,
4801                    resource_type: s.fill_resource_type,
4802                });
4803            };
4804            if !s.hint_text_name.is_empty() {
4805                if !self.check_resource_exists(&format!("{}StartHoverTime", s.name), "SplitTime") {
4806                    self.problem_report_custom(
4807                        RustConstructorError::SplitTimeNotFound {
4808                            split_time_name: format!("{}StartHoverTime", s.name),
4809                        },
4810                        SeverityLevel::MildWarning,
4811                        self.problem_list.clone(),
4812                    );
4813                    self.add_split_time(
4814                        SplitTime::default().name(&format!("{}StartHoverTime", s.name)),
4815                    );
4816                };
4817                if !self.check_resource_exists(&format!("{}HintFadeAnimation", s.name), "SplitTime")
4818                {
4819                    self.problem_report_custom(
4820                        RustConstructorError::SplitTimeNotFound {
4821                            split_time_name: format!("{}HintFadeAnimation", s.name),
4822                        },
4823                        SeverityLevel::MildWarning,
4824                        self.problem_list.clone(),
4825                    );
4826                    self.add_split_time(
4827                        SplitTime::default().name(&format!("{}HintFadeAnimation", s.name)),
4828                    );
4829                };
4830                if !self.check_resource_exists(&s.hint_text_name, "Text") {
4831                    self.problem_report_custom(
4832                        RustConstructorError::TextNotFound {
4833                            text_name: s.hint_text_name.clone(),
4834                        },
4835                        SeverityLevel::MildWarning,
4836                        self.problem_list.clone(),
4837                    );
4838                    self.add_text(
4839                        Text::default()
4840                            .name(&s.hint_text_name)
4841                            .content("")
4842                            .origin_position(0_f32, 0_f32)
4843                            .font_size(25_f32)
4844                            .wrap_width(300_f32)
4845                            .background_rounding(10_f32)
4846                            .color(255, 255, 255, 0)
4847                            .background_color(0, 0, 0, 255)
4848                            .center_display(HorizontalAlign::Left, VerticalAlign::Top)
4849                            .selectable(false),
4850                    );
4851                };
4852            };
4853        };
4854        let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
4855            "Image" => Box::new(
4856                self.get_resource::<Image>(&s.fill_resource_name.clone(), &s.fill_resource_type)
4857                    .unwrap()
4858                    .unwrap()
4859                    .clone(),
4860            ),
4861            "CustomRect" => Box::new(
4862                self.get_resource::<CustomRect>(
4863                    &s.fill_resource_name.clone(),
4864                    &s.fill_resource_type,
4865                )
4866                .unwrap()
4867                .unwrap()
4868                .clone(),
4869            ),
4870            &_ => {
4871                self.problem_report_custom(
4872                    RustConstructorError::SwitchFillResourceMismatch {
4873                        switch_name: name.to_string(),
4874                        fill_resource_name: s.fill_resource_name.clone(),
4875                        fill_resource_type: s.fill_resource_type.clone(),
4876                    },
4877                    SeverityLevel::SevereWarning,
4878                    self.problem_list.clone(),
4879                );
4880                return Err(RustConstructorError::SwitchFillResourceMismatch {
4881                    switch_name: name.to_string(),
4882                    fill_resource_name: s.fill_resource_name,
4883                    fill_resource_type: s.fill_resource_type,
4884                });
4885            }
4886        };
4887        s.reg_render_resource(&mut self.render_resource_list);
4888        let rect = Rect::from_min_size(
4889            Pos2::new(fr.position()[0], fr.position()[1]),
4890            Vec2::new(fr.size()[0], fr.size()[1]),
4891        );
4892        let mut hovered = false;
4893        if enable {
4894            if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos()) {
4895                // 判断是否在矩形内
4896                if rect.contains(mouse_pos) {
4897                    if !s.hint_text_name.is_empty() {
4898                        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
4899                            && !self.check_resource_exists(&s.hint_text_name, "Text")
4900                        {
4901                            self.problem_report_custom(
4902                                RustConstructorError::TextNotFound {
4903                                    text_name: s.hint_text_name.clone(),
4904                                },
4905                                SeverityLevel::SevereWarning,
4906                                self.problem_list.clone(),
4907                            );
4908                            return Err(RustConstructorError::TextNotFound {
4909                                text_name: s.hint_text_name.clone(),
4910                            });
4911                        };
4912                        let mut t = self
4913                            .get_resource::<Text>(&s.hint_text_name, "Text")
4914                            .unwrap()
4915                            .unwrap()
4916                            .clone();
4917                        if !s.last_time_hovered {
4918                            self.reset_split_time(&format!("{}StartHoverTime", s.name), safe_mode)
4919                                .unwrap();
4920                        } else if self.timer.total_time
4921                            - self
4922                                .split_time(&format!("{}StartHoverTime", s.name), safe_mode)
4923                                .unwrap()[1]
4924                            >= 2_f32
4925                            || t.color[3] != 0
4926                        {
4927                            t.color[3] = 255;
4928                            t.origin_position = [mouse_pos.x, mouse_pos.y];
4929                        };
4930                        t.center_display.0 =
4931                            if mouse_pos.x + t.size[0] <= ctx.available_rect().width() {
4932                                HorizontalAlign::Left
4933                            } else {
4934                                HorizontalAlign::Right
4935                            };
4936                        t.center_display.1 =
4937                            if mouse_pos.y + t.size[1] <= ctx.available_rect().height() {
4938                                VerticalAlign::Top
4939                            } else {
4940                                VerticalAlign::Bottom
4941                            };
4942                        self.replace_resource(&s.hint_text_name, "Text", t.clone())
4943                            .unwrap();
4944                    };
4945                    hovered = true;
4946                    let mut clicked = vec![];
4947                    for u in 0..s.click_method.len() as u32 {
4948                        clicked.push(ui.input(|i| {
4949                            i.pointer
4950                                .button_down(s.click_method[u as usize].click_method)
4951                        }));
4952                        if clicked[u as usize] {
4953                            s.last_time_clicked_index = u as usize;
4954                            break;
4955                        };
4956                    }
4957                    if clicked.iter().any(|x| *x) {
4958                        s.last_time_clicked = true;
4959                        if s.enable_hover_click_fill_resource[1] {
4960                            if s.enable_hover_click_fill_resource[0] {
4961                                appearance_count = 2;
4962                            } else {
4963                                appearance_count = 1;
4964                            };
4965                        } else if !s.enable_hover_click_fill_resource[0] {
4966                            appearance_count = 0;
4967                        };
4968                    } else {
4969                        if s.last_time_clicked {
4970                            s.switched = true;
4971                            if s.click_method[s.last_time_clicked_index].action {
4972                                if s.state
4973                                    < (s.appearance.len() / s.animation_count as usize - 1) as u32
4974                                {
4975                                    s.state += 1;
4976                                } else {
4977                                    s.state = 0;
4978                                };
4979                            };
4980                            s.last_time_clicked = false;
4981                        };
4982                        if s.enable_hover_click_fill_resource[0] {
4983                            appearance_count = 1;
4984                        } else {
4985                            appearance_count = 0;
4986                        };
4987                    };
4988                } else {
4989                    s.last_time_clicked = false;
4990                    appearance_count = 0;
4991                };
4992            } else {
4993                s.last_time_clicked = false;
4994                appearance_count = 0;
4995            };
4996        } else {
4997            s.last_time_clicked = false;
4998            appearance_count = 0;
4999        };
5000        if !hovered && !s.hint_text_name.is_empty() {
5001            if s.last_time_hovered {
5002                self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5003                    .unwrap();
5004            };
5005            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5006                && !self.check_resource_exists(&s.hint_text_name, "Text")
5007            {
5008                self.problem_report_custom(
5009                    RustConstructorError::TextNotFound {
5010                        text_name: s.hint_text_name.clone(),
5011                    },
5012                    SeverityLevel::SevereWarning,
5013                    self.problem_list.clone(),
5014                );
5015                return Err(RustConstructorError::TextNotFound {
5016                    text_name: s.hint_text_name.clone(),
5017                });
5018            };
5019            let mut t = self
5020                .get_resource::<Text>(&s.hint_text_name, "Text")
5021                .unwrap()
5022                .unwrap()
5023                .clone();
5024            if self.timer.total_time
5025                - self
5026                    .split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5027                    .unwrap()[1]
5028                >= self.tick_interval
5029            {
5030                self.reset_split_time(&format!("{}HintFadeAnimation", s.name), safe_mode)
5031                    .unwrap();
5032                t.color[3] = t.color[3].saturating_sub(10);
5033            };
5034            self.replace_resource(&s.hint_text_name, "Text", t.clone())
5035                .unwrap();
5036        };
5037        let fr: Box<dyn BasicFrontResource> = match &*s.fill_resource_type {
5038            "Image" => {
5039                let mut im = Box::new(
5040                    fr.as_any()
5041                        .downcast_ref::<Image>()
5042                        .unwrap()
5043                        .clone()
5044                        .from_config(
5045                            s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5046                                .image_config
5047                                .clone(),
5048                        ),
5049                );
5050                if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5051                    && !self.check_resource_exists(
5052                        &s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5053                            .texture
5054                            .clone(),
5055                        "ImageTexture",
5056                    )
5057                {
5058                    self.problem_report_custom(
5059                        RustConstructorError::ImageTextureNotFound {
5060                            image_texture_name: s.appearance
5061                                [(s.state * s.animation_count + appearance_count) as usize]
5062                                .texture
5063                                .clone(),
5064                        },
5065                        SeverityLevel::SevereWarning,
5066                        self.problem_list.clone(),
5067                    );
5068                    return Err(RustConstructorError::ImageTextureNotFound {
5069                        image_texture_name: s.appearance
5070                            [(s.state * s.animation_count + appearance_count) as usize]
5071                            .texture
5072                            .clone(),
5073                    });
5074                };
5075                im.cite_texture = s.appearance
5076                    [(s.state * s.animation_count + appearance_count) as usize]
5077                    .texture
5078                    .clone();
5079                im
5080            }
5081            "CustomRect" => Box::new(
5082                fr.as_any()
5083                    .downcast_ref::<CustomRect>()
5084                    .unwrap()
5085                    .clone()
5086                    .name(&s.fill_resource_name)
5087                    .from_config(
5088                        s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5089                            .custom_rect_config
5090                            .clone(),
5091                    ),
5092            ),
5093            &_ => {
5094                self.problem_report_custom(
5095                    RustConstructorError::SwitchFillResourceMismatch {
5096                        switch_name: name.to_string(),
5097                        fill_resource_name: s.fill_resource_name.clone(),
5098                        fill_resource_type: s.fill_resource_type.clone(),
5099                    },
5100                    SeverityLevel::SevereWarning,
5101                    self.problem_list.clone(),
5102                );
5103                return Err(RustConstructorError::SwitchFillResourceMismatch {
5104                    switch_name: name.to_string(),
5105                    fill_resource_name: s.fill_resource_name,
5106                    fill_resource_type: s.fill_resource_type,
5107                });
5108            }
5109        };
5110        if !s.hint_text_name.is_empty() {
5111            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5112                && !self.check_resource_exists(&s.hint_text_name, "Text")
5113            {
5114                self.problem_report_custom(
5115                    RustConstructorError::TextNotFound {
5116                        text_name: s.hint_text_name.clone(),
5117                    },
5118                    SeverityLevel::SevereWarning,
5119                    self.problem_list.clone(),
5120                );
5121                return Err(RustConstructorError::TextNotFound {
5122                    text_name: s.hint_text_name,
5123                });
5124            };
5125            let mut t = self
5126                .get_resource::<Text>(&s.hint_text_name, "Text")
5127                .unwrap()
5128                .unwrap()
5129                .clone();
5130            t.background_color[3] = t.color[3];
5131            t.content = s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5132                .hint_text
5133                .clone();
5134            self.replace_resource(&s.hint_text_name, "Text", t.clone())
5135                .unwrap();
5136        };
5137        s.last_time_hovered = hovered;
5138        self.replace_resource(name, "Switch", s.clone()).unwrap();
5139        match s.fill_resource_type.as_str() {
5140            "Image" => {
5141                let im = fr.as_any().downcast_ref::<Image>().unwrap().clone();
5142                self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, im)
5143                    .unwrap();
5144                self.image(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5145                    .unwrap();
5146            }
5147            "CustomRect" => {
5148                let cr = fr.as_any().downcast_ref::<CustomRect>().unwrap().clone();
5149                self.replace_resource(&s.fill_resource_name, &s.fill_resource_type, cr)
5150                    .unwrap();
5151                self.custom_rect(&s.fill_resource_name.clone(), ui, ctx, safe_mode)
5152                    .unwrap();
5153            }
5154            &_ => {}
5155        };
5156        s.text_origin_position = s.appearance
5157            [(s.state * s.animation_count + appearance_count) as usize]
5158            .text_config
5159            .origin_position;
5160        if !s.text_name.is_empty() {
5161            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5162                && !self.check_resource_exists(&s.text_name, "Text")
5163            {
5164                self.problem_report_custom(
5165                    RustConstructorError::TextNotFound {
5166                        text_name: s.text_name.clone(),
5167                    },
5168                    SeverityLevel::SevereWarning,
5169                    self.problem_list.clone(),
5170                );
5171                return Err(RustConstructorError::TextNotFound {
5172                    text_name: s.text_name,
5173                });
5174            };
5175            let mut t = self
5176                .get_resource::<Text>(&s.text_name, "Text")
5177                .unwrap()
5178                .unwrap()
5179                .clone();
5180            t.origin_position = [
5181                fr.position()[0] + s.text_origin_position[0],
5182                fr.position()[1] + s.text_origin_position[1],
5183            ];
5184            t = t.from_config(
5185                s.appearance[(s.state * s.animation_count + appearance_count) as usize]
5186                    .text_config
5187                    .clone(),
5188            );
5189            self.replace_resource(&s.text_name, "Text", t.clone())
5190                .unwrap();
5191            self.text(&s.text_name, ui, ctx, safe_mode).unwrap();
5192        };
5193        if !s.hint_text_name.is_empty() {
5194            if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5195                && !self.check_resource_exists(&s.hint_text_name, "Text")
5196            {
5197                self.problem_report_custom(
5198                    RustConstructorError::TextNotFound {
5199                        text_name: s.hint_text_name.clone(),
5200                    },
5201                    SeverityLevel::SevereWarning,
5202                    self.problem_list.clone(),
5203                );
5204                return Err(RustConstructorError::TextNotFound {
5205                    text_name: s.hint_text_name,
5206                });
5207            };
5208            self.text(&s.hint_text_name, ui, ctx, safe_mode).unwrap();
5209        };
5210        Ok(())
5211    }
5212
5213    /// 查找指定开关的常用判定字段集合。
5214    pub fn check_switch_data(
5215        &self,
5216        name: &str,
5217        safe_mode: Option<bool>,
5218    ) -> Result<SwitchData, RustConstructorError> {
5219        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5220            && !self.check_resource_exists(name, "Switch")
5221        {
5222            self.problem_report_custom(
5223                RustConstructorError::SwitchNotFound {
5224                    switch_name: name.to_string(),
5225                },
5226                SeverityLevel::SevereWarning,
5227                self.problem_list.clone(),
5228            );
5229            return Err(RustConstructorError::SwitchNotFound {
5230                switch_name: name.to_string(),
5231            });
5232        };
5233        let s = self
5234            .get_resource::<Switch>(name, "Switch")
5235            .unwrap()
5236            .unwrap();
5237        Ok(SwitchData {
5238            switched: s.switched,
5239            last_time_clicked_index: s.last_time_clicked_index,
5240            state: s.state,
5241        })
5242    }
5243
5244    /// 添加鼠标检测器资源。
5245    pub fn add_mouse_detector(&mut self, mouse_detector: MouseDetector) {
5246        self.rust_constructor_resource
5247            .push(Box::new(mouse_detector));
5248    }
5249
5250    pub fn mouse_detector(
5251        &mut self,
5252        name: &str,
5253        ui: &Ui,
5254        ctx: &Context,
5255        mouse_detector_level: MouseDetectorLevel,
5256        safe_mode: Option<bool>,
5257    ) -> Result<(), RustConstructorError> {
5258        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5259            && !self.check_resource_exists(name, "MouseDetector")
5260        {
5261            self.problem_report_custom(
5262                RustConstructorError::MouseDetectorNotFound {
5263                    mouse_detector_name: name.to_string(),
5264                },
5265                SeverityLevel::SevereWarning,
5266                self.problem_list.clone(),
5267            );
5268            return Err(RustConstructorError::MouseDetectorNotFound {
5269                mouse_detector_name: name.to_string(),
5270            });
5271        };
5272        let md = self
5273            .get_resource_mut::<MouseDetector>(name, "MouseDetector")
5274            .unwrap();
5275        md.position[0] = match md.x_grid[1] {
5276            0 => md.origin_position[0],
5277            _ => {
5278                (ctx.available_rect().width() as f64 / md.x_grid[1] as f64 * md.x_grid[0] as f64)
5279                    as f32
5280                    + md.origin_position[0]
5281            }
5282        };
5283        md.position[1] = match md.y_grid[1] {
5284            0 => md.origin_position[1],
5285            _ => {
5286                (ctx.available_rect().height() as f64 / md.y_grid[1] as f64 * md.y_grid[0] as f64)
5287                    as f32
5288                    + md.origin_position[1]
5289            }
5290        };
5291        match md.center_display.0 {
5292            HorizontalAlign::Left => {}
5293            HorizontalAlign::Center => md.position[0] -= md.size[0] / 2.0,
5294            HorizontalAlign::Right => md.position[0] -= md.size[0],
5295        };
5296        match md.center_display.1 {
5297            VerticalAlign::Top => {}
5298            VerticalAlign::Center => md.position[1] -= md.size[1] / 2.0,
5299            VerticalAlign::Bottom => md.position[1] -= md.size[1],
5300        };
5301        md.position[0] += md.offset[0];
5302        md.position[1] += md.offset[1];
5303        let rect = Rect::from_min_max(
5304            Pos2::new(md.position[0], md.position[1]),
5305            Pos2::new(md.position[0] + md.size[0], md.position[1] + md.size[1]),
5306        );
5307        let response = ui.interact(rect, Id::new(name), Sense::click_and_drag());
5308        md.detect_result = match mouse_detector_level {
5309            MouseDetectorLevel::Lite => MouseDetectResult {
5310                clicked: response.clicked(),
5311                contains_pointer: response.contains_pointer(),
5312                secondary_clicked: None,
5313                middle_clicked: None,
5314                clicked_by_extra_button: None,
5315                long_touched: None,
5316                double_clicked: None,
5317                triple_clicked: None,
5318                double_clicked_by: None,
5319                triple_clicked_by: None,
5320                clicked_elsewhere: None,
5321                hovered: None,
5322                drag_started: None,
5323                drag_started_by: None,
5324                dragged: None,
5325                dragged_by: None,
5326                drag_stopped: None,
5327                deag_stopped_by: None,
5328                drag_delta: None,
5329                total_drag_delta: None,
5330                drag_motion: None,
5331                interact_pointer_pos: None,
5332                hover_pos: None,
5333                is_pointer_button_down_on: None,
5334            },
5335            MouseDetectorLevel::Default => {
5336                let interact_hover_pos = response.interact_pointer_pos();
5337                let hover_pos = response.hover_pos();
5338                MouseDetectResult {
5339                    clicked: response.clicked(),
5340                    contains_pointer: response.contains_pointer(),
5341                    secondary_clicked: Some(response.secondary_clicked()),
5342                    middle_clicked: Some(response.middle_clicked()),
5343                    clicked_by_extra_button: None,
5344                    long_touched: None,
5345                    double_clicked: Some(response.double_clicked()),
5346                    triple_clicked: Some(response.triple_clicked()),
5347                    double_clicked_by: None,
5348                    triple_clicked_by: None,
5349                    clicked_elsewhere: Some(response.clicked_elsewhere()),
5350                    hovered: Some(response.hovered()),
5351                    drag_started: Some(response.drag_started()),
5352                    drag_started_by: None,
5353                    dragged: Some(response.dragged()),
5354                    dragged_by: None,
5355                    drag_stopped: Some(response.drag_stopped()),
5356                    deag_stopped_by: None,
5357                    drag_delta: None,
5358                    total_drag_delta: None,
5359                    drag_motion: None,
5360                    interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5361                        Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5362                    } else {
5363                        Some(None)
5364                    },
5365                    hover_pos: if let Some(hover_pos) = hover_pos {
5366                        Some(Some([hover_pos.x, hover_pos.y]))
5367                    } else {
5368                        Some(None)
5369                    },
5370                    is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5371                }
5372            }
5373            MouseDetectorLevel::Pro => {
5374                let interact_hover_pos = response.interact_pointer_pos();
5375                let hover_pos = response.hover_pos();
5376                let total_drag_delta = response.total_drag_delta();
5377                MouseDetectResult {
5378                    clicked: response.clicked(),
5379                    contains_pointer: response.contains_pointer(),
5380                    secondary_clicked: Some(response.secondary_clicked()),
5381                    middle_clicked: Some(response.middle_clicked()),
5382                    clicked_by_extra_button: Some([
5383                        response.clicked_by(PointerButton::Extra1),
5384                        response.clicked_by(PointerButton::Extra2),
5385                    ]),
5386                    long_touched: Some(response.long_touched()),
5387                    double_clicked: Some(response.double_clicked()),
5388                    triple_clicked: Some(response.triple_clicked()),
5389                    double_clicked_by: Some([
5390                        response.double_clicked_by(PointerButton::Primary),
5391                        response.double_clicked_by(PointerButton::Secondary),
5392                        response.double_clicked_by(PointerButton::Middle),
5393                        response.double_clicked_by(PointerButton::Extra1),
5394                        response.double_clicked_by(PointerButton::Extra2),
5395                    ]),
5396                    triple_clicked_by: Some([
5397                        response.triple_clicked_by(PointerButton::Primary),
5398                        response.triple_clicked_by(PointerButton::Secondary),
5399                        response.triple_clicked_by(PointerButton::Middle),
5400                        response.triple_clicked_by(PointerButton::Extra1),
5401                        response.triple_clicked_by(PointerButton::Extra2),
5402                    ]),
5403                    clicked_elsewhere: Some(response.clicked_elsewhere()),
5404                    hovered: Some(response.hovered()),
5405                    drag_started: Some(response.drag_started()),
5406                    drag_started_by: Some([
5407                        response.drag_started_by(PointerButton::Primary),
5408                        response.drag_started_by(PointerButton::Secondary),
5409                        response.drag_started_by(PointerButton::Middle),
5410                        response.drag_started_by(PointerButton::Extra1),
5411                        response.drag_started_by(PointerButton::Extra2),
5412                    ]),
5413                    dragged: Some(response.dragged()),
5414                    dragged_by: Some([
5415                        response.dragged_by(PointerButton::Primary),
5416                        response.dragged_by(PointerButton::Secondary),
5417                        response.dragged_by(PointerButton::Middle),
5418                        response.dragged_by(PointerButton::Extra1),
5419                        response.dragged_by(PointerButton::Extra2),
5420                    ]),
5421                    drag_stopped: Some(response.drag_stopped()),
5422                    deag_stopped_by: Some([
5423                        response.drag_stopped_by(PointerButton::Primary),
5424                        response.drag_stopped_by(PointerButton::Secondary),
5425                        response.drag_stopped_by(PointerButton::Middle),
5426                        response.drag_stopped_by(PointerButton::Extra1),
5427                        response.drag_stopped_by(PointerButton::Extra2),
5428                    ]),
5429                    drag_delta: Some([response.drag_delta().x, response.drag_delta().y]),
5430                    total_drag_delta: if let Some(total_drag_delta) = total_drag_delta {
5431                        Some(Some([total_drag_delta.x, total_drag_delta.y]))
5432                    } else {
5433                        Some(None)
5434                    },
5435                    drag_motion: Some([response.drag_motion().x, response.drag_motion().y]),
5436                    interact_pointer_pos: if let Some(interact_hover_pos) = interact_hover_pos {
5437                        Some(Some([interact_hover_pos.x, interact_hover_pos.y]))
5438                    } else {
5439                        Some(None)
5440                    },
5441                    hover_pos: if let Some(hover_pos) = hover_pos {
5442                        Some(Some([hover_pos.x, hover_pos.y]))
5443                    } else {
5444                        Some(None)
5445                    },
5446                    is_pointer_button_down_on: Some(response.is_pointer_button_down_on()),
5447                }
5448            }
5449        };
5450        Ok(())
5451    }
5452
5453    pub fn check_mouse_detect_result(
5454        &self,
5455        name: &str,
5456        safe_mode: Option<bool>,
5457    ) -> Result<MouseDetectResult, RustConstructorError> {
5458        if (safe_mode.is_some() && safe_mode.unwrap() || self.safe_mode)
5459            && !self.check_resource_exists(name, "MouseDetector")
5460        {
5461            self.problem_report_custom(
5462                RustConstructorError::MouseDetectorNotFound {
5463                    mouse_detector_name: name.to_string(),
5464                },
5465                SeverityLevel::SevereWarning,
5466                self.problem_list.clone(),
5467            );
5468            return Err(RustConstructorError::MouseDetectorNotFound {
5469                mouse_detector_name: name.to_string(),
5470            });
5471        };
5472        let md = self
5473            .get_resource::<MouseDetector>(name, "MouseDetector")
5474            .unwrap()
5475            .unwrap();
5476        Ok(md.detect_result.clone())
5477    }
5478}