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