rust_constructor/
lib.rs

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