Skip to main content

rust_constructor/
lib.rs

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