rust_constructor/
lib.rs

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