rust_constructor/
lib.rs

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