rust_constructor/
lib.rs

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