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)]
1682pub struct App {
1683    /// RC资源。
1684    pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
1685    /// RC资源刷新率。
1686    pub tick_interval: f32,
1687    /// 当前页面。
1688    pub current_page: String,
1689    /// 计时器。
1690    pub timer: Timer,
1691    /// 帧时间。
1692    pub frame_times: Vec<f32>,
1693    /// 上一帧时间。
1694    pub last_frame_time: Option<f32>,
1695    /// 标记哪些资源属于基本前端资源,此列表不应以任何形式进行修改。
1696    pub basic_front_resource_list: Vec<String>,
1697    /// 标记渲染物件的层级和位置。
1698    pub render_layer: Vec<([String; 2], [[f32; 2]; 2], bool)>,
1699    /// 活跃资源列表。
1700    pub active_list: Vec<[String; 2]>,
1701    /// 渲染队列。
1702    pub render_list: Vec<[String; 2]>,
1703    /// 事件列表。
1704    pub event_list: Vec<Event>,
1705    /// 事件映射。
1706    pub event_map: Vec<[String; 2]>,
1707}
1708
1709impl Default for App {
1710    fn default() -> Self {
1711        App {
1712            rust_constructor_resource: Vec::new(),
1713            tick_interval: 0.05,
1714            current_page: String::new(),
1715            timer: Timer::default(),
1716            frame_times: Vec::new(),
1717            last_frame_time: None,
1718            basic_front_resource_list: vec![
1719                String::from("rust_constructor::Image"),
1720                String::from("rust_constructor::Text"),
1721                String::from("rust_constructor::CustomRect"),
1722            ],
1723            render_layer: Vec::new(),
1724            active_list: Vec::new(),
1725            render_list: Vec::new(),
1726            event_list: Vec::new(),
1727            event_map: vec![
1728                [
1729                    "rust_constructor::001".to_string(),
1730                    "Attempting to create an external resource.".to_string(),
1731                ],
1732                [
1733                    "rust_constructor::002".to_string(),
1734                    "Attempting to remove an external resource.".to_string(),
1735                ],
1736                [
1737                    "rust_constructor::003".to_string(),
1738                    "Attempting to use an external resource.".to_string(),
1739                ],
1740            ],
1741        }
1742    }
1743}
1744
1745impl App {
1746    const PLACEHOLDER: [&str; 2] = ["PLACEHOLDER", "rust_constructor::Placeholder"];
1747    #[inline]
1748    pub fn tick_interval(mut self, tick_interval: f32) -> Self {
1749        self.tick_interval = tick_interval;
1750        self
1751    }
1752
1753    #[inline]
1754    pub fn current_page(mut self, current_page: &str) -> Self {
1755        self.current_page = current_page.to_string();
1756        self
1757    }
1758
1759    /// 添加事件。
1760    pub fn add_event(&mut self, id: &str, tag: HashMap<&str, &str>, auto_delete: bool) {
1761        self.event_list.push(Event {
1762            id: id.to_string(),
1763            tag: tag
1764                .into_iter()
1765                .map(|s| (s.0.to_string(), s.1.to_string()))
1766                .collect(),
1767            description: if let Some(index) = self.event_map.iter().position(|x| x[0] == id) {
1768                self.event_map[index][1].clone()
1769            } else {
1770                "This event has no description.".to_string()
1771            },
1772            event_state: EventState {
1773                current_page: self.current_page.clone(),
1774                current_total_runtime: self.timer.total_time,
1775                current_page_runtime: self.timer.now_time,
1776            },
1777            auto_delete,
1778            handled: false,
1779        });
1780    }
1781
1782    /// 更新事件列表。
1783    pub fn update_event_list(&mut self) {
1784        let mut count = 0;
1785        for event in &mut self.event_list.clone() {
1786            if event.handled && event.auto_delete {
1787                self.event_list.remove(count);
1788                continue;
1789            };
1790            count += 1;
1791        }
1792    }
1793
1794    /// 一次性绘制所有资源,会丢弃所有返回值,不建议使用。
1795    pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
1796        for i in 0..self.render_list.len() {
1797            #[allow(warnings)]
1798            self.draw_resource_by_index(ui, ctx, i);
1799        }
1800    }
1801
1802    /// 根据索引值绘制资源,建议使用for循环搭配。
1803    pub fn draw_resource_by_index(
1804        &mut self,
1805        ui: &mut Ui,
1806        ctx: &Context,
1807        index: usize,
1808    ) -> Result<(), RustConstructorError> {
1809        if index < self.render_list.len() {
1810            let render_resource = &self.render_list.clone()[index];
1811            match &*render_resource[1] {
1812                "rust_constructor::Image" => {
1813                    let image =
1814                        self.get_resource::<Image>(&render_resource[0], "rust_constructor::Image")?;
1815                    if image.display_info.enable {
1816                        let mut image = image.clone();
1817                        if image.cite_texture != image.last_frame_cite_texture {
1818                            let image_texture = self.get_resource::<ImageTexture>(
1819                                &image.cite_texture,
1820                                "rust_constructor::ImageTexture",
1821                            )?;
1822                            image.texture = image_texture.texture.clone();
1823                        };
1824                        [
1825                            image
1826                                .basic_front_resource_config
1827                                .position_size_config
1828                                .position,
1829                            image.basic_front_resource_config.position_size_config.size,
1830                        ] = self.position_size_processor(
1831                            image.basic_front_resource_config.position_size_config,
1832                            ctx,
1833                        );
1834                        if !image.display_info.hidden {
1835                            if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
1836                                let [min, size] = self.position_size_processor(clip_rect, ctx);
1837                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
1838                            };
1839                            if let Some(texture) = &image.texture {
1840                                let rect = Rect::from_min_size(
1841                                    Pos2::new(
1842                                        image
1843                                            .basic_front_resource_config
1844                                            .position_size_config
1845                                            .position[0],
1846                                        image
1847                                            .basic_front_resource_config
1848                                            .position_size_config
1849                                            .position[1],
1850                                    ),
1851                                    Vec2::new(
1852                                        image.basic_front_resource_config.position_size_config.size
1853                                            [0],
1854                                        image.basic_front_resource_config.position_size_config.size
1855                                            [1],
1856                                    ),
1857                                );
1858
1859                                // 直接绘制图片
1860                                egui::Image::new(ImageSource::Texture((&texture.0).into()))
1861                                    .tint(Color32::from_rgba_unmultiplied(
1862                                        image.overlay_color[0],
1863                                        image.overlay_color[1],
1864                                        image.overlay_color[2],
1865                                        // 将图片透明度与覆盖颜色透明度相乘
1866                                        (image.alpha as f32 * image.overlay_color[3] as f32 / 255.0)
1867                                            as u8,
1868                                    ))
1869                                    .bg_fill(Color32::from_rgba_unmultiplied(
1870                                        image.background_color[0],
1871                                        image.background_color[1],
1872                                        image.background_color[2],
1873                                        image.background_color[3],
1874                                    ))
1875                                    .rotate(
1876                                        image.rotate_angle,
1877                                        [
1878                                            image.rotate_center[0]
1879                                                / image
1880                                                    .basic_front_resource_config
1881                                                    .position_size_config
1882                                                    .size[0],
1883                                            image.rotate_center[1]
1884                                                / image
1885                                                    .basic_front_resource_config
1886                                                    .position_size_config
1887                                                    .size[1],
1888                                        ]
1889                                        .into(),
1890                                    )
1891                                    .paint_at(ui, rect)
1892                            };
1893                            if image.basic_front_resource_config.clip_rect.is_some() {
1894                                ui.set_clip_rect(Rect::from_min_size(
1895                                    [0_f32, 0_f32].into(),
1896                                    [ctx.available_rect().width(), ctx.available_rect().height()]
1897                                        .into(),
1898                                ));
1899                            };
1900                        };
1901                        image.last_frame_cite_texture = image.cite_texture.clone();
1902                        self.replace_resource(&render_resource[0], image)?;
1903                    };
1904                }
1905                "rust_constructor::Text" => {
1906                    let text =
1907                        self.get_resource::<Text>(&render_resource[0], "rust_constructor::Text")?;
1908                    if text.display_info.enable {
1909                        let mut text = text.clone();
1910                        [
1911                            text.basic_front_resource_config
1912                                .position_size_config
1913                                .position,
1914                            text.basic_front_resource_config.position_size_config.size,
1915                        ] = self.position_size_processor(
1916                            text.basic_front_resource_config.position_size_config,
1917                            ctx,
1918                        );
1919                        let display_content = if text.truncate {
1920                            let original_galley = ui.fonts_mut(|f| {
1921                                f.layout(
1922                                    text.content.to_string(),
1923                                    FontId::proportional(text.font_size),
1924                                    Color32::default(),
1925                                    text.basic_front_resource_config.position_size_config.size[0],
1926                                )
1927                            });
1928
1929                            let mut truncated = text.content.to_string();
1930                            let mut ellipsis = "";
1931                            if original_galley.size().y
1932                                > text.basic_front_resource_config.position_size_config.size[1]
1933                            {
1934                                // 如果超出,逐步缩短文本直到加上省略号后能放下
1935                                ellipsis = "...";
1936
1937                                while !truncated.is_empty() {
1938                                    let test_text = format!("{}{}", truncated, ellipsis);
1939                                    let test_galley = ui.fonts_mut(|f| {
1940                                        f.layout(
1941                                            test_text,
1942                                            FontId::proportional(text.font_size),
1943                                            Color32::default(),
1944                                            text.basic_front_resource_config
1945                                                .position_size_config
1946                                                .size[0],
1947                                        )
1948                                    });
1949
1950                                    if test_galley.size().y
1951                                        <= text
1952                                            .basic_front_resource_config
1953                                            .position_size_config
1954                                            .size[1]
1955                                    {
1956                                        break;
1957                                    }
1958
1959                                    // 移除最后一个字符
1960                                    truncated.pop();
1961                                }
1962                            };
1963                            format!("{}{}", truncated, ellipsis)
1964                        } else {
1965                            text.content.to_string()
1966                        };
1967                        // 计算文本大小
1968                        let galley: Arc<Galley> = ui.fonts_mut(|f| {
1969                            f.layout(
1970                                display_content.to_string(),
1971                                if !text.font.is_empty() {
1972                                    if self
1973                                        .check_resource_exists(&text.font, "rust_constructor::Font")
1974                                        .is_none()
1975                                    {
1976                                        FontId::new(
1977                                            text.font_size,
1978                                            FontFamily::Name(text.font.clone().into()),
1979                                        )
1980                                    } else {
1981                                        FontId::proportional(text.font_size)
1982                                    }
1983                                } else {
1984                                    FontId::proportional(text.font_size)
1985                                },
1986                                Color32::from_rgba_unmultiplied(
1987                                    text.color[0],
1988                                    text.color[1],
1989                                    text.color[2],
1990                                    text.color[3],
1991                                ),
1992                                text.basic_front_resource_config.position_size_config.size[0],
1993                            )
1994                        });
1995                        text.actual_size = [galley.size().x, galley.size().y];
1996                        // 查找超链接索引值
1997                        if text.last_frame_content != display_content {
1998                            text.hyperlink_index.clear();
1999
2000                            // 创建字节索引到字符索引的映射
2001                            let byte_to_char_map: std::collections::HashMap<usize, usize> =
2002                                display_content
2003                                    .char_indices()
2004                                    .enumerate()
2005                                    .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
2006                                    .collect();
2007
2008                            for (hyperlink_text, method) in &text.hyperlink_text {
2009                                let matches: Vec<(usize, &str)> =
2010                                    display_content.match_indices(hyperlink_text).collect();
2011                                let text_char_count = hyperlink_text.chars().count();
2012
2013                                if let HyperlinkSelectMethod::All(url) = method {
2014                                    for (byte_index, _) in matches {
2015                                        if let Some(&start_char_index) =
2016                                            byte_to_char_map.get(&byte_index)
2017                                        {
2018                                            text.hyperlink_index.push((
2019                                                start_char_index,
2020                                                start_char_index + text_char_count,
2021                                                url.clone(),
2022                                            ));
2023                                        };
2024                                    }
2025                                } else if let HyperlinkSelectMethod::Segment(list) = method {
2026                                    for (index, url) in list {
2027                                        if *index >= matches.len() {
2028                                            continue;
2029                                        };
2030                                        let (byte_index, _) = matches[*index];
2031                                        if let Some(&start_char_index) =
2032                                            byte_to_char_map.get(&byte_index)
2033                                        {
2034                                            text.hyperlink_index.push((
2035                                                start_char_index,
2036                                                start_char_index + text_char_count,
2037                                                url.clone(),
2038                                            ));
2039                                        };
2040                                    }
2041                                };
2042                            }
2043                        };
2044                        if !text.display_info.hidden {
2045                            // 使用绝对定位放置文本
2046                            let rect = Rect::from_min_size(
2047                                text.basic_front_resource_config
2048                                    .position_size_config
2049                                    .position
2050                                    .into(),
2051                                text.actual_size.into(),
2052                            );
2053                            // 绘制背景颜色
2054                            ui.painter().rect_filled(
2055                                rect,
2056                                text.background_rounding,
2057                                Color32::from_rgba_unmultiplied(
2058                                    text.background_color[0],
2059                                    text.background_color[1],
2060                                    text.background_color[2],
2061                                    text.background_color[3],
2062                                ),
2063                            );
2064
2065                            if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
2066                                let [min, size] = self.position_size_processor(clip_rect, ctx);
2067                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2068                            };
2069
2070                            // 绘制文本
2071                            ui.painter().galley(
2072                                text.basic_front_resource_config
2073                                    .position_size_config
2074                                    .position
2075                                    .into(),
2076                                galley.clone(),
2077                                Color32::from_rgba_unmultiplied(
2078                                    text.color[0],
2079                                    text.color[1],
2080                                    text.color[2],
2081                                    text.color[3],
2082                                ),
2083                            );
2084
2085                            // 绘制超链接
2086                            for (start, end, _) in &text.hyperlink_index {
2087                                // 获取超链接文本的范围
2088                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2089                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2090
2091                                let start_pos = start_cursor.left_top();
2092                                let end_pos = end_cursor.right_top();
2093                                // 绘制超链接下划线
2094                                // 检查超链接是否跨行
2095                                if start_cursor.min.y == end_cursor.min.y {
2096                                    // 单行超链接
2097                                    let underline_y = text
2098                                        .basic_front_resource_config
2099                                        .position_size_config
2100                                        .position[1]
2101                                        + start_pos.y
2102                                        + galley.rows.first().map_or(14.0, |row| row.height())
2103                                        - 2.0;
2104
2105                                    // 绘制下划线
2106                                    let color = Color32::from_rgba_unmultiplied(
2107                                        text.color[0],
2108                                        text.color[1],
2109                                        text.color[2],
2110                                        text.color[3],
2111                                    );
2112
2113                                    ui.painter().line_segment(
2114                                        [
2115                                            Pos2::new(
2116                                                text.basic_front_resource_config
2117                                                    .position_size_config
2118                                                    .position[0]
2119                                                    + start_pos.x,
2120                                                underline_y,
2121                                            ),
2122                                            Pos2::new(
2123                                                text.basic_front_resource_config
2124                                                    .position_size_config
2125                                                    .position[0]
2126                                                    + end_pos.x,
2127                                                underline_y,
2128                                            ),
2129                                        ],
2130                                        Stroke::new(text.font_size / 10_f32, color),
2131                                    );
2132                                } else {
2133                                    // 多行超链接
2134                                    let row_height =
2135                                        galley.rows.first().map_or(14.0, |row| row.height()); // 默认行高14.0
2136
2137                                    // 计算起始行和结束行的索引
2138                                    let start_row = (start_pos.y / row_height).round() as usize;
2139                                    let end_row = (end_pos.y / row_height).round() as usize;
2140
2141                                    for row in start_row..=end_row {
2142                                        let row_y = text
2143                                            .basic_front_resource_config
2144                                            .position_size_config
2145                                            .position[1]
2146                                            + row as f32 * row_height
2147                                            + row_height
2148                                            - 2.0; // 行底部稍微上移一点绘制下划线
2149
2150                                        // 获取当前行的矩形范围
2151                                        if let Some(current_row) = galley.rows.get(row) {
2152                                            let row_rect = current_row.rect();
2153
2154                                            let color = Color32::from_rgba_unmultiplied(
2155                                                text.color[0],
2156                                                text.color[1],
2157                                                text.color[2],
2158                                                text.color[3],
2159                                            );
2160
2161                                            if row == start_row {
2162                                                // 第一行从文本开始位置到行尾
2163                                                ui.painter().line_segment(
2164                                                    [
2165                                                        Pos2::new(
2166                                                            text.basic_front_resource_config
2167                                                                .position_size_config
2168                                                                .position[0]
2169                                                                + start_pos.x,
2170                                                            row_y,
2171                                                        ),
2172                                                        Pos2::new(
2173                                                            text.basic_front_resource_config
2174                                                                .position_size_config
2175                                                                .position[0]
2176                                                                + row_rect.max.x,
2177                                                            row_y,
2178                                                        ),
2179                                                    ],
2180                                                    Stroke::new(text.font_size / 10_f32, color),
2181                                                );
2182                                            } else if row == end_row {
2183                                                // 最后一行从行首到文本结束位置
2184                                                ui.painter().line_segment(
2185                                                    [
2186                                                        Pos2::new(
2187                                                            text.basic_front_resource_config
2188                                                                .position_size_config
2189                                                                .position[0]
2190                                                                + row_rect.min.x,
2191                                                            row_y,
2192                                                        ),
2193                                                        Pos2::new(
2194                                                            text.basic_front_resource_config
2195                                                                .position_size_config
2196                                                                .position[0]
2197                                                                + end_pos.x,
2198                                                            row_y,
2199                                                        ),
2200                                                    ],
2201                                                    Stroke::new(text.font_size / 10_f32, color),
2202                                                );
2203                                            } else {
2204                                                // 中间整行下划线
2205                                                ui.painter().line_segment(
2206                                                    [
2207                                                        Pos2::new(
2208                                                            text.basic_front_resource_config
2209                                                                .position_size_config
2210                                                                .position[0]
2211                                                                + row_rect.min.x,
2212                                                            row_y,
2213                                                        ),
2214                                                        Pos2::new(
2215                                                            text.basic_front_resource_config
2216                                                                .position_size_config
2217                                                                .position[0]
2218                                                                + row_rect.max.x,
2219                                                            row_y,
2220                                                        ),
2221                                                    ],
2222                                                    Stroke::new(text.font_size / 10_f32, color),
2223                                                );
2224                                            };
2225                                        };
2226                                    }
2227                                };
2228                            }
2229
2230                            if text.selectable {
2231                                // 处理选择逻辑
2232                                let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
2233                                    let relative_pos = pointer_pos
2234                                        - text
2235                                            .basic_front_resource_config
2236                                            .position_size_config
2237                                            .position
2238                                            .into();
2239                                    let cursor = galley.cursor_from_pos(relative_pos);
2240                                    cursor.index
2241                                };
2242
2243                                let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
2244                                let rect = Rect::from_min_size(
2245                                    text.basic_front_resource_config
2246                                        .position_size_config
2247                                        .position
2248                                        .into(),
2249                                    text.actual_size.into(),
2250                                );
2251                                let detect_result = ui.interact(
2252                                    rect,
2253                                    Id::new(&render_resource[0]),
2254                                    Sense::click_and_drag(),
2255                                );
2256
2257                                if !detect_result.clicked()
2258                                    && (fullscreen_detect_result.any_click()
2259                                        || fullscreen_detect_result.any_pressed())
2260                                {
2261                                    text.selection = None;
2262                                };
2263
2264                                if let Some(index) = self.get_render_layer_resource(
2265                                    &render_resource[0],
2266                                    "rust_constructor::Text",
2267                                ) && let Some(mouse_pos) =
2268                                    fullscreen_detect_result.interact_pos()
2269                                    && self.resource_get_focus(index, mouse_pos.into())
2270                                    && (detect_result.clicked() || detect_result.drag_started())
2271                                {
2272                                    let cursor = cursor_at_pointer(mouse_pos.to_vec2());
2273                                    text.selection = Some((cursor, cursor));
2274                                };
2275
2276                                if detect_result.dragged()
2277                                    && text.selection.is_some()
2278                                    && let Some(pointer_pos) =
2279                                        ui.input(|i| i.pointer.interact_pos())
2280                                {
2281                                    let cursor = cursor_at_pointer(pointer_pos.to_vec2());
2282                                    if let Some((start, _)) = text.selection {
2283                                        text.selection = Some((start, cursor));
2284                                    };
2285                                };
2286
2287                                if text.selection.is_some()
2288                                    && ui.input(|input| {
2289                                        input.key_released(Key::A) && input.modifiers.command
2290                                    })
2291                                {
2292                                    text.selection = Some((0, display_content.chars().count()));
2293                                };
2294
2295                                // 处理复制操作
2296                                let copy_triggered = ui.input(|input| {
2297                                    let c_released = input.key_released(Key::C);
2298                                    let cmd_pressed = input.modifiers.command;
2299                                    c_released && cmd_pressed
2300                                });
2301                                if copy_triggered && let Some((start, end)) = text.selection {
2302                                    let (start, end) = (start.min(end), start.max(end));
2303                                    let chars: Vec<char> = display_content.chars().collect();
2304                                    if start <= chars.len() && end <= chars.len() && start < end {
2305                                        let selected_text: String =
2306                                            chars[start..end].iter().collect();
2307                                        ui.ctx().copy_text(selected_text);
2308                                    };
2309                                };
2310
2311                                // 绘制选择区域背景
2312                                if let Some((start, end)) = text.selection {
2313                                    let (start, end) = (start.min(end), start.max(end));
2314                                    if start != end {
2315                                        // 获取选择区域的范围
2316                                        let start_cursor =
2317                                            galley.pos_from_cursor(CCursor::new(start));
2318                                        let end_cursor = galley.pos_from_cursor(CCursor::new(end));
2319
2320                                        let start_pos = start_cursor.left_top();
2321                                        let end_pos = end_cursor.right_top();
2322                                        // 选择框绘制
2323                                        if start_pos.y == end_pos.y {
2324                                            // 单行选择
2325                                            let rows = &galley.rows;
2326                                            let row_height = if !rows.is_empty() {
2327                                                // 获取实际行的高度
2328                                                if let Some(row) = rows.first() {
2329                                                    row.height()
2330                                                } else {
2331                                                    text.actual_size[1]
2332                                                        / display_content.lines().count() as f32
2333                                                }
2334                                            } else {
2335                                                text.actual_size[1]
2336                                                    / display_content.lines().count() as f32
2337                                            };
2338
2339                                            let selection_rect = Rect::from_min_max(
2340                                                Pos2::new(
2341                                                    text.basic_front_resource_config
2342                                                        .position_size_config
2343                                                        .position[0]
2344                                                        + start_pos.x,
2345                                                    text.basic_front_resource_config
2346                                                        .position_size_config
2347                                                        .position[1]
2348                                                        + start_pos.y,
2349                                                ),
2350                                                Pos2::new(
2351                                                    text.basic_front_resource_config
2352                                                        .position_size_config
2353                                                        .position[0]
2354                                                        + end_pos.x,
2355                                                    text.basic_front_resource_config
2356                                                        .position_size_config
2357                                                        .position[1]
2358                                                        + start_pos.y
2359                                                        + row_height,
2360                                                ),
2361                                            );
2362                                            ui.painter().rect_filled(
2363                                                selection_rect,
2364                                                0.0,
2365                                                Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2366                                            );
2367                                        } else {
2368                                            // 多行选择 - 为每行创建精确的矩形
2369                                            let rows = &galley.rows;
2370                                            let row_height = if !rows.is_empty() {
2371                                                rows[0].height()
2372                                            } else {
2373                                                text.actual_size[1]
2374                                                    / display_content.lines().count() as f32
2375                                            };
2376
2377                                            // 计算选择的上下边界
2378                                            let selection_top = text
2379                                                .basic_front_resource_config
2380                                                .position_size_config
2381                                                .position[1]
2382                                                + start_pos.y.min(end_pos.y);
2383                                            let selection_bottom = text
2384                                                .basic_front_resource_config
2385                                                .position_size_config
2386                                                .position[1]
2387                                                + start_pos.y.max(end_pos.y);
2388
2389                                            // 确定起始行和结束行的索引
2390                                            let start_row_index =
2391                                                (start_pos.y / row_height).floor() as usize;
2392                                            let end_row_index =
2393                                                (end_pos.y / row_height).floor() as usize;
2394                                            let (first_row_index, last_row_index) =
2395                                                if start_row_index <= end_row_index {
2396                                                    (start_row_index, end_row_index)
2397                                                } else {
2398                                                    (end_row_index, start_row_index)
2399                                                };
2400
2401                                            for (i, row) in rows.iter().enumerate() {
2402                                                let row_y = text
2403                                                    .basic_front_resource_config
2404                                                    .position_size_config
2405                                                    .position[1]
2406                                                    + row_height * i as f32;
2407                                                let row_bottom = row_y + row_height;
2408                                                // 检查当前行是否与选择区域相交
2409                                                if row_bottom > selection_top
2410                                                    && row_y <= selection_bottom
2411                                                {
2412                                                    let left = if i == first_row_index {
2413                                                        // 首行 - 从选择开始位置开始
2414                                                        text.basic_front_resource_config
2415                                                            .position_size_config
2416                                                            .position[0]
2417                                                            + start_pos.x
2418                                                    } else {
2419                                                        // 非首行 - 从行首开始
2420                                                        text.basic_front_resource_config
2421                                                            .position_size_config
2422                                                            .position[0]
2423                                                            + row.rect().min.x
2424                                                    };
2425
2426                                                    let right = if i == last_row_index {
2427                                                        // 尾行 - 到选择结束位置结束
2428                                                        text.basic_front_resource_config
2429                                                            .position_size_config
2430                                                            .position[0]
2431                                                            + end_pos.x
2432                                                    } else {
2433                                                        // 非尾行 - 到行尾结束
2434                                                        text.basic_front_resource_config
2435                                                            .position_size_config
2436                                                            .position[0]
2437                                                            + row.rect().max.x
2438                                                    };
2439
2440                                                    let selection_rect = Rect::from_min_max(
2441                                                        Pos2::new(left, row_y),
2442                                                        Pos2::new(right, row_bottom),
2443                                                    );
2444
2445                                                    // 确保矩形有效
2446                                                    if selection_rect.width() > 0.0
2447                                                        && selection_rect.height() > 0.0
2448                                                    {
2449                                                        ui.painter().rect_filled(
2450                                                            selection_rect,
2451                                                            0.0,
2452                                                            Color32::from_rgba_unmultiplied(
2453                                                                0, 120, 255, 100,
2454                                                            ),
2455                                                        );
2456                                                    };
2457                                                };
2458                                            }
2459                                        };
2460                                    };
2461                                };
2462                            };
2463
2464                            // 处理超链接操作
2465                            for (start, end, url) in &text.hyperlink_index {
2466                                // 获取超链接文本的范围
2467                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
2468                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
2469
2470                                let start_pos = start_cursor.left_top();
2471                                let end_pos = end_cursor.right_top();
2472
2473                                let row_height =
2474                                    galley.rows.first().map_or(14.0, |row| row.height());
2475
2476                                // 为超链接创建交互响应对象
2477                                let link_responses = if start_cursor.min.y == end_cursor.min.y {
2478                                    // 单行超链接
2479                                    let link_rect = Rect::from_min_max(
2480                                        Pos2::new(
2481                                            text.basic_front_resource_config
2482                                                .position_size_config
2483                                                .position[0]
2484                                                + start_pos.x,
2485                                            text.basic_front_resource_config
2486                                                .position_size_config
2487                                                .position[1]
2488                                                + start_pos.y,
2489                                        ),
2490                                        Pos2::new(
2491                                            text.basic_front_resource_config
2492                                                .position_size_config
2493                                                .position[0]
2494                                                + end_pos.x,
2495                                            text.basic_front_resource_config
2496                                                .position_size_config
2497                                                .position[1]
2498                                                + start_pos.y
2499                                                + row_height,
2500                                        ),
2501                                    );
2502                                    vec![ui.interact(
2503                                        link_rect,
2504                                        egui::Id::new(format!(
2505                                            "link_{}_{}_{}",
2506                                            render_resource[0], start, end
2507                                        )),
2508                                        egui::Sense::click(),
2509                                    )]
2510                                } else {
2511                                    // 多行超链接
2512                                    let start_row = (start_pos.y / row_height).round() as usize;
2513                                    let end_row = (end_pos.y / row_height).round() as usize;
2514                                    let mut responses = Vec::new();
2515
2516                                    for row in start_row..=end_row {
2517                                        if let Some(current_row) = galley.rows.get(row) {
2518                                            let row_rect = current_row.rect();
2519                                            let row_y = text
2520                                                .basic_front_resource_config
2521                                                .position_size_config
2522                                                .position[1]
2523                                                + row as f32 * row_height;
2524
2525                                            let link_rect = if row == start_row {
2526                                                // 第一行从文本开始位置到行尾
2527                                                Rect::from_min_max(
2528                                                    Pos2::new(
2529                                                        text.basic_front_resource_config
2530                                                            .position_size_config
2531                                                            .position[0]
2532                                                            + start_pos.x,
2533                                                        row_y,
2534                                                    ),
2535                                                    Pos2::new(
2536                                                        text.basic_front_resource_config
2537                                                            .position_size_config
2538                                                            .position[0]
2539                                                            + row_rect.max.x,
2540                                                        row_y + row_height,
2541                                                    ),
2542                                                )
2543                                            } else if row == end_row {
2544                                                // 最后一行从行首到文本结束位置
2545                                                Rect::from_min_max(
2546                                                    Pos2::new(
2547                                                        text.basic_front_resource_config
2548                                                            .position_size_config
2549                                                            .position[0]
2550                                                            + row_rect.min.x,
2551                                                        row_y,
2552                                                    ),
2553                                                    Pos2::new(
2554                                                        text.basic_front_resource_config
2555                                                            .position_size_config
2556                                                            .position[0]
2557                                                            + end_pos.x,
2558                                                        row_y + row_height,
2559                                                    ),
2560                                                )
2561                                            } else {
2562                                                // 中间整行
2563                                                Rect::from_min_max(
2564                                                    Pos2::new(
2565                                                        text.basic_front_resource_config
2566                                                            .position_size_config
2567                                                            .position[0]
2568                                                            + row_rect.min.x,
2569                                                        row_y,
2570                                                    ),
2571                                                    Pos2::new(
2572                                                        text.basic_front_resource_config
2573                                                            .position_size_config
2574                                                            .position[0]
2575                                                            + row_rect.max.x,
2576                                                        row_y + row_height,
2577                                                    ),
2578                                                )
2579                                            };
2580
2581                                            responses.push(ui.interact(
2582                                                link_rect,
2583                                                Id::new(format!(
2584                                                    "link_{}_{}_{}_row_{}",
2585                                                    render_resource[0], start, end, row
2586                                                )),
2587                                                Sense::click(),
2588                                            ));
2589                                        };
2590                                    }
2591                                    responses
2592                                };
2593
2594                                // 检查是否正在点击这个超链接
2595                                let mut is_pressing_link = false;
2596                                for link_response in &link_responses {
2597                                    if let Some(index) = self.get_render_layer_resource(
2598                                        &render_resource[0],
2599                                        "rust_constructor::Text",
2600                                    ) && let Some(mouse_pos) =
2601                                        ui.input(|i| i.pointer.interact_pos())
2602                                        && self.resource_get_focus(index, mouse_pos.into())
2603                                    {
2604                                        if link_response.is_pointer_button_down_on()
2605                                            && !link_response.drag_started()
2606                                        {
2607                                            text.selection = None;
2608                                            if let Some(pointer_pos) =
2609                                                ui.input(|i| i.pointer.interact_pos())
2610                                            {
2611                                                let relative_pos = pointer_pos
2612                                                    - <[f32; 2] as Into<Pos2>>::into(
2613                                                        text.basic_front_resource_config
2614                                                            .position_size_config
2615                                                            .position,
2616                                                    );
2617                                                let cursor = galley.cursor_from_pos(relative_pos);
2618                                                if cursor.index >= *start && cursor.index <= *end {
2619                                                    is_pressing_link = true;
2620                                                    break;
2621                                                };
2622                                            };
2623                                        };
2624                                        // 检查是否释放了鼠标(点击完成)
2625                                        let mut clicked_on_link = false;
2626                                        for link_response in &link_responses {
2627                                            if link_response.clicked()
2628                                                && let Some(pointer_pos) =
2629                                                    ui.input(|i| i.pointer.interact_pos())
2630                                            {
2631                                                let relative_pos = pointer_pos
2632                                                    - <[f32; 2] as Into<Pos2>>::into(
2633                                                        text.basic_front_resource_config
2634                                                            .position_size_config
2635                                                            .position,
2636                                                    );
2637                                                let cursor = galley.cursor_from_pos(relative_pos);
2638                                                if cursor.index >= *start && cursor.index <= *end {
2639                                                    clicked_on_link = true;
2640                                                    break;
2641                                                };
2642                                            };
2643                                        }
2644
2645                                        if clicked_on_link {
2646                                            // 执行超链接跳转
2647                                            if !url.is_empty() {
2648                                                ui.ctx().open_url(OpenUrl::new_tab(url));
2649                                            };
2650                                        };
2651                                    };
2652                                }
2653
2654                                // 绘制超链接高亮(如果正在点击或悬停)
2655                                if is_pressing_link {
2656                                    if start_cursor.min.y == end_cursor.min.y {
2657                                        // 单行超链接高亮
2658                                        let selection_rect = Rect::from_min_max(
2659                                            Pos2::new(
2660                                                text.basic_front_resource_config
2661                                                    .position_size_config
2662                                                    .position[0]
2663                                                    + start_pos.x,
2664                                                text.basic_front_resource_config
2665                                                    .position_size_config
2666                                                    .position[1]
2667                                                    + start_pos.y,
2668                                            ),
2669                                            Pos2::new(
2670                                                text.basic_front_resource_config
2671                                                    .position_size_config
2672                                                    .position[0]
2673                                                    + end_pos.x,
2674                                                text.basic_front_resource_config
2675                                                    .position_size_config
2676                                                    .position[1]
2677                                                    + start_pos.y
2678                                                    + galley
2679                                                        .rows
2680                                                        .first()
2681                                                        .map_or(14.0, |row| row.height()),
2682                                            ),
2683                                        );
2684                                        ui.painter().rect_filled(
2685                                            selection_rect,
2686                                            0.0,
2687                                            Color32::from_rgba_unmultiplied(0, 120, 255, 100),
2688                                        );
2689                                    } else {
2690                                        // 多行超链接高亮
2691                                        let row_height =
2692                                            galley.rows.first().map_or(14.0, |row| row.height());
2693                                        let start_row = (start_pos.y / row_height).round() as usize;
2694                                        let end_row = (end_pos.y / row_height).round() as usize;
2695
2696                                        for row in start_row..=end_row {
2697                                            if let Some(current_row) = galley.rows.get(row) {
2698                                                let row_rect = current_row.rect();
2699
2700                                                if row == start_row {
2701                                                    // 第一行从文本开始位置到行尾
2702                                                    let selection_rect = Rect::from_min_max(
2703                                                        Pos2::new(
2704                                                            text.basic_front_resource_config
2705                                                                .position_size_config
2706                                                                .position[0]
2707                                                                + start_pos.x,
2708                                                            text.basic_front_resource_config
2709                                                                .position_size_config
2710                                                                .position[1]
2711                                                                + row as f32 * row_height,
2712                                                        ),
2713                                                        Pos2::new(
2714                                                            text.basic_front_resource_config
2715                                                                .position_size_config
2716                                                                .position[0]
2717                                                                + row_rect.max.x,
2718                                                            text.basic_front_resource_config
2719                                                                .position_size_config
2720                                                                .position[1]
2721                                                                + row as f32 * row_height
2722                                                                + row_height,
2723                                                        ),
2724                                                    );
2725                                                    ui.painter().rect_filled(
2726                                                        selection_rect,
2727                                                        0.0,
2728                                                        Color32::from_rgba_unmultiplied(
2729                                                            0, 120, 255, 100,
2730                                                        ),
2731                                                    );
2732                                                } else if row == end_row {
2733                                                    // 最后一行从行首到文本结束位置
2734                                                    let selection_rect = Rect::from_min_max(
2735                                                        Pos2::new(
2736                                                            text.basic_front_resource_config
2737                                                                .position_size_config
2738                                                                .position[0]
2739                                                                + row_rect.min.x,
2740                                                            text.basic_front_resource_config
2741                                                                .position_size_config
2742                                                                .position[1]
2743                                                                + row as f32 * row_height,
2744                                                        ),
2745                                                        Pos2::new(
2746                                                            text.basic_front_resource_config
2747                                                                .position_size_config
2748                                                                .position[0]
2749                                                                + end_pos.x,
2750                                                            text.basic_front_resource_config
2751                                                                .position_size_config
2752                                                                .position[1]
2753                                                                + row as f32 * row_height
2754                                                                + row_height,
2755                                                        ),
2756                                                    );
2757                                                    ui.painter().rect_filled(
2758                                                        selection_rect,
2759                                                        0.0,
2760                                                        Color32::from_rgba_unmultiplied(
2761                                                            0, 120, 255, 100,
2762                                                        ),
2763                                                    );
2764                                                } else {
2765                                                    // 中间整行高亮
2766                                                    let selection_rect = Rect::from_min_max(
2767                                                        Pos2::new(
2768                                                            text.basic_front_resource_config
2769                                                                .position_size_config
2770                                                                .position[0]
2771                                                                + row_rect.min.x,
2772                                                            text.basic_front_resource_config
2773                                                                .position_size_config
2774                                                                .position[1]
2775                                                                + row as f32 * row_height,
2776                                                        ),
2777                                                        Pos2::new(
2778                                                            text.basic_front_resource_config
2779                                                                .position_size_config
2780                                                                .position[0]
2781                                                                + row_rect.max.x,
2782                                                            text.basic_front_resource_config
2783                                                                .position_size_config
2784                                                                .position[1]
2785                                                                + row as f32 * row_height
2786                                                                + row_height,
2787                                                        ),
2788                                                    );
2789                                                    ui.painter().rect_filled(
2790                                                        selection_rect,
2791                                                        0.0,
2792                                                        Color32::from_rgba_unmultiplied(
2793                                                            0, 120, 255, 100,
2794                                                        ),
2795                                                    );
2796                                                };
2797                                            };
2798                                        }
2799                                    };
2800                                };
2801                            }
2802                            if text.basic_front_resource_config.clip_rect.is_some() {
2803                                ui.set_clip_rect(Rect::from_min_size(
2804                                    [0_f32, 0_f32].into(),
2805                                    [ctx.available_rect().width(), ctx.available_rect().height()]
2806                                        .into(),
2807                                ));
2808                            };
2809                        } else {
2810                            text.selection = None;
2811                        };
2812                        text.last_frame_content = display_content;
2813                        self.replace_resource(&render_resource[0], text)?;
2814                    };
2815                }
2816                "rust_constructor::CustomRect" => {
2817                    let custom_rect = self.get_resource::<CustomRect>(
2818                        &render_resource[0],
2819                        "rust_constructor::CustomRect",
2820                    )?;
2821                    if custom_rect.display_info.enable {
2822                        let mut custom_rect = custom_rect.clone();
2823                        [
2824                            custom_rect
2825                                .basic_front_resource_config
2826                                .position_size_config
2827                                .position,
2828                            custom_rect
2829                                .basic_front_resource_config
2830                                .position_size_config
2831                                .size,
2832                        ] = self.position_size_processor(
2833                            custom_rect.basic_front_resource_config.position_size_config,
2834                            ctx,
2835                        );
2836                        if !custom_rect.display_info.hidden {
2837                            if let Some(clip_rect) =
2838                                custom_rect.basic_front_resource_config.clip_rect
2839                            {
2840                                let [min, size] = self.position_size_processor(clip_rect, ctx);
2841                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
2842                            };
2843                            ui.painter().rect(
2844                                Rect::from_min_max(
2845                                    Pos2::new(
2846                                        custom_rect
2847                                            .basic_front_resource_config
2848                                            .position_size_config
2849                                            .position[0],
2850                                        custom_rect
2851                                            .basic_front_resource_config
2852                                            .position_size_config
2853                                            .position[1],
2854                                    ),
2855                                    Pos2::new(
2856                                        custom_rect
2857                                            .basic_front_resource_config
2858                                            .position_size_config
2859                                            .position[0]
2860                                            + custom_rect
2861                                                .basic_front_resource_config
2862                                                .position_size_config
2863                                                .size[0],
2864                                        custom_rect
2865                                            .basic_front_resource_config
2866                                            .position_size_config
2867                                            .position[1]
2868                                            + custom_rect
2869                                                .basic_front_resource_config
2870                                                .position_size_config
2871                                                .size[1],
2872                                    ),
2873                                ),
2874                                custom_rect.rounding,
2875                                Color32::from_rgba_unmultiplied(
2876                                    custom_rect.color[0],
2877                                    custom_rect.color[1],
2878                                    custom_rect.color[2],
2879                                    custom_rect.color[3],
2880                                ),
2881                                Stroke {
2882                                    width: custom_rect.border_width,
2883                                    color: Color32::from_rgba_unmultiplied(
2884                                        custom_rect.border_color[0],
2885                                        custom_rect.border_color[1],
2886                                        custom_rect.border_color[2],
2887                                        custom_rect.border_color[3],
2888                                    ),
2889                                },
2890                                match custom_rect.border_kind {
2891                                    BorderKind::Inside => StrokeKind::Inside,
2892                                    BorderKind::Middle => StrokeKind::Middle,
2893                                    BorderKind::Outside => StrokeKind::Outside,
2894                                },
2895                            );
2896                            if custom_rect.basic_front_resource_config.clip_rect.is_some() {
2897                                ui.set_clip_rect(Rect::from_min_size(
2898                                    [0_f32, 0_f32].into(),
2899                                    [ctx.available_rect().width(), ctx.available_rect().height()]
2900                                        .into(),
2901                                ));
2902                            };
2903                        };
2904                        self.replace_resource(&render_resource[0], custom_rect)?;
2905                    };
2906                }
2907                _ => {
2908                    unreachable!()
2909                }
2910            }
2911            Ok(())
2912        } else {
2913            Err(RustConstructorError {
2914                error_id: "IndexOutOfRange".to_string(),
2915                description: format!(
2916                    "The maximum index of the target list is {}, but the index is {index}.",
2917                    self.render_list.len() - 1
2918                ),
2919            })
2920        }
2921    }
2922
2923    /// 打印资源活跃情况。
2924    pub fn active_list_info(&self, display_complex_info: bool, format: bool) -> String {
2925        let mut text = String::from("Resource Active Info:\n");
2926        for info in &self.active_list {
2927            if display_complex_info {
2928                if let Some(index) = self
2929                    .rust_constructor_resource
2930                    .iter()
2931                    .position(|x| x.id.name == info[0] && x.id.discern_type == info[1])
2932                {
2933                    text += &if format {
2934                        format!(
2935                            "\nName: {}\nType: {}\nDetail: {:#?}\n",
2936                            info[0], info[1], self.rust_constructor_resource[index],
2937                        )
2938                    } else {
2939                        format!(
2940                            "\nName: {}\nType: {}\nDetail: {:?}\n",
2941                            info[0], info[1], self.rust_constructor_resource[index],
2942                        )
2943                    };
2944                };
2945            } else {
2946                text += &format!("\nName: {}\nType: {}\n", info[0], info[1]);
2947            };
2948        }
2949        text
2950    }
2951
2952    /// 打印渲染层级列表。
2953    pub fn render_layer_info(&self) -> String {
2954        let mut text = String::from("Render Layer Info:\n");
2955        for ([name, expose_type], [min_position, max_position], ignore_render_layer) in
2956            &self.render_layer
2957        {
2958            text += &format!(
2959                "\nName: {:?}\nType: {:?}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
2960                name, expose_type, min_position, max_position, ignore_render_layer
2961            );
2962        }
2963        text
2964    }
2965
2966    /// 打印渲染队列。
2967    pub fn render_list_info(&self) -> String {
2968        let mut text = String::from("Render List Info:\n");
2969        for [name, expose_type] in &self.render_list {
2970            text += &format!("\nName: {:?}\nType: {:?}\n", name, expose_type);
2971        }
2972        text
2973    }
2974
2975    /// 更新渲染队列。
2976    pub fn update_render_list(&mut self) {
2977        if self.render_list.is_empty() {
2978            for info in &self.active_list {
2979                if self.basic_front_resource_list.contains(&info[1]) {
2980                    self.render_list.push([info[0].clone(), info[1].clone()]);
2981                };
2982            }
2983        } else {
2984            let mut count = 0;
2985            for render_resource in &self.render_list.clone() {
2986                if !self.active_list.contains(render_resource) {
2987                    self.render_list.remove(count);
2988                } else {
2989                    count += 1;
2990                };
2991            }
2992            let mut insert_index = 0;
2993            for info in &self.active_list {
2994                if self.basic_front_resource_list.contains(&info[1]) {
2995                    if !self.render_list.contains(info) {
2996                        self.render_list
2997                            .insert(insert_index, [info[0].clone(), info[1].clone()]);
2998                    } else {
2999                        insert_index += 1;
3000                    }
3001                };
3002            }
3003        };
3004    }
3005
3006    /// 请求在渲染队列中插队。
3007    pub fn request_jump_render_list(
3008        &mut self,
3009        requester: [&str; 2],
3010    ) -> Result<(), RustConstructorError> {
3011        if let Some(index) = self
3012            .render_list
3013            .iter()
3014            .position(|x| x[0] == requester[0] && x[1] == requester[1])
3015        {
3016            self.render_list.remove(index);
3017            self.render_list
3018                .push([requester[0].to_string(), requester[1].to_string()]);
3019            Ok(())
3020        } else {
3021            Err(RustConstructorError {
3022                error_id: "RenderResourceNotFound".to_string(),
3023                description: format!(
3024                    "Render resource \"{}({})\" not found.",
3025                    requester[0], requester[1]
3026                ),
3027            })
3028        }
3029    }
3030
3031    /// 根据活跃资源更新渲染层级列表。
3032    pub fn update_render_layer(&mut self) {
3033        self.render_layer.clear();
3034        for info in &self.render_list {
3035            if let Some(index) = self
3036                .rust_constructor_resource
3037                .iter()
3038                .position(|x| x.id.name == info[0] && x.id.discern_type == info[1])
3039            {
3040                let basic_front_resource: Box<dyn BasicFrontResource> = match &*info[1] {
3041                    "rust_constructor::Image" => Box::new(
3042                        self.rust_constructor_resource[index]
3043                            .content
3044                            .as_any()
3045                            .downcast_ref::<Image>()
3046                            .unwrap()
3047                            .clone(),
3048                    ),
3049                    "rust_constructor::Text" => Box::new(
3050                        self.rust_constructor_resource[index]
3051                            .content
3052                            .as_any()
3053                            .downcast_ref::<Text>()
3054                            .unwrap()
3055                            .clone(),
3056                    ),
3057                    "rust_constructor::CustomRect" => Box::new(
3058                        self.rust_constructor_resource[index]
3059                            .content
3060                            .as_any()
3061                            .downcast_ref::<CustomRect>()
3062                            .unwrap()
3063                            .clone(),
3064                    ),
3065                    _ => {
3066                        unreachable!()
3067                    }
3068                };
3069                if let Some(display_info) = basic_front_resource.display_display_info() {
3070                    self.render_layer.push((
3071                        info.clone(),
3072                        [
3073                            basic_front_resource.display_position_size_config().position,
3074                            [
3075                                basic_front_resource.display_position_size_config().position[0]
3076                                    + basic_front_resource.display_position_size_config().size[0],
3077                                basic_front_resource.display_position_size_config().position[1]
3078                                    + basic_front_resource.display_position_size_config().size[1],
3079                            ],
3080                        ],
3081                        display_info.ignore_render_layer,
3082                    ));
3083                };
3084            };
3085        }
3086    }
3087
3088    /// 绘制渲染层。
3089    pub fn display_render_layer(
3090        &self,
3091        ui: &mut Ui,
3092        render_config: &RenderConfig,
3093        ignore_render_config: &RenderConfig,
3094    ) {
3095        for (_, point, ignore_render_layer) in &self.render_layer {
3096            match if *ignore_render_layer {
3097                ignore_render_config
3098            } else {
3099                render_config
3100            } {
3101                RenderConfig::Rect(
3102                    corner_radius,
3103                    fill_color,
3104                    border_color,
3105                    border_width,
3106                    border_kind,
3107                ) => {
3108                    let rect = Rect::from_min_max(point[0].into(), point[1].into());
3109                    ui.painter().rect(
3110                        rect,
3111                        CornerRadius {
3112                            nw: corner_radius[0],
3113                            ne: corner_radius[1],
3114                            sw: corner_radius[2],
3115                            se: corner_radius[3],
3116                        },
3117                        Color32::from_rgba_unmultiplied(
3118                            fill_color[0],
3119                            fill_color[1],
3120                            fill_color[2],
3121                            fill_color[3],
3122                        ),
3123                        Stroke::new(
3124                            *border_width,
3125                            Color32::from_rgba_unmultiplied(
3126                                border_color[0],
3127                                border_color[1],
3128                                border_color[2],
3129                                border_color[3],
3130                            ),
3131                        ),
3132                        match *border_kind {
3133                            BorderKind::Inside => StrokeKind::Inside,
3134                            BorderKind::Middle => StrokeKind::Middle,
3135                            BorderKind::Outside => StrokeKind::Outside,
3136                        },
3137                    );
3138                }
3139                RenderConfig::Line(width, color) => {
3140                    ui.painter().line_segment(
3141                        [point[0].into(), point[1].into()],
3142                        Stroke::new(
3143                            *width,
3144                            Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
3145                        ),
3146                    );
3147                }
3148            };
3149        }
3150    }
3151
3152    /// 通过名称和类型在渲染列表中查找资源。
3153    pub fn get_render_layer_resource(&self, name: &str, discern_type: &str) -> Option<usize> {
3154        self.render_layer
3155            .iter()
3156            .position(|x| x.0[0] == name && x.0[1] == discern_type)
3157    }
3158
3159    /// 检查资源是否获取鼠标焦点。
3160    pub fn resource_get_focus(&self, index: usize, mouse_pos: [f32; 2]) -> bool {
3161        for i in index + 1..self.render_layer.len() {
3162            let point = self.render_layer[i].1;
3163            if mouse_pos[0] > point[0][0]
3164                && mouse_pos[1] > point[0][1]
3165                && mouse_pos[0] < point[1][0]
3166                && mouse_pos[1] < point[1][1]
3167                && !self.render_layer[i].2
3168            {
3169                return false;
3170            };
3171        }
3172        true
3173    }
3174
3175    /// 标记活跃资源。
3176    pub fn add_active_resource(
3177        &mut self,
3178        name: &str,
3179        discern_type: &str,
3180    ) -> Result<(), RustConstructorError> {
3181        let is_placeholder = name == Self::PLACEHOLDER[0] && discern_type == Self::PLACEHOLDER[1];
3182        if self.check_resource_exists(name, discern_type).is_some() || is_placeholder {
3183            if let Some(index) = self
3184                .active_list
3185                .iter()
3186                .position(|x| x[0] == Self::PLACEHOLDER[0] && x[1] == Self::PLACEHOLDER[1])
3187                && !is_placeholder
3188            {
3189                self.active_list.remove(index);
3190                self.active_list
3191                    .insert(index, [name.to_string(), discern_type.to_string()]);
3192            } else {
3193                self.active_list
3194                    .push([name.to_string(), discern_type.to_string()]);
3195            };
3196            Ok(())
3197        } else {
3198            Err(RustConstructorError {
3199                error_id: "ResourceNotFound".to_string(),
3200                description: format!("Resource \"{name}({discern_type})\" not found."),
3201            })
3202        }
3203    }
3204
3205    /// 添加资源。
3206    pub fn add_resource<T: RustConstructorResource + 'static>(
3207        &mut self,
3208        name: &str,
3209        mut resource: T,
3210    ) -> Result<(), RustConstructorError> {
3211        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3212            list.0
3213        } else {
3214            type_name_of_val(&resource)
3215        };
3216        if self.check_resource_exists(name, discern_type).is_some() {
3217            return Err(RustConstructorError {
3218                error_id: "ResourceNameRepetition".to_string(),
3219                description: format!("Resource \"{name}({discern_type})\" has already existed."),
3220            });
3221        };
3222        if name.is_empty() {
3223            return Err(RustConstructorError {
3224                error_id: "ResourceUntitled".to_string(),
3225                description: "All resources must have a valid name.".to_string(),
3226            });
3227        };
3228        match discern_type {
3229            "rust_constructor::PageData" => {}
3230            "rust_constructor::CustomRect" => {}
3231            "rust_constructor::Text" => {}
3232            "rust_constructor::Variable" => {}
3233            "rust_constructor::SplitTime" => {
3234                if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
3235                    split_time.time = [self.timer.now_time, self.timer.total_time];
3236                };
3237            }
3238            "rust_constructor::ImageTexture" => {
3239                if let Some(image_texture) = resource.as_any_mut().downcast_mut::<ImageTexture>() {
3240                    if let Ok(mut file) = File::open(&image_texture.cite_path) {
3241                        let mut buffer = Vec::new();
3242                        file.read_to_end(&mut buffer).unwrap();
3243                        let img_bytes = buffer;
3244                        let img = image::load_from_memory(&img_bytes).unwrap();
3245                        let color_data = match image_texture.flip {
3246                            [true, true] => img.fliph().flipv().into_rgba8(),
3247                            [true, false] => img.fliph().into_rgba8(),
3248                            [false, true] => img.flipv().into_rgba8(),
3249                            _ => img.into_rgba8(),
3250                        };
3251                        let (w, h) = (color_data.width(), color_data.height());
3252                        let raw_data: Vec<u8> = color_data.into_raw();
3253
3254                        let color_image =
3255                            ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3256                        let loaded_image_texture = image_texture.context.load_texture(
3257                            name,
3258                            color_image,
3259                            TextureOptions::LINEAR,
3260                        );
3261                        image_texture.texture =
3262                            Some(DebugTextureHandle::new(&loaded_image_texture));
3263                        image_texture.cite_path = image_texture.cite_path.to_string();
3264                    } else {
3265                        return Err(RustConstructorError {
3266                            error_id: "ImageLoadFailed".to_string(),
3267                            description: format!(
3268                                "Failed to load an image from the path \"{}\".",
3269                                image_texture.cite_path
3270                            ),
3271                        });
3272                    };
3273                };
3274            }
3275            "rust_constructor::Image" => {
3276                if let Some(image) = resource.as_any_mut().downcast_mut::<Image>() {
3277                    let image_texture = self.get_resource::<ImageTexture>(
3278                        &image.cite_texture,
3279                        "rust_constructor::ImageTexture",
3280                    )?;
3281                    image.texture = image_texture.texture.clone();
3282                    image.last_frame_cite_texture = image.cite_texture.clone();
3283                };
3284            }
3285            "rust_constructor::Font" => {
3286                if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
3287                    let mut fonts = FontDefinitions::default();
3288                    if let Ok(font_read_data) = read(&font.path) {
3289                        let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
3290                        fonts.font_data.insert(
3291                            name.to_owned(),
3292                            Arc::new(FontData::from_owned(
3293                                Arc::try_unwrap(font_data).ok().unwrap(),
3294                            )),
3295                        );
3296
3297                        // 将字体添加到字体列表中
3298                        fonts
3299                            .families
3300                            .entry(FontFamily::Proportional)
3301                            .or_default()
3302                            .insert(0, name.to_owned());
3303
3304                        fonts
3305                            .families
3306                            .entry(FontFamily::Monospace)
3307                            .or_default()
3308                            .insert(0, name.to_owned());
3309
3310                        font.font_definitions = fonts;
3311                    } else {
3312                        return Err(RustConstructorError {
3313                            error_id: "FontLoadFailed".to_string(),
3314                            description: format!(
3315                                "Failed to load a font from the path \"{}\".",
3316                                font.path
3317                            ),
3318                        });
3319                    }
3320                };
3321            }
3322            _ => {
3323                let mut tag = HashMap::new();
3324                tag.insert("name", name);
3325                tag.insert("discern_type", discern_type);
3326                self.add_event("rust_constructor::001", tag, false);
3327            }
3328        };
3329        self.rust_constructor_resource
3330            .push(RustConstructorResourceBox::new(
3331                name,
3332                discern_type,
3333                Box::new(resource),
3334            ));
3335        Ok(())
3336    }
3337
3338    /// 移除资源。此方法非常危险!务必确保资源一定不再使用后删除。
3339    pub fn drop_resource(
3340        &mut self,
3341        name: &str,
3342        discern_type: &str,
3343    ) -> Result<(), RustConstructorError> {
3344        if let Some(index) = self.check_resource_exists(name, discern_type) {
3345            self.rust_constructor_resource.remove(index);
3346            if let Some(index) = self
3347                .active_list
3348                .iter()
3349                .position(|x| x[0] == name && x[1] == discern_type)
3350            {
3351                self.active_list.remove(index);
3352            };
3353            if let Some(index) = self
3354                .render_layer
3355                .iter()
3356                .position(|x| x.0[0] == name && x.0[1] == discern_type)
3357            {
3358                self.render_layer.remove(index);
3359            };
3360            let mut tag = HashMap::new();
3361            tag.insert("name", name);
3362            tag.insert("discern_type", discern_type);
3363            self.add_event("rust_constructor::002", tag, false);
3364            Ok(())
3365        } else {
3366            Err(RustConstructorError {
3367                error_id: "ResourceNotFound".to_string(),
3368                description: format!("Resource \"{name}({discern_type})\" not found."),
3369            })
3370        }
3371    }
3372
3373    /// 从列表中替换资源。
3374    pub fn replace_resource<T>(
3375        &mut self,
3376        name: &str,
3377        resource: T,
3378    ) -> Result<(), RustConstructorError>
3379    where
3380        T: RustConstructorResource + 'static,
3381    {
3382        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3383            list.0
3384        } else {
3385            type_name_of_val(&resource)
3386        };
3387        if let Some(index) = self.check_resource_exists(name, discern_type) {
3388            self.rust_constructor_resource[index] =
3389                RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
3390            Ok(())
3391        } else {
3392            Err(RustConstructorError {
3393                error_id: "ResourceNotFound".to_string(),
3394                description: format!("Resource \"{name}({discern_type})\" not found."),
3395            })
3396        }
3397    }
3398
3399    /// 从列表中获取不可变资源。
3400    pub fn get_resource<T>(
3401        &self,
3402        name: &str,
3403        discern_type: &str,
3404    ) -> Result<&T, RustConstructorError>
3405    where
3406        T: RustConstructorResource + 'static,
3407    {
3408        if let Some(index) = self.check_resource_exists(name, discern_type) {
3409            if let Some(resource) = self.rust_constructor_resource[index]
3410                .content
3411                .as_any()
3412                .downcast_ref::<T>()
3413            {
3414                Ok(resource)
3415            } else {
3416                Err(RustConstructorError {
3417                    error_id: "ResourceGenericMismatch".to_string(),
3418                    description: format!(
3419                        "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3420                    ),
3421                })
3422            }
3423        } else {
3424            Err(RustConstructorError {
3425                error_id: "ResourceNotFound".to_string(),
3426                description: format!("Resource \"{name}({discern_type})\" not found."),
3427            })
3428        }
3429    }
3430
3431    /// 从列表中获取可变资源。
3432    pub fn get_resource_mut<T>(
3433        &mut self,
3434        name: &str,
3435        discern_type: &str,
3436    ) -> Result<&mut T, RustConstructorError>
3437    where
3438        T: RustConstructorResource + 'static,
3439    {
3440        if let Some(index) = self.check_resource_exists(name, discern_type) {
3441            if let Some(resource) = self.rust_constructor_resource[index]
3442                .content
3443                .as_any_mut()
3444                .downcast_mut::<T>()
3445            {
3446                Ok(resource)
3447            } else {
3448                Err(RustConstructorError {
3449                    error_id: "ResourceGenericMismatch".to_string(),
3450                    description: format!(
3451                        "The generic type of the resource \"{name}({discern_type})\" is mismatched."
3452                    ),
3453                })
3454            }
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 check_resource_exists(&self, name: &str, discern_type: &str) -> Option<usize> {
3465        self.rust_constructor_resource
3466            .iter()
3467            .position(|x| x.id.name == name && x.id.discern_type == discern_type)
3468    }
3469
3470    /// 快速放置。
3471    pub fn quick_place<T: RustConstructorResource + 'static>(
3472        &mut self,
3473        name: &str,
3474        resource: T,
3475        ui: &mut Ui,
3476        ctx: &Context,
3477        need_place_holder: NeedPlaceholder,
3478    ) -> Result<(), RustConstructorError> {
3479        let discern_type = if let Some(list) = type_name_of_val(&resource).split_once("<") {
3480            list.0
3481        } else {
3482            type_name_of_val(&resource)
3483        };
3484        if self.check_resource_exists(name, discern_type).is_none() {
3485            self.add_resource(name, resource)
3486        } else {
3487            self.use_resource(name, discern_type, ui, ctx, need_place_holder)
3488        }
3489    }
3490
3491    /// 调用资源。
3492    pub fn use_resource(
3493        &mut self,
3494        name: &str,
3495        discern_type: &str,
3496        ui: &mut Ui,
3497        ctx: &Context,
3498        need_place_holder: NeedPlaceholder,
3499    ) -> Result<(), RustConstructorError> {
3500        if self.check_resource_exists(name, discern_type).is_some() {
3501            match discern_type {
3502                "rust_constructor::CustomRect"
3503                | "rust_constructor::Text"
3504                | "rust_constructor::Image" => {
3505                    self.add_active_resource(name, discern_type)?;
3506                }
3507                "rust_constructor::PageData" => {
3508                    // 更新帧数
3509                    self.update_frame_stats();
3510                    // 更新渲染队列。
3511                    self.update_render_list();
3512                    // 绘制渲染队列中的资源。
3513                    for i in 0..self.render_list.len() {
3514                        self.draw_resource_by_index(ui, ctx, i)?;
3515                    }
3516                    // 更新渲染列表。
3517                    self.update_render_layer();
3518                    // 更新事件列表。
3519                    self.update_event_list();
3520                    // 更新资源活跃状态。
3521                    self.active_list.clear();
3522                    // 更新资源启用状态。
3523                    for rcr in &mut self.rust_constructor_resource {
3524                        if let Some(display_info) = &mut rcr.content.display_display_info() {
3525                            rcr.content.modify_display_info(DisplayInfo {
3526                                enable: true,
3527                                hidden: display_info.hidden,
3528                                ignore_render_layer: display_info.ignore_render_layer,
3529                            });
3530                        };
3531                    }
3532                    // 更新计时器
3533                    self.update_timer();
3534                    let current_page = &self.current_page.clone();
3535                    let page_data =
3536                        self.get_resource::<PageData>(current_page, "rust_constructor::PageData")?;
3537                    if page_data.forced_update {
3538                        ctx.request_repaint();
3539                    };
3540                }
3541                _ => {
3542                    let mut tag = HashMap::new();
3543                    tag.insert("name", name);
3544                    tag.insert("discern_type", discern_type);
3545                    self.add_event("rust_constructor::003", tag, true);
3546                }
3547            }
3548            if let NeedPlaceholder::Yes(amount) = need_place_holder {
3549                for _ in 0..amount {
3550                    self.add_active_resource(Self::PLACEHOLDER[0], Self::PLACEHOLDER[1])?;
3551                }
3552            };
3553            Ok(())
3554        } else {
3555            Err(RustConstructorError {
3556                error_id: "ResourceNotFound".to_string(),
3557                description: format!("Resource \"{name}({discern_type})\" not found."),
3558            })
3559        }
3560    }
3561
3562    /// 切换页面。
3563    pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
3564        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3565        page_data.enter_page_updated = false;
3566        self.timer.start_time = self.timer.total_time;
3567        self.current_page = name.to_string();
3568        self.update_timer();
3569        Ok(())
3570    }
3571
3572    /// 输出字体资源。
3573    pub fn get_font(&mut self, name: &str) -> Result<FontDefinitions, RustConstructorError> {
3574        let font = self.get_resource::<Font>(name, "rust_constructor::Font")?;
3575        Ok(font.font_definitions.clone())
3576    }
3577
3578    /// 将所有已添加到RC的字体资源添加到egui中。
3579    pub fn register_all_fonts(&mut self, ctx: &Context) {
3580        let mut font_definitions_amount = FontDefinitions::default();
3581        let mut fonts = Vec::new();
3582        for i in 0..self.rust_constructor_resource.len() {
3583            if let Some(font) = self.rust_constructor_resource[i]
3584                .content
3585                .as_any()
3586                .downcast_ref::<Font>()
3587            {
3588                fonts.push((
3589                    self.rust_constructor_resource[i].id.name.clone(),
3590                    font.font_definitions.clone(),
3591                ));
3592            };
3593        }
3594        for i in &fonts {
3595            // 从 font_def 中提取对应字体的 Arc<FontData>
3596            if let Some(font_data) = i.1.font_data.get(&i.0) {
3597                font_definitions_amount
3598                    .font_data
3599                    .insert(i.0.clone(), Arc::clone(font_data));
3600                font_definitions_amount
3601                    .families
3602                    .entry(FontFamily::Name(i.0.clone().into()))
3603                    .or_default()
3604                    .push(i.0.clone());
3605            };
3606
3607            // 将字体添加到字体列表中
3608            font_definitions_amount
3609                .families
3610                .entry(FontFamily::Proportional)
3611                .or_default()
3612                .insert(0, i.0.to_owned());
3613
3614            font_definitions_amount
3615                .families
3616                .entry(FontFamily::Monospace)
3617                .or_default()
3618                .insert(0, i.0.to_owned());
3619        }
3620        ctx.set_fonts(font_definitions_amount);
3621    }
3622
3623    /// 处理最基本的位置计算。
3624    pub fn position_size_processor(
3625        &self,
3626        position_size_config: PositionSizeConfig,
3627        ctx: &Context,
3628    ) -> [[f32; 2]; 2] {
3629        let mut position = [0_f32, 0_f32];
3630        let mut size = [0_f32, 0_f32];
3631        size[0] = match position_size_config.x_size_grid[0] {
3632            0_f32 => position_size_config.origin_size[0],
3633            _ => {
3634                (ctx.available_rect().width() / position_size_config.x_size_grid[1]
3635                    * position_size_config.x_size_grid[0])
3636                    + position_size_config.origin_size[0]
3637            }
3638        };
3639        size[1] = match position_size_config.y_size_grid[0] {
3640            0_f32 => position_size_config.origin_size[1],
3641            _ => {
3642                (ctx.available_rect().height() / position_size_config.y_size_grid[1]
3643                    * position_size_config.y_size_grid[0])
3644                    + position_size_config.origin_size[1]
3645            }
3646        };
3647        position[0] = match position_size_config.x_location_grid[1] {
3648            0_f32 => position_size_config.origin_position[0],
3649            _ => {
3650                (ctx.available_rect().width() / position_size_config.x_location_grid[1]
3651                    * position_size_config.x_location_grid[0])
3652                    + position_size_config.origin_position[0]
3653            }
3654        };
3655        position[1] = match position_size_config.y_location_grid[1] {
3656            0_f32 => position_size_config.origin_position[1],
3657            _ => {
3658                (ctx.available_rect().height() / position_size_config.y_location_grid[1]
3659                    * position_size_config.y_location_grid[0])
3660                    + position_size_config.origin_position[1]
3661            }
3662        };
3663        match position_size_config.display_method.0 {
3664            HorizontalAlign::Left => {}
3665            HorizontalAlign::Center => position[0] -= size[0] / 2.0,
3666            HorizontalAlign::Right => position[0] -= size[0],
3667        };
3668        match position_size_config.display_method.1 {
3669            VerticalAlign::Top => {}
3670            VerticalAlign::Center => position[1] -= size[1] / 2.0,
3671            VerticalAlign::Bottom => position[1] -= size[1],
3672        };
3673        position[0] += position_size_config.offset[0];
3674        position[1] += position_size_config.offset[1];
3675        [position, size]
3676    }
3677
3678    /// 检查页面是否已完成首次加载。
3679    pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3680        let page_data = self
3681            .get_resource::<PageData>(name, "rust_constructor::PageData")?
3682            .clone();
3683        if !page_data.change_page_updated {
3684            self.new_page_update(name)?;
3685        };
3686        Ok(page_data.change_page_updated)
3687    }
3688
3689    /// 检查页面是否已完成加载。
3690    pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
3691        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3692        page_data.enter_page_updated = true;
3693        Ok(page_data.enter_page_updated)
3694    }
3695
3696    /// 进入新页面时的更新。
3697    pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
3698        let page_data = self.get_resource_mut::<PageData>(name, "rust_constructor::PageData")?;
3699        page_data.change_page_updated = true;
3700        self.timer.start_time = self.timer.total_time;
3701        self.update_timer();
3702        Ok(())
3703    }
3704
3705    /// 更新帧数。
3706    pub fn update_frame_stats(&mut self) {
3707        let current_time = self.timer.total_time;
3708        if let Some(last) = self.last_frame_time {
3709            let delta = current_time - last;
3710            self.frame_times.push(delta);
3711            const MAX_SAMPLES: usize = 120;
3712            if self.frame_times.len() > MAX_SAMPLES {
3713                let remove_count = self.frame_times.len() - MAX_SAMPLES;
3714                self.frame_times.drain(0..remove_count);
3715            }
3716        }
3717        self.last_frame_time = Some(current_time);
3718    }
3719
3720    /// 更新帧数显示。
3721    pub fn current_fps(&self) -> f32 {
3722        if self.frame_times.is_empty() {
3723            0.0
3724        } else {
3725            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
3726        }
3727    }
3728
3729    /// 重置分段时间。
3730    pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
3731        let new_time = [self.timer.now_time, self.timer.total_time];
3732        let split_time = self.get_resource_mut::<SplitTime>(name, "rust_constructor::SplitTime")?;
3733        split_time.time = new_time;
3734        Ok(())
3735    }
3736
3737    /// 输出分段时间。
3738    pub fn get_split_time(&mut self, name: &str) -> Result<[f32; 2], RustConstructorError> {
3739        let split_time = self.get_resource::<SplitTime>(name, "rust_constructor::SplitTime")?;
3740        Ok(split_time.time)
3741    }
3742
3743    /// 更新计时器。
3744    pub fn update_timer(&mut self) {
3745        let elapsed = self.timer.timer.elapsed();
3746        let seconds = elapsed.as_secs();
3747        let milliseconds = elapsed.subsec_millis();
3748        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
3749        self.timer.now_time = self.timer.total_time - self.timer.start_time
3750    }
3751
3752    /// 修改变量资源。
3753    pub fn modify_variable<T: Debug + 'static>(
3754        &mut self,
3755        name: &str,
3756        value: Option<T>,
3757    ) -> Result<(), RustConstructorError> {
3758        let variable = self.get_resource_mut::<Variable<T>>(name, "rust_constructor::Variable")?;
3759        variable.value = value;
3760        Ok(())
3761    }
3762
3763    /// 取出变量。
3764    pub fn get_variable<T: Debug + Clone + 'static>(
3765        &mut self,
3766        name: &str,
3767    ) -> Result<Option<T>, RustConstructorError> {
3768        if let Ok(variable) = self.get_resource::<Variable<T>>(name, "rust_constructor::Variable") {
3769            Ok(variable.value.clone())
3770        } else if self
3771            .check_resource_exists(name, "rust_constructor::Variable")
3772            .is_none()
3773        {
3774            Err(RustConstructorError {
3775                error_id: "ResourceNotFound".to_string(),
3776                description: format!(
3777                    "Resource \"{name}(rust_constructor::Variable<T>)\" not found."
3778                ),
3779            })
3780        } else {
3781            Err(RustConstructorError {
3782                error_id: "ResourceGenericMismatch".to_string(),
3783                description: format!(
3784                    "The generic type of the resource \"{name}(rust_constructor::Variable<T>)\" is mismatched."
3785                ),
3786            })
3787        }
3788    }
3789
3790    /// 输出图片纹理。
3791    pub fn get_image_texture(
3792        &mut self,
3793        name: &str,
3794    ) -> Result<Option<DebugTextureHandle>, RustConstructorError> {
3795        let image_texture =
3796            self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3797        Ok(image_texture.texture.clone())
3798    }
3799
3800    /// 重置图片纹理。
3801    pub fn reset_image_texture(
3802        &mut self,
3803        name: &str,
3804        path: &str,
3805        flip: [bool; 2],
3806        ctx: &Context,
3807    ) -> Result<(), RustConstructorError> {
3808        let image_texture =
3809            self.get_resource_mut::<ImageTexture>(name, "rust_constructor::ImageTexture")?;
3810        if let Ok(mut file) = File::open(path) {
3811            let mut buffer = Vec::new();
3812            file.read_to_end(&mut buffer).unwrap();
3813            let img_bytes = buffer;
3814            let img = image::load_from_memory(&img_bytes).unwrap();
3815            let color_data = match flip {
3816                [true, true] => img.fliph().flipv().into_rgba8(),
3817                [true, false] => img.fliph().into_rgba8(),
3818                [false, true] => img.flipv().into_rgba8(),
3819                _ => img.into_rgba8(),
3820            };
3821            let (w, h) = (color_data.width(), color_data.height());
3822            let raw_data: Vec<u8> = color_data.into_raw();
3823
3824            let color_image =
3825                ColorImage::from_rgba_unmultiplied([w as usize, h as usize], &raw_data);
3826            let texture = ctx.load_texture(name, color_image, TextureOptions::LINEAR);
3827            image_texture.texture = Some(DebugTextureHandle::new(&texture));
3828            image_texture.cite_path = path.to_string();
3829        } else {
3830            return Err(RustConstructorError {
3831                error_id: "ImageLoadFailed".to_string(),
3832                description: format!(
3833                    "Failed to load an image from the path \"{}\".",
3834                    image_texture.cite_path
3835                ),
3836            });
3837        }
3838        Ok(())
3839    }
3840}