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