Skip to main content

rust_constructor/
app.rs

1//! Main application struct containing all GUI resources and state management.
2//!
3//! 程序主体,包含所有GUI资源和状态管理。
4use crate::{
5    BasicFrontResource, BorderKind, DisplayInfo, HorizontalAlign, ListInfoDescribeMethod,
6    PositionSizeConfig, RenderConfig, RequestMethod, RequestType, RustConstructorError,
7    RustConstructorId, RustConstructorResource, RustConstructorResourceBox, Timer, VerticalAlign,
8    advance_front::{
9        Background, BackgroundType, ClickAim, CustomPanelLayout, PanelLocation, PanelMargin,
10        PanelStorage, ResourcePanel, ScrollBarDisplayMethod, ScrollLengthMethod, Switch,
11        SwitchData,
12    },
13    background::{PageData, SplitTime, Variable},
14    basic_front::{
15        CustomRect, DebugTextureHandle, HyperlinkSelectMethod, Image, ImageLoadMethod, Text,
16    },
17    downcast_resource, downcast_resource_mut, get_tag, position_size_processor, type_processor,
18};
19use eframe::{
20    egui::{
21        Color32, ColorImage, Context, CornerRadius, CursorIcon, FontData, FontDefinitions,
22        FontFamily, FontId, Galley, Id, ImageSource, Key, OpenUrl, Pos2, Sense, StrokeKind, Ui,
23        Vec2, text::CCursor,
24    },
25    emath::Rect,
26    epaint::{Stroke, textures::TextureOptions},
27};
28use std::{
29    char,
30    cmp::Ordering,
31    fmt::Debug,
32    fs::{File, read},
33    io::Read,
34    sync::Arc,
35    vec::Vec,
36};
37
38/// This struct serves as the central hub for the Rust Constructor framework.
39///
40/// 该结构体是Rust Constructor框架的中心枢纽。
41#[derive(Debug)]
42pub struct App {
43    /// Collection of all Rust Constructor resources with type-erased storage.
44    ///
45    /// 所有Rust Constructor资源的集合,使用类型擦除存储。
46    pub rust_constructor_resource: Vec<RustConstructorResourceBox>,
47
48    /// Refresh rate for resource updates in milliseconds.
49    ///
50    /// 资源更新的刷新率(毫秒)。
51    pub tick_interval: u128,
52
53    /// Name of the current active page.
54    ///
55    /// 当前活动页面的名称。
56    pub current_page: String,
57
58    /// Timer for tracking application runtime and page durations.
59    ///
60    /// 用于跟踪应用程序运行时间和页面持续时间的计时器。
61    pub timer: Timer,
62
63    /// Record of recent frame times for performance monitoring.
64    ///
65    /// 最近帧时间的记录,用于性能监控。
66    pub frame_times: Vec<u128>,
67
68    /// The time for rendering the previous frame in milliseconds.
69    ///
70    /// 渲染上一帧的时间(毫秒)。
71    pub last_frame_time: Option<u128>,
72
73    /// List of resource IDs that are basic front resources.
74    ///
75    /// 基本前端资源的资源ID列表。
76    ///
77    /// This list should not be modified manually.
78    ///
79    /// 此列表不应手动修改。
80    pub basic_front_resource_list: Vec<String>,
81
82    /// Rendering layer information: (resource_id, [position, size], ignore_render_layer).
83    ///
84    /// 渲染层级信息:(资源ID, [位置, 尺寸], 是否忽略渲染层级)。
85    pub render_layer: Vec<(RustConstructorId, [[f32; 2]; 2], bool)>,
86
87    /// List of currently active resources.
88    ///
89    /// 当前活动的资源列表。
90    pub active_list: Vec<(RustConstructorId, Option<RustConstructorId>)>,
91
92    /// Queue of resources to be rendered in the current frame.
93    ///
94    /// 要在当前帧中呈现的资源队列。
95    pub render_list: Vec<(RustConstructorId, Option<RustConstructorId>)>,
96
97    /// List the loaded fonts.
98    ///
99    /// 列出已加载的字体。
100    pub loaded_fonts: Vec<[String; 2]>,
101
102    /// List the fonts that are currently loading.
103    ///
104    /// 列出正在加载的字体。
105    pub loading_fonts: Vec<[String; 2]>,
106}
107
108impl Default for App {
109    fn default() -> Self {
110        App {
111            rust_constructor_resource: Vec::new(),
112            tick_interval: 50,
113            current_page: String::new(),
114            timer: Timer::default(),
115            frame_times: Vec::new(),
116            last_frame_time: None,
117            basic_front_resource_list: vec![
118                String::from("Image"),
119                String::from("Text"),
120                String::from("CustomRect"),
121            ],
122            render_layer: Vec::new(),
123            active_list: Vec::new(),
124            render_list: Vec::new(),
125            loaded_fonts: Vec::new(),
126            loading_fonts: Vec::new(),
127        }
128    }
129}
130
131impl App {
132    #[inline]
133    pub fn tick_interval(mut self, tick_interval: u128) -> Self {
134        self.tick_interval = tick_interval;
135        self
136    }
137
138    #[inline]
139    pub fn current_page(mut self, current_page: &str) -> Self {
140        self.current_page = current_page.to_string();
141        self
142    }
143
144    /// Draws all resources in the rendering queue at once, discarding all return values.
145    ///
146    /// 一次性绘制渲染队列中的所有资源,会丢弃所有返回值。
147    ///
148    /// This method iterates through all resources in the render list and draws them.
149    /// It's not recommended for production use due to error handling limitations.
150    ///
151    /// 此方法遍历渲染列表中的所有资源并绘制它们。由于错误处理限制,不建议在生产环境中使用。
152    ///
153    /// # Arguments
154    ///
155    /// * `ui` - The UI context for drawing
156    /// * `ctx` - The rendering context
157    ///
158    /// # 参数
159    ///
160    /// * `ui` - 用于绘制的UI上下文
161    /// * `ctx` - 渲染上下文
162    pub fn draw_resources(&mut self, ui: &mut Ui, ctx: &Context) {
163        for i in 0..self.render_list.len() {
164            let _ = self.draw_resource_by_index(ui, ctx, i);
165        }
166    }
167
168    /// Draws a specific resource by its index in the rendering queue.
169    ///
170    /// 根据资源在渲染队列中的索引值绘制特定资源。
171    ///
172    /// This method handles the rendering of different resource types including:
173    /// - Images with various loading methods and transformations
174    /// - Text with formatting, selection, and hyperlink support
175    /// - Custom rectangles with borders and styling
176    ///
177    /// 此方法处理不同类型资源的渲染,包括:
178    /// - 具有各种加载方法和变换的图像
179    /// - 具有格式设置、选择和超链接支持的文本
180    /// - 具有边框和样式的自定义矩形
181    ///
182    /// # Arguments
183    ///
184    /// * `ui` - The UI context for drawing
185    /// * `ctx` - The rendering context
186    /// * `index` - The index of the resource in the render list
187    ///
188    /// # Returns
189    ///
190    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource
191    /// cannot be found or drawn.
192    ///
193    /// # 参数
194    ///
195    /// * `ui` - 用于绘制的UI上下文
196    /// * `ctx` - 渲染上下文
197    /// * `index` - 资源在渲染列表中的索引
198    ///
199    /// # 返回值
200    ///
201    /// 成功时返回`Ok(())`,如果资源无法找到或绘制则返回`Err(RustConstructorError)`。
202    pub fn draw_resource_by_index(
203        &mut self,
204        ui: &mut Ui,
205        ctx: &Context,
206        index: usize,
207    ) -> Result<(), RustConstructorError> {
208        if let Some(render_resource) = self.render_list.clone().get(index) {
209            match &*render_resource.0.discern_type {
210                "Image" => {
211                    let image = self.get_resource::<Image>(&RustConstructorId {
212                        name: render_resource.0.name.clone(),
213                        discern_type: "Image".to_string(),
214                    })?;
215                    if image.display_info.enable {
216                        let mut image = image.clone();
217                        match image.image_load_method {
218                            ImageLoadMethod::ByPath((ref path, flip)) => {
219                                if *path != image.last_frame_path {
220                                    if let Ok(mut file) = File::open(path) {
221                                        let mut buffer = Vec::new();
222                                        file.read_to_end(&mut buffer).unwrap();
223                                        let img_bytes = buffer;
224                                        let img = image::load_from_memory(&img_bytes).unwrap();
225                                        let color_data = match flip {
226                                            [true, true] => img.fliph().flipv().into_rgba8(),
227                                            [true, false] => img.fliph().into_rgba8(),
228                                            [false, true] => img.flipv().into_rgba8(),
229                                            _ => img.into_rgba8(),
230                                        };
231                                        let (w, h) = (color_data.width(), color_data.height());
232                                        let raw_data: Vec<u8> = color_data.into_raw();
233
234                                        let color_image = ColorImage::from_rgba_unmultiplied(
235                                            [w as usize, h as usize],
236                                            &raw_data,
237                                        );
238                                        let loaded_image_texture = ctx.load_texture(
239                                            &render_resource.0.name,
240                                            color_image,
241                                            TextureOptions::LINEAR,
242                                        );
243                                        image.texture =
244                                            Some(DebugTextureHandle::new(&loaded_image_texture));
245                                    } else {
246                                        return Err(RustConstructorError {
247                                            error_id: "ImageLoadFailed".to_string(),
248                                            description: format!(
249                                                "Failed to load an image from the path '{path}'.",
250                                            ),
251                                        });
252                                    };
253                                };
254                            }
255                            ImageLoadMethod::ByTexture(ref texture) => {
256                                image.texture = Some(texture.clone());
257                            }
258                        };
259                        [image.position, image.size] = position_size_processor(
260                            image.basic_front_resource_config.position_size_config,
261                            ctx,
262                        );
263                        if !image.display_info.hidden {
264                            if let Some(clip_rect) = image.basic_front_resource_config.clip_rect {
265                                let [min, size] = position_size_processor(clip_rect, ctx);
266                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
267                            };
268                            if let Some(texture) = &image.texture {
269                                let rect = Rect::from_min_size(
270                                    Pos2::new(image.position[0], image.position[1]),
271                                    Vec2::new(image.size[0], image.size[1]),
272                                );
273
274                                // 直接绘制图片
275                                eframe::egui::Image::new(ImageSource::Texture((&texture.0).into()))
276                                    .tint(Color32::from_rgba_unmultiplied(
277                                        image.overlay_color[0],
278                                        image.overlay_color[1],
279                                        image.overlay_color[2],
280                                        (image.alpha as f32 * image.overlay_alpha as f32 / 255_f32)
281                                            as u8,
282                                    ))
283                                    .bg_fill(Color32::from_rgba_unmultiplied(
284                                        image.background_color[0],
285                                        image.background_color[1],
286                                        image.background_color[2],
287                                        (image.alpha as f32 * image.background_alpha as f32
288                                            / 255_f32)
289                                            as u8,
290                                    ))
291                                    .rotate(
292                                        image.rotate_angle,
293                                        [
294                                            image.rotate_center[0] / image.size[0],
295                                            image.rotate_center[1] / image.size[1],
296                                        ]
297                                        .into(),
298                                    )
299                                    .paint_at(ui, rect)
300                            };
301                            if image.basic_front_resource_config.clip_rect.is_some() {
302                                ui.set_clip_rect(Rect::from_min_size(
303                                    [0_f32, 0_f32].into(),
304                                    [ctx.available_rect().width(), ctx.available_rect().height()]
305                                        .into(),
306                                ));
307                            };
308                        };
309                        match image.image_load_method {
310                            ImageLoadMethod::ByPath((ref path, _)) => {
311                                image.last_frame_path = path.clone()
312                            }
313                            ImageLoadMethod::ByTexture(_) => {}
314                        };
315                        self.replace_resource(&render_resource.0.name, image)?;
316                    };
317                }
318                "Text" => {
319                    let text = self.get_resource::<Text>(&RustConstructorId {
320                        name: render_resource.0.name.clone(),
321                        discern_type: "Text".to_string(),
322                    })?;
323                    if text.display_info.enable {
324                        let mut text = text.clone();
325                        [_, text.truncate_size] = position_size_processor(
326                            text.basic_front_resource_config.position_size_config,
327                            ctx,
328                        );
329                        let display_content = if text.content.is_empty()
330                            || text
331                                .basic_front_resource_config
332                                .position_size_config
333                                .origin_size
334                                .contains(&0_f32)
335                        {
336                            "".to_string()
337                        } else {
338                            let original_galley = ui.fonts_mut(|f| {
339                                f.layout(
340                                    text.content.to_string(),
341                                    FontId::proportional(text.font_size),
342                                    Color32::default(),
343                                    text.truncate_size[0],
344                                )
345                            });
346
347                            let mut truncated = text.content.to_string();
348                            let mut ellipsis = "";
349                            if original_galley.size().y > text.truncate_size[1] {
350                                // 如果超出,逐步缩短文本直到加上省略号后能放下
351                                ellipsis = "...";
352
353                                while !truncated.is_empty() {
354                                    let test_text = format!("{}{}", truncated, ellipsis);
355                                    let test_galley = ui.fonts_mut(|f| {
356                                        f.layout(
357                                            test_text,
358                                            FontId::proportional(text.font_size),
359                                            Color32::default(),
360                                            text.truncate_size[0],
361                                        )
362                                    });
363
364                                    if test_galley.size().y <= text.truncate_size[1] {
365                                        break;
366                                    }
367
368                                    // 移除最后一个字符
369                                    truncated.pop();
370                                }
371                            };
372                            format!("{}{}", truncated, ellipsis)
373                        };
374                        // 计算文本大小
375                        let galley: Arc<Galley> = ui.fonts_mut(|f| {
376                            f.layout(
377                                display_content.to_string(),
378                                if !text.font.is_empty() {
379                                    if self.loaded_fonts.iter().any(|x| x[0] == text.font) {
380                                        FontId::new(
381                                            text.font_size,
382                                            FontFamily::Name(text.font.clone().into()),
383                                        )
384                                    } else {
385                                        FontId::proportional(text.font_size)
386                                    }
387                                } else {
388                                    FontId::proportional(text.font_size)
389                                },
390                                Color32::from_rgba_unmultiplied(
391                                    text.color[0],
392                                    text.color[1],
393                                    text.color[2],
394                                    text.alpha,
395                                ),
396                                text.truncate_size[0],
397                            )
398                        });
399                        text.size = [
400                            if text.auto_fit[0] {
401                                galley.size().x
402                            } else {
403                                text.truncate_size[0]
404                            },
405                            if text.auto_fit[1] {
406                                galley.size().y
407                            } else {
408                                text.truncate_size[1]
409                            },
410                        ];
411                        text.actual_size = [galley.size().x, galley.size().y];
412                        [text.position, _] = position_size_processor(
413                            text.basic_front_resource_config
414                                .position_size_config
415                                .x_size_grid(0_f32, 0_f32)
416                                .y_size_grid(0_f32, 0_f32)
417                                .origin_size(text.size[0], text.size[1]),
418                            ctx,
419                        );
420                        // 查找超链接索引值
421                        if text.last_frame_content != display_content {
422                            text.hyperlink_index.clear();
423
424                            // 创建字节索引到字符索引的映射
425                            let byte_to_char_map: std::collections::HashMap<usize, usize> =
426                                display_content
427                                    .char_indices()
428                                    .enumerate()
429                                    .map(|(char_idx, (byte_idx, _))| (byte_idx, char_idx))
430                                    .collect();
431
432                            for (hyperlink_text, method) in &text.hyperlink_text {
433                                let matches: Vec<(usize, &str)> =
434                                    display_content.match_indices(hyperlink_text).collect();
435                                let text_char_count = hyperlink_text.chars().count();
436
437                                if let HyperlinkSelectMethod::All(url) = method {
438                                    for (byte_index, _) in matches {
439                                        if let Some(&start_char_index) =
440                                            byte_to_char_map.get(&byte_index)
441                                        {
442                                            text.hyperlink_index.push((
443                                                start_char_index,
444                                                start_char_index + text_char_count,
445                                                url.clone(),
446                                            ));
447                                        };
448                                    }
449                                } else if let HyperlinkSelectMethod::Segment(list) = method {
450                                    for (index, url) in list {
451                                        if *index >= matches.len() {
452                                            continue;
453                                        };
454                                        let (byte_index, _) = matches[*index];
455                                        if let Some(&start_char_index) =
456                                            byte_to_char_map.get(&byte_index)
457                                        {
458                                            text.hyperlink_index.push((
459                                                start_char_index,
460                                                start_char_index + text_char_count,
461                                                url.clone(),
462                                            ));
463                                        };
464                                    }
465                                };
466                            }
467                        };
468                        if !text.display_info.hidden {
469                            // 使用绝对定位放置文本
470                            let rect =
471                                Rect::from_min_size(text.position.into(), text.actual_size.into());
472                            // 绘制背景颜色
473                            ui.painter().rect_filled(
474                                rect,
475                                text.background_rounding,
476                                Color32::from_rgba_unmultiplied(
477                                    text.background_color[0],
478                                    text.background_color[1],
479                                    text.background_color[2],
480                                    text.background_alpha,
481                                ),
482                            );
483
484                            if let Some(clip_rect) = text.basic_front_resource_config.clip_rect {
485                                let [min, size] = position_size_processor(clip_rect, ctx);
486                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
487                            };
488
489                            // 绘制文本
490                            ui.painter().galley(
491                                text.position.into(),
492                                galley.clone(),
493                                Color32::from_rgba_unmultiplied(
494                                    text.color[0],
495                                    text.color[1],
496                                    text.color[2],
497                                    text.alpha,
498                                ),
499                            );
500
501                            // 绘制超链接
502                            for (start, end, _) in &text.hyperlink_index {
503                                // 获取超链接文本的范围
504                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
505                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
506
507                                let start_pos = start_cursor.left_top();
508                                let end_pos = end_cursor.right_top();
509                                // 绘制超链接下划线
510                                // 检查超链接是否跨行
511                                if start_cursor.min.y == end_cursor.min.y {
512                                    // 单行超链接
513                                    let underline_y = text.position[1]
514                                        + start_pos.y
515                                        + galley.rows.first().map_or(14.0, |row| row.height())
516                                        - 2.0;
517
518                                    // 绘制下划线
519                                    let color = Color32::from_rgba_unmultiplied(
520                                        text.color[0],
521                                        text.color[1],
522                                        text.color[2],
523                                        text.alpha,
524                                    );
525
526                                    ui.painter().line_segment(
527                                        [
528                                            Pos2::new(text.position[0] + start_pos.x, underline_y),
529                                            Pos2::new(text.position[0] + end_pos.x, underline_y),
530                                        ],
531                                        Stroke::new(text.font_size / 10_f32, color),
532                                    );
533                                } else {
534                                    // 多行超链接
535                                    let row_height =
536                                        galley.rows.first().map_or(14.0, |row| row.height()); // 默认行高14.0
537
538                                    // 计算起始行和结束行的索引
539                                    let start_row = (start_pos.y / row_height).round() as usize;
540                                    let end_row = (end_pos.y / row_height).round() as usize;
541
542                                    for row in start_row..=end_row {
543                                        let row_y =
544                                            text.position[1] + row as f32 * row_height + row_height
545                                                - 2.0; // 行底部稍微上移一点绘制下划线
546
547                                        // 获取当前行的矩形范围
548                                        if let Some(current_row) = galley.rows.get(row) {
549                                            let row_rect = current_row.rect();
550
551                                            let color = Color32::from_rgba_unmultiplied(
552                                                text.color[0],
553                                                text.color[1],
554                                                text.color[2],
555                                                text.alpha,
556                                            );
557
558                                            if row == start_row {
559                                                // 第一行从文本开始位置到行尾
560                                                ui.painter().line_segment(
561                                                    [
562                                                        Pos2::new(
563                                                            text.position[0] + start_pos.x,
564                                                            row_y,
565                                                        ),
566                                                        Pos2::new(
567                                                            text.position[0] + row_rect.max.x,
568                                                            row_y,
569                                                        ),
570                                                    ],
571                                                    Stroke::new(text.font_size / 10_f32, color),
572                                                );
573                                            } else if row == end_row {
574                                                // 最后一行从行首到文本结束位置
575                                                ui.painter().line_segment(
576                                                    [
577                                                        Pos2::new(
578                                                            text.position[0] + row_rect.min.x,
579                                                            row_y,
580                                                        ),
581                                                        Pos2::new(
582                                                            text.position[0] + end_pos.x,
583                                                            row_y,
584                                                        ),
585                                                    ],
586                                                    Stroke::new(text.font_size / 10_f32, color),
587                                                );
588                                            } else {
589                                                // 中间整行下划线
590                                                ui.painter().line_segment(
591                                                    [
592                                                        Pos2::new(
593                                                            text.position[0] + row_rect.min.x,
594                                                            row_y,
595                                                        ),
596                                                        Pos2::new(
597                                                            text.position[0] + row_rect.max.x,
598                                                            row_y,
599                                                        ),
600                                                    ],
601                                                    Stroke::new(text.font_size / 10_f32, color),
602                                                );
603                                            };
604                                        };
605                                    }
606                                };
607                            }
608
609                            if text.selectable {
610                                // 处理选择逻辑
611                                let cursor_at_pointer = |pointer_pos: Vec2| -> usize {
612                                    let relative_pos = pointer_pos - text.position.into();
613                                    let cursor = galley.cursor_from_pos(relative_pos);
614                                    cursor.index
615                                };
616
617                                let fullscreen_detect_result = ui.input(|i| i.pointer.clone());
618                                let rect = Rect::from_min_size(
619                                    text.position.into(),
620                                    text.actual_size.into(),
621                                );
622                                let detect_result = ui.interact(
623                                    rect,
624                                    Id::new(&render_resource.0.name),
625                                    Sense::click_and_drag(),
626                                );
627
628                                if !detect_result.clicked()
629                                    && (fullscreen_detect_result.any_click()
630                                        || fullscreen_detect_result.any_pressed())
631                                {
632                                    text.selection = None;
633                                };
634
635                                if let Some(index) =
636                                    self.get_render_layer_resource(&RustConstructorId {
637                                        name: render_resource.0.name.clone(),
638                                        discern_type: "Text".to_string(),
639                                    })
640                                    && let Some(mouse_pos) = fullscreen_detect_result.interact_pos()
641                                    && self.resource_get_focus(
642                                        index,
643                                        mouse_pos.into(),
644                                        false,
645                                        vec![],
646                                    )
647                                    && (detect_result.clicked() || detect_result.drag_started())
648                                {
649                                    let cursor = cursor_at_pointer(mouse_pos.to_vec2());
650                                    text.selection = Some((cursor, cursor));
651                                };
652
653                                if detect_result.dragged()
654                                    && text.selection.is_some()
655                                    && let Some(pointer_pos) =
656                                        ui.input(|i| i.pointer.interact_pos())
657                                {
658                                    let cursor = cursor_at_pointer(pointer_pos.to_vec2());
659                                    if let Some((start, _)) = text.selection {
660                                        text.selection = Some((start, cursor));
661                                    };
662                                };
663
664                                if text.selection.is_some()
665                                    && ui.input(|input| {
666                                        input.key_released(Key::A) && input.modifiers.command
667                                    })
668                                {
669                                    text.selection = Some((0, display_content.chars().count()));
670                                };
671
672                                // 处理复制操作
673                                let copy_triggered = ui.input(|input| {
674                                    let c_released = input.key_released(Key::C);
675                                    let cmd_pressed = input.modifiers.command;
676                                    c_released && cmd_pressed
677                                });
678                                if copy_triggered && let Some((start, end)) = text.selection {
679                                    let (start, end) = (start.min(end), start.max(end));
680                                    let chars: Vec<char> = display_content.chars().collect();
681                                    if start <= chars.len() && end <= chars.len() && start < end {
682                                        let selected_text: String =
683                                            chars[start..end].iter().collect();
684                                        ui.ctx().copy_text(selected_text);
685                                    };
686                                };
687
688                                // 绘制选择区域背景
689                                if let Some((start, end)) = text.selection {
690                                    let (start, end) = (start.min(end), start.max(end));
691                                    if start != end {
692                                        // 获取选择区域的范围
693                                        let start_cursor =
694                                            galley.pos_from_cursor(CCursor::new(start));
695                                        let end_cursor = galley.pos_from_cursor(CCursor::new(end));
696
697                                        let start_pos = start_cursor.left_top();
698                                        let end_pos = end_cursor.right_top();
699                                        // 选择框绘制
700                                        if start_pos.y == end_pos.y {
701                                            // 单行选择
702                                            let rows = &galley.rows;
703                                            let row_height = if !rows.is_empty() {
704                                                // 获取实际行的高度
705                                                if let Some(row) = rows.first() {
706                                                    row.height()
707                                                } else {
708                                                    text.actual_size[1]
709                                                        / display_content.lines().count() as f32
710                                                }
711                                            } else {
712                                                text.actual_size[1]
713                                                    / display_content.lines().count() as f32
714                                            };
715
716                                            let selection_rect = Rect::from_min_max(
717                                                Pos2::new(
718                                                    text.position[0] + start_pos.x,
719                                                    text.position[1] + start_pos.y,
720                                                ),
721                                                Pos2::new(
722                                                    text.position[0] + end_pos.x,
723                                                    text.position[1] + start_pos.y + row_height,
724                                                ),
725                                            );
726                                            ui.painter().rect_filled(
727                                                selection_rect,
728                                                0.0,
729                                                Color32::from_rgba_unmultiplied(0, 120, 255, 100),
730                                            );
731                                        } else {
732                                            // 多行选择 - 为每行创建精确的矩形
733                                            let rows = &galley.rows;
734                                            let row_height = if !rows.is_empty() {
735                                                rows[0].height()
736                                            } else {
737                                                text.actual_size[1]
738                                                    / display_content.lines().count() as f32
739                                            };
740
741                                            // 计算选择的上下边界
742                                            let selection_top =
743                                                text.position[1] + start_pos.y.min(end_pos.y);
744                                            let selection_bottom =
745                                                text.position[1] + start_pos.y.max(end_pos.y);
746
747                                            // 确定起始行和结束行的索引
748                                            let start_row_index =
749                                                (start_pos.y / row_height).floor() as usize;
750                                            let end_row_index =
751                                                (end_pos.y / row_height).floor() as usize;
752                                            let (first_row_index, last_row_index) =
753                                                if start_row_index <= end_row_index {
754                                                    (start_row_index, end_row_index)
755                                                } else {
756                                                    (end_row_index, start_row_index)
757                                                };
758
759                                            for (i, row) in rows.iter().enumerate() {
760                                                let row_y =
761                                                    text.position[1] + row_height * i as f32;
762                                                let row_bottom = row_y + row_height;
763                                                // 检查当前行是否与选择区域相交
764                                                if row_bottom > selection_top
765                                                    && row_y <= selection_bottom
766                                                {
767                                                    let left = if i == first_row_index {
768                                                        // 首行 - 从选择开始位置开始
769                                                        text.position[0] + start_pos.x
770                                                    } else {
771                                                        // 非首行 - 从行首开始
772                                                        text.position[0] + row.rect().min.x
773                                                    };
774
775                                                    let right = if i == last_row_index {
776                                                        // 尾行 - 到选择结束位置结束
777                                                        text.position[0] + end_pos.x
778                                                    } else {
779                                                        // 非尾行 - 到行尾结束
780                                                        text.position[0] + row.rect().max.x
781                                                    };
782
783                                                    let selection_rect = Rect::from_min_max(
784                                                        Pos2::new(left, row_y),
785                                                        Pos2::new(right, row_bottom),
786                                                    );
787
788                                                    // 确保矩形有效
789                                                    if selection_rect.width() > 0.0
790                                                        && selection_rect.height() > 0.0
791                                                    {
792                                                        ui.painter().rect_filled(
793                                                            selection_rect,
794                                                            0.0,
795                                                            Color32::from_rgba_unmultiplied(
796                                                                0, 120, 255, 100,
797                                                            ),
798                                                        );
799                                                    };
800                                                };
801                                            }
802                                        };
803                                    };
804                                };
805                            };
806
807                            // 处理超链接操作
808                            for (start, end, url) in &text.hyperlink_index {
809                                // 获取超链接文本的范围
810                                let start_cursor = galley.pos_from_cursor(CCursor::new(*start));
811                                let end_cursor = galley.pos_from_cursor(CCursor::new(*end));
812
813                                let start_pos = start_cursor.left_top();
814                                let end_pos = end_cursor.right_top();
815
816                                let row_height =
817                                    galley.rows.first().map_or(14.0, |row| row.height());
818
819                                // 为超链接创建交互响应对象
820                                let link_responses = if start_cursor.min.y == end_cursor.min.y {
821                                    // 单行超链接
822                                    let link_rect = Rect::from_min_max(
823                                        Pos2::new(
824                                            text.position[0] + start_pos.x,
825                                            text.position[1] + start_pos.y,
826                                        ),
827                                        Pos2::new(
828                                            text.position[0] + end_pos.x,
829                                            text.position[1] + start_pos.y + row_height,
830                                        ),
831                                    );
832                                    vec![ui.interact(
833                                        link_rect,
834                                        Id::new(format!(
835                                            "link_{}_{}_{}",
836                                            render_resource.0.name, start, end
837                                        )),
838                                        Sense::click(),
839                                    )]
840                                } else {
841                                    // 多行超链接
842                                    let start_row = (start_pos.y / row_height).round() as usize;
843                                    let end_row = (end_pos.y / row_height).round() as usize;
844                                    let mut responses = Vec::new();
845
846                                    for row in start_row..=end_row {
847                                        if let Some(current_row) = galley.rows.get(row) {
848                                            let row_rect = current_row.rect();
849                                            let row_y = text.position[1] + row as f32 * row_height;
850
851                                            let link_rect = if row == start_row {
852                                                // 第一行从文本开始位置到行尾
853                                                Rect::from_min_max(
854                                                    Pos2::new(
855                                                        text.position[0] + start_pos.x,
856                                                        row_y,
857                                                    ),
858                                                    Pos2::new(
859                                                        text.position[0] + row_rect.max.x,
860                                                        row_y + row_height,
861                                                    ),
862                                                )
863                                            } else if row == end_row {
864                                                // 最后一行从行首到文本结束位置
865                                                Rect::from_min_max(
866                                                    Pos2::new(
867                                                        text.position[0] + row_rect.min.x,
868                                                        row_y,
869                                                    ),
870                                                    Pos2::new(
871                                                        text.position[0] + end_pos.x,
872                                                        row_y + row_height,
873                                                    ),
874                                                )
875                                            } else {
876                                                // 中间整行
877                                                Rect::from_min_max(
878                                                    Pos2::new(
879                                                        text.position[0] + row_rect.min.x,
880                                                        row_y,
881                                                    ),
882                                                    Pos2::new(
883                                                        text.position[0] + row_rect.max.x,
884                                                        row_y + row_height,
885                                                    ),
886                                                )
887                                            };
888
889                                            responses.push(ui.interact(
890                                                link_rect,
891                                                Id::new(format!(
892                                                    "link_{}_{}_{}_row_{}",
893                                                    render_resource.0.name, start, end, row
894                                                )),
895                                                Sense::click(),
896                                            ));
897                                        };
898                                    }
899                                    responses
900                                };
901
902                                // 检查是否正在点击这个超链接
903                                let mut is_pressing_link = false;
904                                for link_response in &link_responses {
905                                    if let Some(index) =
906                                        self.get_render_layer_resource(&RustConstructorId {
907                                            name: render_resource.0.name.clone(),
908                                            discern_type: "Text".to_string(),
909                                        })
910                                        && let Some(mouse_pos) =
911                                            ui.input(|i| i.pointer.interact_pos())
912                                        && self.resource_get_focus(
913                                            index,
914                                            mouse_pos.into(),
915                                            false,
916                                            vec![],
917                                        )
918                                    {
919                                        if link_response.is_pointer_button_down_on()
920                                            && !link_response.drag_started()
921                                        {
922                                            text.selection = None;
923                                            if let Some(pointer_pos) =
924                                                ui.input(|i| i.pointer.interact_pos())
925                                            {
926                                                let relative_pos = pointer_pos
927                                                    - <[f32; 2] as Into<Pos2>>::into(text.position);
928                                                let cursor = galley.cursor_from_pos(relative_pos);
929                                                if cursor.index >= *start && cursor.index <= *end {
930                                                    is_pressing_link = true;
931                                                    break;
932                                                };
933                                            };
934                                        };
935                                        // 检查是否释放了鼠标(点击完成)
936                                        let mut clicked_on_link = false;
937                                        for link_response in &link_responses {
938                                            if link_response.clicked()
939                                                && let Some(pointer_pos) =
940                                                    ui.input(|i| i.pointer.interact_pos())
941                                            {
942                                                let relative_pos = pointer_pos
943                                                    - <[f32; 2] as Into<Pos2>>::into(text.position);
944                                                let cursor = galley.cursor_from_pos(relative_pos);
945                                                if cursor.index >= *start && cursor.index <= *end {
946                                                    clicked_on_link = true;
947                                                    break;
948                                                };
949                                            };
950                                        }
951
952                                        if clicked_on_link {
953                                            // 执行超链接跳转
954                                            if !url.is_empty() {
955                                                ui.ctx().open_url(OpenUrl::new_tab(url));
956                                            };
957                                        };
958                                    };
959                                }
960
961                                // 绘制超链接高亮(如果正在点击或悬停)
962                                if is_pressing_link {
963                                    if start_cursor.min.y == end_cursor.min.y {
964                                        // 单行超链接高亮
965                                        let selection_rect = Rect::from_min_max(
966                                            Pos2::new(
967                                                text.position[0] + start_pos.x,
968                                                text.position[1] + start_pos.y,
969                                            ),
970                                            Pos2::new(
971                                                text.position[0] + end_pos.x,
972                                                text.position[1]
973                                                    + start_pos.y
974                                                    + galley
975                                                        .rows
976                                                        .first()
977                                                        .map_or(14.0, |row| row.height()),
978                                            ),
979                                        );
980                                        ui.painter().rect_filled(
981                                            selection_rect,
982                                            0.0,
983                                            Color32::from_rgba_unmultiplied(0, 120, 255, 100),
984                                        );
985                                    } else {
986                                        // 多行超链接高亮
987                                        let row_height =
988                                            galley.rows.first().map_or(14.0, |row| row.height());
989                                        let start_row = (start_pos.y / row_height).round() as usize;
990                                        let end_row = (end_pos.y / row_height).round() as usize;
991
992                                        for row in start_row..=end_row {
993                                            if let Some(current_row) = galley.rows.get(row) {
994                                                let row_rect = current_row.rect();
995
996                                                if row == start_row {
997                                                    // 第一行从文本开始位置到行尾
998                                                    let selection_rect = Rect::from_min_max(
999                                                        Pos2::new(
1000                                                            text.position[0] + start_pos.x,
1001                                                            text.position[1]
1002                                                                + row as f32 * row_height,
1003                                                        ),
1004                                                        Pos2::new(
1005                                                            text.position[0] + row_rect.max.x,
1006                                                            text.position[1]
1007                                                                + row as f32 * row_height
1008                                                                + row_height,
1009                                                        ),
1010                                                    );
1011                                                    ui.painter().rect_filled(
1012                                                        selection_rect,
1013                                                        0.0,
1014                                                        Color32::from_rgba_unmultiplied(
1015                                                            0, 120, 255, 100,
1016                                                        ),
1017                                                    );
1018                                                } else if row == end_row {
1019                                                    // 最后一行从行首到文本结束位置
1020                                                    let selection_rect = Rect::from_min_max(
1021                                                        Pos2::new(
1022                                                            text.position[0] + row_rect.min.x,
1023                                                            text.position[1]
1024                                                                + row as f32 * row_height,
1025                                                        ),
1026                                                        Pos2::new(
1027                                                            text.position[0] + end_pos.x,
1028                                                            text.position[1]
1029                                                                + row as f32 * row_height
1030                                                                + row_height,
1031                                                        ),
1032                                                    );
1033                                                    ui.painter().rect_filled(
1034                                                        selection_rect,
1035                                                        0.0,
1036                                                        Color32::from_rgba_unmultiplied(
1037                                                            0, 120, 255, 100,
1038                                                        ),
1039                                                    );
1040                                                } else {
1041                                                    // 中间整行高亮
1042                                                    let selection_rect = Rect::from_min_max(
1043                                                        Pos2::new(
1044                                                            text.position[0] + row_rect.min.x,
1045                                                            text.position[1]
1046                                                                + row as f32 * row_height,
1047                                                        ),
1048                                                        Pos2::new(
1049                                                            text.position[0] + row_rect.max.x,
1050                                                            text.position[1]
1051                                                                + row as f32 * row_height
1052                                                                + row_height,
1053                                                        ),
1054                                                    );
1055                                                    ui.painter().rect_filled(
1056                                                        selection_rect,
1057                                                        0.0,
1058                                                        Color32::from_rgba_unmultiplied(
1059                                                            0, 120, 255, 100,
1060                                                        ),
1061                                                    );
1062                                                };
1063                                            };
1064                                        }
1065                                    };
1066                                };
1067                            }
1068                            if text.basic_front_resource_config.clip_rect.is_some() {
1069                                ui.set_clip_rect(Rect::from_min_size(
1070                                    [0_f32, 0_f32].into(),
1071                                    [ctx.available_rect().width(), ctx.available_rect().height()]
1072                                        .into(),
1073                                ));
1074                            };
1075                        } else {
1076                            text.selection = None;
1077                        };
1078                        text.last_frame_content = display_content;
1079                        self.replace_resource(&render_resource.0.name, text)?;
1080                    };
1081                }
1082                "CustomRect" => {
1083                    let custom_rect = self.get_resource::<CustomRect>(&RustConstructorId {
1084                        name: render_resource.0.name.clone(),
1085                        discern_type: "CustomRect".to_string(),
1086                    })?;
1087                    if custom_rect.display_info.enable {
1088                        let mut custom_rect = custom_rect.clone();
1089                        [custom_rect.position, custom_rect.size] = position_size_processor(
1090                            custom_rect.basic_front_resource_config.position_size_config,
1091                            ctx,
1092                        );
1093                        if !custom_rect.display_info.hidden {
1094                            if let Some(clip_rect) =
1095                                custom_rect.basic_front_resource_config.clip_rect
1096                            {
1097                                let [min, size] = position_size_processor(clip_rect, ctx);
1098                                ui.set_clip_rect(Rect::from_min_size(min.into(), size.into()));
1099                            };
1100                            ui.painter().rect(
1101                                Rect::from_min_max(
1102                                    Pos2::new(custom_rect.position[0], custom_rect.position[1]),
1103                                    Pos2::new(
1104                                        custom_rect.position[0] + custom_rect.size[0],
1105                                        custom_rect.position[1] + custom_rect.size[1],
1106                                    ),
1107                                ),
1108                                custom_rect.rounding,
1109                                if let Some(overlay_alpha) = custom_rect.overlay_alpha {
1110                                    Color32::from_rgba_unmultiplied(
1111                                        (custom_rect.color[0] as f32
1112                                            * custom_rect.overlay_color[0] as f32
1113                                            / 255_f32)
1114                                            as u8,
1115                                        (custom_rect.color[1] as f32
1116                                            * custom_rect.overlay_color[1] as f32
1117                                            / 255_f32)
1118                                            as u8,
1119                                        (custom_rect.color[2] as f32
1120                                            * custom_rect.overlay_color[2] as f32
1121                                            / 255_f32)
1122                                            as u8,
1123                                        (custom_rect.alpha as f32 * overlay_alpha as f32 / 255_f32)
1124                                            as u8,
1125                                    )
1126                                } else {
1127                                    Color32::from_rgba_unmultiplied(
1128                                        custom_rect.color[0],
1129                                        custom_rect.color[1],
1130                                        custom_rect.color[2],
1131                                        custom_rect.alpha,
1132                                    )
1133                                },
1134                                Stroke {
1135                                    width: custom_rect.border_width,
1136                                    color: if let Some(overlay_border_alpha) =
1137                                        custom_rect.overlay_border_alpha
1138                                    {
1139                                        Color32::from_rgba_unmultiplied(
1140                                            (custom_rect.border_color[0] as f32
1141                                                * custom_rect.overlay_border_color[0] as f32
1142                                                / 255_f32)
1143                                                as u8,
1144                                            (custom_rect.border_color[1] as f32
1145                                                * custom_rect.overlay_border_color[1] as f32
1146                                                / 255_f32)
1147                                                as u8,
1148                                            (custom_rect.border_color[2] as f32
1149                                                * custom_rect.overlay_border_color[2] as f32
1150                                                / 255_f32)
1151                                                as u8,
1152                                            (custom_rect.border_alpha as f32
1153                                                * overlay_border_alpha as f32
1154                                                / 255_f32)
1155                                                as u8,
1156                                        )
1157                                    } else {
1158                                        Color32::from_rgba_unmultiplied(
1159                                            custom_rect.border_color[0],
1160                                            custom_rect.border_color[1],
1161                                            custom_rect.border_color[2],
1162                                            custom_rect.border_alpha,
1163                                        )
1164                                    },
1165                                },
1166                                match custom_rect.border_kind {
1167                                    BorderKind::Inside => StrokeKind::Inside,
1168                                    BorderKind::Middle => StrokeKind::Middle,
1169                                    BorderKind::Outside => StrokeKind::Outside,
1170                                },
1171                            );
1172                            if custom_rect.basic_front_resource_config.clip_rect.is_some() {
1173                                ui.set_clip_rect(Rect::from_min_size(
1174                                    [0_f32, 0_f32].into(),
1175                                    [ctx.available_rect().width(), ctx.available_rect().height()]
1176                                        .into(),
1177                                ));
1178                            };
1179                        };
1180                        self.replace_resource(&render_resource.0.name, custom_rect)?;
1181                    };
1182                }
1183                _ => {
1184                    unreachable!()
1185                }
1186            }
1187            Ok(())
1188        } else {
1189            Err(RustConstructorError {
1190                error_id: "IndexOutOfRange".to_string(),
1191                description: format!(
1192                    "The maximum index of the target list is {}, but the index is {index}.",
1193                    self.render_list.len() - 1
1194                ),
1195            })
1196        }
1197    }
1198
1199    /// Generate information for Rust Constructor resources.
1200    ///
1201    /// 生成Rust Constructor资源的信息。
1202    ///
1203    /// This method returns a formatted string containing details about all resources.
1204    /// The level of detail depends on the specified method.
1205    ///
1206    /// 此方法返回一个格式化字符串,包含所有资源的详细信息。
1207    /// 详细程度取决于指定的方法。
1208    ///
1209    /// # Arguments
1210    ///
1211    /// * `describe` - Determines the level of detail in the output
1212    /// * `print` - Determines whether to print
1213    ///
1214    /// # Returns
1215    ///
1216    /// A formatted string with resource information.
1217    ///
1218    /// # 参数
1219    ///
1220    /// * `describe` - 决定输出信息的详细程度
1221    /// * `print` - 决定是否打印
1222    ///
1223    /// # 返回值
1224    ///
1225    /// 包含资源信息的格式化字符串。
1226    pub fn rust_constructor_resource_info(
1227        &self,
1228        describe: ListInfoDescribeMethod,
1229        print: bool,
1230    ) -> String {
1231        let mut text =
1232            String::from("————————————————————————————————————\nRust Constructor Resource Info:\n");
1233        for info in &self.rust_constructor_resource {
1234            if let ListInfoDescribeMethod::Detailed(format) = describe {
1235                text += &if format {
1236                    format!(
1237                        "\nName: {}\nType: {}\nDetail: {:#?}\n",
1238                        info.id.name, info.id.discern_type, info.content,
1239                    )
1240                } else {
1241                    format!(
1242                        "\nName: {}\nType: {}\nDetail: {:?}\n",
1243                        info.id.name, info.id.discern_type, info.content,
1244                    )
1245                };
1246            } else {
1247                text += &format!("\nName: {}\nType: {}\n", info.id.name, info.id.discern_type,)
1248            };
1249        }
1250        if print {
1251            println!("{text}");
1252        };
1253        text
1254    }
1255
1256    /// Generates information about currently active resources.
1257    ///
1258    /// 生成当前活跃资源的信息。
1259    ///
1260    /// This method returns a formatted string containing details about all resources
1261    /// in the active list. The level of detail depends on the specified method.
1262    ///
1263    /// 此方法返回一个格式化字符串,包含活动列表中所有资源的详细信息。
1264    /// 详细程度取决于指定的方法。
1265    ///
1266    /// # Arguments
1267    ///
1268    /// * `describe` - Determines the level of detail in the output
1269    /// * `print` - Determines whether to print
1270    ///
1271    /// # Returns
1272    ///
1273    /// A formatted string with resource information.
1274    ///
1275    /// # 参数
1276    ///
1277    /// * `describe` - 决定输出信息的详细程度
1278    /// * `print` - 决定是否打印
1279    ///
1280    /// # 返回值
1281    ///
1282    /// 包含资源信息的格式化字符串。
1283    pub fn active_list_info(&self, describe: ListInfoDescribeMethod, print: bool) -> String {
1284        let mut text =
1285            String::from("————————————————————————————————————\nResource Active Info:\n");
1286        for info in &self.active_list {
1287            if let ListInfoDescribeMethod::Detailed(format) = describe {
1288                if let Some(index) = self.check_resource_exists(&info.0) {
1289                    text += &if format {
1290                        format!(
1291                            "\nName: {}\nType: {}\nCiter: {:?}\nDetail: {:#?}\n",
1292                            info.0.name,
1293                            info.0.discern_type,
1294                            info.1,
1295                            self.rust_constructor_resource[index],
1296                        )
1297                    } else {
1298                        format!(
1299                            "\nName: {}\nType: {}\nCiter: {:?}\nDetail: {:?}\n",
1300                            info.0.name,
1301                            info.0.discern_type,
1302                            info.1,
1303                            self.rust_constructor_resource[index],
1304                        )
1305                    };
1306                };
1307            } else {
1308                text += &format!(
1309                    "\nName: {}\nType: {}\nCiter: {:?}\n",
1310                    info.0.name, info.0.discern_type, info.1
1311                );
1312            };
1313        }
1314        if print {
1315            println!("{text}");
1316        };
1317        text
1318    }
1319
1320    /// Generates information about the current rendering layers.
1321    ///
1322    /// 生成当前渲染层级的信息。
1323    ///
1324    /// This method returns a formatted string containing details about the rendering
1325    /// layer stack, including resource positions and rendering behavior.
1326    ///
1327    /// 此方法返回一个格式化字符串,包含渲染层级堆栈的详细信息,
1328    /// 包括资源位置和渲染行为。
1329    ///
1330    /// # Arguments
1331    ///
1332    /// * `print` - Determines whether to print
1333    ///
1334    /// # Returns
1335    ///
1336    /// A formatted string with rendering layer information.
1337    ///
1338    /// # 参数
1339    ///
1340    /// * `print` - 决定是否打印
1341    ///
1342    /// # 返回值
1343    ///
1344    /// 包含渲染层级信息的格式化字符串。
1345    pub fn render_layer_info(&self, print: bool) -> String {
1346        let mut text = String::from("————————————————————————————————————\nRender Layer Info:\n");
1347        for (
1348            RustConstructorId { name, discern_type },
1349            [min_position, max_position],
1350            ignore_render_layer,
1351        ) in &self.render_layer
1352        {
1353            text += &format!(
1354                "\nName: {}\nType: {}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
1355                name, discern_type, min_position, max_position, ignore_render_layer
1356            )
1357        }
1358        if print {
1359            println!("{text}");
1360        };
1361        text
1362    }
1363
1364    /// Generates information about the current render queue.
1365    ///
1366    /// 生成当前渲染队列的信息。
1367    ///
1368    /// This method returns a formatted string listing all resources in the
1369    /// render queue with their names and types.
1370    ///
1371    /// 此方法返回一个格式化字符串,列出渲染队列中的所有资源及其名称和类型。
1372    ///
1373    /// # Arguments
1374    ///
1375    /// * `print` - Determines whether to print
1376    ///
1377    /// # Returns
1378    ///
1379    /// A formatted string with render queue information.
1380    ///
1381    /// # 参数
1382    ///
1383    /// * `print` - 决定是否打印
1384    ///
1385    /// # 返回值
1386    ///
1387    /// 包含渲染队列信息的格式化字符串。
1388    pub fn render_list_info(&self, print: bool) -> String {
1389        let mut text = String::from("————————————————————————————————————\nRender List Info:\n");
1390        for (RustConstructorId { name, discern_type }, citer) in &self.render_list {
1391            text += &format!(
1392                "\nName: {}\nType: {}\nCiter: {:?}\n",
1393                name, discern_type, citer
1394            )
1395        }
1396        if print {
1397            println!("{text}");
1398        };
1399        text
1400    }
1401
1402    /// Updates the render queue based on active resources.
1403    ///
1404    /// 根据活跃资源更新渲染队列。
1405    ///
1406    /// This method synchronizes the render list with the active list, ensuring that
1407    /// only active basic front resources are included in the rendering queue.
1408    ///
1409    /// 此方法将渲染列表与活跃列表同步,确保只有活跃的基本前端资源包含在渲染队列中。
1410    pub fn update_render_list(&mut self) {
1411        if self.render_list.is_empty() {
1412            for info in &self.active_list {
1413                if self
1414                    .basic_front_resource_list
1415                    .contains(&info.0.discern_type)
1416                {
1417                    self.render_list.push(info.clone());
1418                };
1419            }
1420        } else {
1421            let mut count = 0;
1422            for render_resource in &self.render_list.clone() {
1423                if !self.active_list.contains(render_resource) {
1424                    self.render_list.remove(count);
1425                } else {
1426                    count += 1;
1427                };
1428            }
1429            let mut insert_index = 0;
1430            for info in &self.active_list {
1431                if self
1432                    .basic_front_resource_list
1433                    .contains(&info.0.discern_type)
1434                {
1435                    if !self.render_list.contains(info) {
1436                        self.render_list.insert(insert_index, info.clone());
1437                        insert_index += 1;
1438                    } else if self.render_list[insert_index].cmp(info) == Ordering::Equal {
1439                        insert_index += 1;
1440                    };
1441                };
1442            }
1443        };
1444    }
1445
1446    /// Attempts to move a resource to the front of the render queue, ignoring whether it exists.
1447    ///
1448    /// 请求在渲染队列中插队,且无视申请跳过队列的资源是否存在。
1449    ///
1450    /// This is a safe wrapper around `request_jump_render_list` that suppresses errors.
1451    /// Use when you want to attempt reordering without handling potential errors.
1452    ///
1453    /// 这是`request_jump_render_list`的安全包装器,会抑制错误。当您想要尝试重新排序而不处理潜在错误时使用。
1454    ///
1455    /// # Arguments
1456    ///
1457    /// * `requester` - The resource to move in the queue
1458    /// * `request_type` - How to move the resource (to top or up N layers)
1459    ///
1460    /// # 参数
1461    ///
1462    /// * `requester` - 要在队列中移动的资源
1463    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1464    pub fn try_request_jump_render_list(
1465        &mut self,
1466        requester: RequestMethod,
1467        request_type: RequestType,
1468    ) {
1469        let _ = self.request_jump_render_list(requester, request_type);
1470    }
1471
1472    /// Moves a resource to the front of the render queue with error handling.
1473    ///
1474    /// 将资源移动到渲染队列的前面(含错误处理)。
1475    ///
1476    /// This method allows changing the rendering order of resources by moving a specific
1477    /// resource to the top of the queue or up a specified number of layers.
1478    ///
1479    /// 此方法允许通过将特定资源移动到队列顶部或上移指定层数来更改资源的渲染顺序。
1480    ///
1481    /// # Arguments
1482    ///
1483    /// * `requester` - The resource to move in the queue
1484    /// * `request_type` - How to move the resource (to top or up N layers)
1485    ///
1486    /// # Returns
1487    ///
1488    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource
1489    /// cannot be found.
1490    ///
1491    /// # 参数
1492    ///
1493    /// * `requester` - 要在队列中移动的资源
1494    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1495    ///
1496    /// # 返回值
1497    ///
1498    /// 成功时返回`Ok(())`,如果资源无法找到则返回`Err(RustConstructorError)`。
1499    pub fn request_jump_render_list(
1500        &mut self,
1501        requester: RequestMethod,
1502        request_type: RequestType,
1503    ) -> Result<(), RustConstructorError> {
1504        match requester {
1505            RequestMethod::Id(id) => {
1506                if let Some(index) = self.render_list.iter().position(|x| x.0 == id) {
1507                    self.jump_render_list_processor(index, request_type)?;
1508                    Ok(())
1509                } else {
1510                    Err(RustConstructorError {
1511                        error_id: "RenderResourceNotFound".to_string(),
1512                        description: format!(
1513                            "Render resource '{}({})' not found.",
1514                            id.name, id.discern_type
1515                        ),
1516                    })
1517                }
1518            }
1519            RequestMethod::Citer(citer) => {
1520                for (i, render_resource) in self.render_list.iter().enumerate() {
1521                    if let Some(render_citer) = &render_resource.1
1522                        && render_citer == &citer
1523                    {
1524                        self.jump_render_list_processor(i, request_type)?;
1525                        return Ok(());
1526                    };
1527                }
1528                Err(RustConstructorError {
1529                    error_id: "RenderResourceNotFound".to_string(),
1530                    description: format!(
1531                        "Render resource citer '{}({})' not found.",
1532                        citer.name, citer.discern_type
1533                    ),
1534                })
1535            }
1536        }
1537    }
1538
1539    /// Handle the operation of skipping the rendering queue.
1540    ///
1541    /// 处理跳过渲染队列操作。
1542    ///
1543    /// # Arguments
1544    ///
1545    /// * `requester_index` - The index of the resources to be moved in the queue
1546    /// * `request_type` - How to move the resource (to top or up N layers)
1547    ///
1548    /// # Returns
1549    ///
1550    /// When successful, return `Ok(())`. If the index is out of bounds, return `Err(RustConstructorError)`.
1551    ///
1552    /// # 参数
1553    ///
1554    /// * `requester_index` - 要在队列中移动的资源的索引
1555    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1556    ///
1557    /// # 返回值
1558    ///
1559    /// 成功时返回`Ok(())`,如果索引越界则返回`Err(RustConstructorError)`。
1560    pub fn jump_render_list_processor(
1561        &mut self,
1562        requester_index: usize,
1563        request_type: RequestType,
1564    ) -> Result<(), RustConstructorError> {
1565        if requester_index < self.render_list.len() {
1566            let requester = self.render_list.remove(requester_index);
1567            let new_index = match request_type {
1568                RequestType::Top => self.render_list.len(),
1569                RequestType::Up(up) => {
1570                    if requester_index + up <= self.render_list.len() {
1571                        requester_index + up
1572                    } else {
1573                        self.render_list.len()
1574                    }
1575                }
1576            };
1577            self.render_list.insert(new_index, requester);
1578            Ok(())
1579        } else {
1580            Err(RustConstructorError {
1581                error_id: "IndexOutOfRange".to_string(),
1582                description: format!(
1583                    "The maximum index of the target list is {}, but the index is {requester_index}.",
1584                    self.render_list.len() - 1
1585                ),
1586            })
1587        }
1588    }
1589
1590    /// Updates the rendering layer information for all rendering resources.
1591    ///
1592    /// 更新所有渲染资源的渲染层信息。
1593    ///
1594    /// This method recalculates the rendering layer by processing all resources
1595    /// in the render list and updating their position, size, and rendering properties.
1596    ///
1597    /// 此方法通过处理渲染列表中的所有资源并更新它们的位置、尺寸和渲染属性来重新计算渲染层级。
1598    ///
1599    /// # Arguments
1600    ///
1601    /// * `ctx` - The rendering context
1602    ///
1603    /// # Returns
1604    ///
1605    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource
1606    /// cannot be found.
1607    ///
1608    /// # 参数
1609    ///
1610    /// * `ctx` - 渲染上下文
1611    ///
1612    /// # 返回值
1613    ///
1614    /// 成功时返回`Ok(())`,如果资源无法找到则返回`Err(RustConstructorError)`。
1615    pub fn update_render_layer(&mut self, ctx: &Context) -> Result<(), RustConstructorError> {
1616        self.render_layer.clear();
1617        for info in &self.render_list {
1618            let basic_front_resource = self.get_basic_front_resource(&info.0)?;
1619            if let Some(display_info) = basic_front_resource.display_display_info() {
1620                self.render_layer.push((
1621                    info.0.clone(),
1622                    if let Some(clip_rect) = basic_front_resource
1623                        .display_basic_front_resource_config()
1624                        .clip_rect
1625                    {
1626                        let [position, size] = position_size_processor(clip_rect, ctx);
1627                        let [resource_rect, clip_rect] = [
1628                            Rect::from_min_max(
1629                                basic_front_resource.display_position().into(),
1630                                [
1631                                    basic_front_resource.display_position()[0]
1632                                        + basic_front_resource.display_size()[0],
1633                                    basic_front_resource.display_position()[1]
1634                                        + basic_front_resource.display_size()[1],
1635                                ]
1636                                .into(),
1637                            ),
1638                            Rect::from_min_size(position.into(), size.into()),
1639                        ];
1640                        let min = resource_rect.min.max(clip_rect.min);
1641                        let max = resource_rect.max.min(clip_rect.max);
1642
1643                        // 检查是否有交集
1644                        if min.x < max.x && min.y < max.y {
1645                            [min.into(), max.into()]
1646                        } else {
1647                            [[0_f32, 0_f32], [0_f32, 0_f32]]
1648                        }
1649                    } else {
1650                        [
1651                            basic_front_resource.display_position(),
1652                            [
1653                                basic_front_resource.display_position()[0]
1654                                    + basic_front_resource.display_size()[0],
1655                                basic_front_resource.display_position()[1]
1656                                    + basic_front_resource.display_size()[1],
1657                            ],
1658                        ]
1659                    },
1660                    display_info.ignore_render_layer,
1661                ));
1662            };
1663        }
1664        Ok(())
1665    }
1666
1667    /// Draw the rendering layer.
1668    ///
1669    /// 绘制渲染层。
1670    ///
1671    /// This method can visually inspect the rendering status of all rendering
1672    /// resources and promptly correct any issues.
1673    ///
1674    /// 此方法可以直观检查所有渲染资源的渲染情况,并及时修正问题。
1675    ///
1676    /// # Arguments
1677    ///
1678    /// * `ui` - The UI context for drawing
1679    /// * `render_config` - The config of the rendering layer area
1680    /// * `ignore_render` - The config of ignore the rendering layer area
1681    /// * `hover_config` - The config of hover the rendering layer area
1682    ///
1683    /// # 参数
1684    ///
1685    /// * `ui` - 用于绘制的UI上下文
1686    /// * `render_config` - 渲染层区域的配置
1687    /// * `ignore_render_config` - 无视渲染层区域的配置
1688    /// * `hover_config` - 鼠标悬停时的配置
1689    pub fn display_render_layer(
1690        &self,
1691        ui: &mut Ui,
1692        render_config: &RenderConfig,
1693        ignore_render_config: &RenderConfig,
1694        hover_config: Option<&RenderConfig>,
1695    ) {
1696        for (i, (_, point, ignore_render_layer)) in self.render_layer.iter().enumerate() {
1697            match if *ignore_render_layer {
1698                ignore_render_config
1699            } else {
1700                render_config
1701            } {
1702                RenderConfig::Rect(
1703                    corner_radius,
1704                    fill_color,
1705                    border_color,
1706                    border_width,
1707                    border_kind,
1708                ) => {
1709                    let rect = Rect::from_min_max(point[0].into(), point[1].into());
1710                    ui.painter().rect(
1711                        rect,
1712                        CornerRadius {
1713                            nw: corner_radius[0],
1714                            ne: corner_radius[1],
1715                            sw: corner_radius[2],
1716                            se: corner_radius[3],
1717                        },
1718                        Color32::from_rgba_unmultiplied(
1719                            fill_color[0],
1720                            fill_color[1],
1721                            fill_color[2],
1722                            fill_color[3],
1723                        ),
1724                        Stroke::new(
1725                            *border_width,
1726                            Color32::from_rgba_unmultiplied(
1727                                border_color[0],
1728                                border_color[1],
1729                                border_color[2],
1730                                border_color[3],
1731                            ),
1732                        ),
1733                        match *border_kind {
1734                            BorderKind::Inside => StrokeKind::Inside,
1735                            BorderKind::Middle => StrokeKind::Middle,
1736                            BorderKind::Outside => StrokeKind::Outside,
1737                        },
1738                    );
1739                }
1740                RenderConfig::Line(width, color) => {
1741                    ui.painter().line_segment(
1742                        [point[0].into(), point[1].into()],
1743                        Stroke::new(
1744                            *width,
1745                            Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
1746                        ),
1747                    );
1748                }
1749            };
1750            if let Some(hover_config) = hover_config
1751                && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
1752                && self.resource_get_focus(i, mouse_pos.into(), true, vec![])
1753            {
1754                match hover_config {
1755                    RenderConfig::Rect(
1756                        corner_radius,
1757                        fill_color,
1758                        border_color,
1759                        border_width,
1760                        border_kind,
1761                    ) => {
1762                        let rect = Rect::from_min_max(point[0].into(), point[1].into());
1763                        ui.painter().rect(
1764                            rect,
1765                            CornerRadius {
1766                                nw: corner_radius[0],
1767                                ne: corner_radius[1],
1768                                sw: corner_radius[2],
1769                                se: corner_radius[3],
1770                            },
1771                            Color32::from_rgba_unmultiplied(
1772                                fill_color[0],
1773                                fill_color[1],
1774                                fill_color[2],
1775                                fill_color[3],
1776                            ),
1777                            Stroke::new(
1778                                *border_width,
1779                                Color32::from_rgba_unmultiplied(
1780                                    border_color[0],
1781                                    border_color[1],
1782                                    border_color[2],
1783                                    border_color[3],
1784                                ),
1785                            ),
1786                            match *border_kind {
1787                                BorderKind::Inside => StrokeKind::Inside,
1788                                BorderKind::Middle => StrokeKind::Middle,
1789                                BorderKind::Outside => StrokeKind::Outside,
1790                            },
1791                        );
1792                    }
1793                    RenderConfig::Line(width, color) => {
1794                        ui.painter().line_segment(
1795                            [point[0].into(), point[1].into()],
1796                            Stroke::new(
1797                                *width,
1798                                Color32::from_rgba_unmultiplied(
1799                                    color[0], color[1], color[2], color[3],
1800                                ),
1801                            ),
1802                        );
1803                    }
1804                };
1805            };
1806        }
1807    }
1808
1809    /// Search for resources in the render list by ID.
1810    ///
1811    /// 通过ID在渲染列表中查找资源。
1812    ///
1813    /// # Arguments
1814    ///
1815    /// * `id` - The ID of the resource to search for
1816    ///
1817    /// # Returns
1818    ///
1819    /// The index of the resource in the render list, or None if not found
1820    ///
1821    /// # 参数
1822    ///
1823    /// * `id` - 要查找的资源的ID
1824    ///
1825    /// # 返回值
1826    ///
1827    /// 渲染列表中的资源索引,如果没有找到则为None
1828    pub fn get_render_layer_resource(&self, id: &RustConstructorId) -> Option<usize> {
1829        self.render_layer.iter().position(|x| &x.0 == id)
1830    }
1831
1832    /// Check whether the resource has obtained the mouse focus.
1833    ///
1834    /// 检查资源是否获取鼠标焦点。
1835    ///
1836    /// Use this method to ensure that mouse operations do not trigger
1837    /// multiple components simultaneously, causing confusion.
1838    ///
1839    /// 使用此方法以保证鼠标操作不会同时触发多个组件产生混乱。
1840    ///
1841    /// # Arguments
1842    ///
1843    /// * `index` - The index value of the rendering resource
1844    /// * `mouse_pos` - The position of the mouse
1845    /// * `need_contains_mouse` - Is it necessary to include the mouse position
1846    /// * `ignore_render_layer` - The range of indices to ignore in the render layer
1847    ///
1848    /// # Returns
1849    ///
1850    /// Return true if the resource is not blocked; otherwise, return false.
1851    ///
1852    /// # 参数
1853    ///
1854    /// * `index` - 渲染资源的索引值
1855    /// * `mouse_pos` - 鼠标的位置
1856    /// * `need_contains_mouse` - 是否需要包含鼠标位置
1857    /// * `ignore_render_layer` - 要忽略的渲染层索引范围
1858    ///
1859    /// # 返回值
1860    ///
1861    /// 如果资源未被阻挡,返回true,否则返回false。
1862    pub fn resource_get_focus(
1863        &self,
1864        index: usize,
1865        mouse_pos: [f32; 2],
1866        need_contains_mouse: bool,
1867        ignore_render_layer: Vec<[usize; 2]>,
1868    ) -> bool {
1869        let mut ignore_list = Vec::new();
1870        for range in ignore_render_layer {
1871            for i in 0..range[1] {
1872                ignore_list.push(range[0] + i);
1873            }
1874        }
1875        for i in index + 1..self.render_layer.len() {
1876            let point = self.render_layer[i].1;
1877            if mouse_pos[0] >= point[0][0]
1878                && mouse_pos[1] >= point[0][1]
1879                && mouse_pos[0] <= point[1][0]
1880                && mouse_pos[1] <= point[1][1]
1881                && !self.render_layer[i].2
1882                && !ignore_list.contains(&i)
1883            {
1884                return false;
1885            };
1886        }
1887        let target_point = self.render_layer[index].1;
1888        !need_contains_mouse
1889            || mouse_pos[0] <= target_point[1][0]
1890                && mouse_pos[0] >= target_point[0][0]
1891                && mouse_pos[1] <= target_point[1][1]
1892                && mouse_pos[1] >= target_point[0][1]
1893    }
1894
1895    /// Mark active resources.
1896    ///
1897    /// 标记活跃资源。
1898    ///
1899    /// This method will be automatically called by the Rust Constructor without
1900    /// the need for manual control.
1901    ///
1902    /// 此方法会被Rust Constructor自动调用,无需手动控制。
1903    ///
1904    /// # Arguments
1905    ///
1906    /// * `id` - The unique identifier of the resource
1907    ///
1908    /// # Returns
1909    ///
1910    /// When a success mark is made, return `Ok(())`, and when the resource is not found,
1911    /// return `Err(RustConstructorError)`.
1912    ///
1913    /// # 参数
1914    ///
1915    /// * `id` - 资源的唯一标识符
1916    ///
1917    /// # 返回值
1918    ///
1919    /// 成功标记时返回`Ok(())`,找不到资源时返回`Err(RustConstructorError)`。
1920    pub fn add_active_resource(
1921        &mut self,
1922        id: &RustConstructorId,
1923    ) -> Result<(), RustConstructorError> {
1924        self.active_list.push((
1925            id.clone(),
1926            if let [Some(citer_name), Some(citer_type)] = [
1927                get_tag("citer_name", &self.get_box_resource(id)?.display_tags()),
1928                get_tag("citer_type", &self.get_box_resource(id)?.display_tags()),
1929            ] {
1930                Some(RustConstructorId {
1931                    name: citer_name.1,
1932                    discern_type: citer_type.1,
1933                })
1934            } else {
1935                None
1936            },
1937        ));
1938        Ok(())
1939    }
1940
1941    /// Adds a new resource to the application with the specified name.
1942    ///
1943    /// 添加一个新资源到应用程序中,并指定名称。
1944    ///
1945    /// This method registers a resource instance with a unique name. If the name is already in use
1946    /// or invalid, an error is returned. For certain resource types like SplitTime, it automatically
1947    /// initializes time values.
1948    ///
1949    /// 此方法使用唯一名称注册资源实例。如果名称已存在或无效,则返回错误。
1950    /// 对于某些资源类型(如 SplitTime),它会自动初始化时间值。
1951    ///
1952    /// # Arguments
1953    ///
1954    /// * `name` - A unique identifier for the resource
1955    /// * `resource` - The resource instance to add
1956    ///
1957    /// # Returns
1958    ///
1959    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be added.
1960    ///
1961    /// # 参数
1962    ///
1963    /// * `name` - 资源的唯一标识符
1964    /// * `resource` - 要添加的资源实例
1965    ///
1966    /// # 返回值
1967    ///
1968    /// 成功时返回 `Ok(())`,如果资源无法添加则返回 `Err(RustConstructorError)`。
1969    pub fn add_resource<T: RustConstructorResource + 'static>(
1970        &mut self,
1971        name: &str,
1972        mut resource: T,
1973    ) -> Result<(), RustConstructorError> {
1974        let discern_type = &*type_processor(&resource);
1975        if self
1976            .check_resource_exists(&RustConstructorId {
1977                name: name.to_string(),
1978                discern_type: discern_type.to_string(),
1979            })
1980            .is_some()
1981        {
1982            return Err(RustConstructorError {
1983                error_id: "ResourceNameRepetition".to_string(),
1984                description: format!("Resource '{name}({discern_type})' has already existed."),
1985            });
1986        };
1987        if name.is_empty() {
1988            return Err(RustConstructorError {
1989                error_id: "ResourceUntitled".to_string(),
1990                description: "All resources must have a valid name.".to_string(),
1991            });
1992        };
1993        match discern_type {
1994            "SplitTime" => {
1995                let split_time = downcast_resource_mut::<SplitTime>(&mut resource)?;
1996                split_time.time = [self.timer.now_time, self.timer.total_time];
1997            }
1998            "Background" => {
1999                let background = downcast_resource_mut::<Background>(&mut resource)?;
2000                match &background.background_type {
2001                    BackgroundType::CustomRect(config) => {
2002                        let mut custom_rect = CustomRect::default().from_config(config);
2003                        if background.use_background_tags {
2004                            custom_rect.modify_tags(&background.tags, false);
2005                        };
2006                        self.add_resource(name, custom_rect)
2007                    }
2008                    BackgroundType::Image(config) => {
2009                        let mut image = Image::default().from_config(config);
2010                        if background.use_background_tags {
2011                            image.modify_tags(&background.tags, false);
2012                        };
2013                        self.add_resource(name, image)
2014                    }
2015                }?;
2016            }
2017            "Switch" => {
2018                let switch = downcast_resource_mut::<Switch>(&mut resource)?;
2019                let count = 1 + switch.enable_animation.iter().filter(|x| **x).count();
2020                if switch.appearance.len() != count * switch.state_amount as usize {
2021                    return Err(RustConstructorError {
2022                        error_id: "SwitchAppearanceConfigMismatch".to_string(),
2023                        description: format!(
2024                            "Expected {} elements, found {}.",
2025                            count * switch.state_amount as usize,
2026                            switch.appearance.len()
2027                        ),
2028                    });
2029                };
2030                if !switch.radio_group.is_empty() {
2031                    if !self.rust_constructor_resource.iter().any(|x| {
2032                        if let Ok(check_switch) = downcast_resource::<Switch>(&*x.content) {
2033                            switch.radio_group == check_switch.radio_group
2034                        } else {
2035                            false
2036                        }
2037                    }) {
2038                        switch.state = 1;
2039                    };
2040                    if switch.state_amount != 2 {
2041                        return Err(RustConstructorError {
2042                            error_id: "SwitchAppearanceConfigMismatch".to_string(),
2043                            description: format!(
2044                                "Radio group is only supported for switches with 2 states, found {}.",
2045                                switch.state_amount
2046                            ),
2047                        });
2048                    };
2049                };
2050                self.add_resource(
2051                    &format!("{name}Background"),
2052                    Background::default()
2053                        .background_type(&switch.background_type)
2054                        .auto_update(true)
2055                        .use_background_tags(true)
2056                        .tags(
2057                            if switch.use_switch_tags {
2058                                &switch.tags
2059                            } else {
2060                                &[]
2061                            },
2062                            false,
2063                        )
2064                        .tags(
2065                            &[
2066                                ["citer_name".to_string(), name.to_string()],
2067                                ["citer_type".to_string(), discern_type.to_string()],
2068                                ["panel_layout_group".to_string(), name.to_string()],
2069                            ],
2070                            false,
2071                        ),
2072                )?;
2073                self.add_resource(
2074                    &format!("{name}Text"),
2075                    Text::default()
2076                        .from_config(&switch.text_config)
2077                        .tags(
2078                            if switch.use_switch_tags {
2079                                &switch.tags
2080                            } else {
2081                                &[]
2082                            },
2083                            false,
2084                        )
2085                        .tags(
2086                            &[
2087                                ["citer_name".to_string(), name.to_string()],
2088                                ["citer_type".to_string(), discern_type.to_string()],
2089                                ["panel_layout_group".to_string(), name.to_string()],
2090                            ],
2091                            false,
2092                        ),
2093                )?;
2094                self.add_resource(
2095                    &format!("{name}HintText"),
2096                    Text::default()
2097                        .from_config(&switch.hint_text_config)
2098                        .ignore_render_layer(true)
2099                        .hidden(true)
2100                        .alpha(0)
2101                        .tags(
2102                            &[
2103                                ["citer_name".to_string(), name.to_string()],
2104                                ["citer_type".to_string(), discern_type.to_string()],
2105                                ["disable_x_scrolling".to_string(), "".to_string()],
2106                                ["disable_y_scrolling".to_string(), "".to_string()],
2107                            ],
2108                            false,
2109                        ),
2110                )?;
2111                self.add_resource(
2112                    &format!("{name}StartHoverTime"),
2113                    SplitTime::default().tags(
2114                        &[
2115                            ["citer_name".to_string(), name.to_string()],
2116                            ["citer_type".to_string(), discern_type.to_string()],
2117                        ],
2118                        false,
2119                    ),
2120                )?;
2121                self.add_resource(
2122                    &format!("{name}HintFadeAnimation"),
2123                    SplitTime::default().tags(
2124                        &[
2125                            ["citer_name".to_string(), name.to_string()],
2126                            ["citer_type".to_string(), discern_type.to_string()],
2127                        ],
2128                        false,
2129                    ),
2130                )?;
2131            }
2132            "ResourcePanel" => {
2133                let resource_panel = downcast_resource_mut::<ResourcePanel>(&mut resource)?;
2134                self.add_resource(
2135                    &format!("{name}Background"),
2136                    Background::default()
2137                        .background_type(&resource_panel.background)
2138                        .auto_update(true)
2139                        .use_background_tags(true)
2140                        .tags(
2141                            &[
2142                                ["citer_name".to_string(), name.to_string()],
2143                                ["citer_type".to_string(), discern_type.to_string()],
2144                            ],
2145                            false,
2146                        ),
2147                )?;
2148                if let ScrollBarDisplayMethod::Always(_, _, _) =
2149                    &resource_panel.scroll_bar_display_method
2150                {
2151                    self.add_resource(
2152                        &format!("{name}XScroll"),
2153                        Background::default()
2154                            .auto_update(true)
2155                            .use_background_tags(true)
2156                            .tags(
2157                                &[
2158                                    ["citer_name".to_string(), name.to_string()],
2159                                    ["citer_type".to_string(), discern_type.to_string()],
2160                                ],
2161                                false,
2162                            ),
2163                    )?;
2164                    self.add_resource(
2165                        &format!("{name}YScroll"),
2166                        Background::default()
2167                            .auto_update(true)
2168                            .use_background_tags(true)
2169                            .tags(
2170                                &[
2171                                    ["citer_name".to_string(), name.to_string()],
2172                                    ["citer_type".to_string(), discern_type.to_string()],
2173                                ],
2174                                false,
2175                            ),
2176                    )?;
2177                };
2178                if let ScrollBarDisplayMethod::OnlyScroll(_, _, _) =
2179                    &resource_panel.scroll_bar_display_method
2180                {
2181                    self.add_resource(
2182                        &format!("{name}XScroll"),
2183                        Background::default()
2184                            .auto_update(true)
2185                            .use_background_tags(true)
2186                            .tags(
2187                                &[
2188                                    ["citer_name".to_string(), name.to_string()],
2189                                    ["citer_type".to_string(), discern_type.to_string()],
2190                                ],
2191                                false,
2192                            ),
2193                    )?;
2194                    self.add_resource(
2195                        &format!("{name}YScroll"),
2196                        Background::default()
2197                            .auto_update(true)
2198                            .use_background_tags(true)
2199                            .tags(
2200                                &[
2201                                    ["citer_name".to_string(), name.to_string()],
2202                                    ["citer_type".to_string(), discern_type.to_string()],
2203                                ],
2204                                false,
2205                            ),
2206                    )?;
2207                    self.add_resource(
2208                        &format!("{name}ScrollBarXAlpha"),
2209                        SplitTime::default().tags(
2210                            &[
2211                                ["citer_name".to_string(), name.to_string()],
2212                                ["citer_type".to_string(), discern_type.to_string()],
2213                            ],
2214                            false,
2215                        ),
2216                    )?;
2217                    self.add_resource(
2218                        &format!("{name}ScrollBarXAlphaStart"),
2219                        SplitTime::default().tags(
2220                            &[
2221                                ["citer_name".to_string(), name.to_string()],
2222                                ["citer_type".to_string(), discern_type.to_string()],
2223                            ],
2224                            false,
2225                        ),
2226                    )?;
2227                    self.add_resource(
2228                        &format!("{name}ScrollBarYAlpha"),
2229                        SplitTime::default().tags(
2230                            &[
2231                                ["citer_name".to_string(), name.to_string()],
2232                                ["citer_type".to_string(), discern_type.to_string()],
2233                            ],
2234                            false,
2235                        ),
2236                    )?;
2237                    self.add_resource(
2238                        &format!("{name}ScrollBarYAlphaStart"),
2239                        SplitTime::default().tags(
2240                            &[
2241                                ["citer_name".to_string(), name.to_string()],
2242                                ["citer_type".to_string(), discern_type.to_string()],
2243                            ],
2244                            false,
2245                        ),
2246                    )?;
2247                };
2248            }
2249            _ => {}
2250        };
2251        self.rust_constructor_resource
2252            .push(RustConstructorResourceBox::new(
2253                name,
2254                discern_type,
2255                Box::new(resource),
2256            ));
2257        Ok(())
2258    }
2259
2260    /// Removes a resource from the application. This method is very dangerous! Ensure the resource is no longer in use before deletion.
2261    ///
2262    /// 移除资源。此方法非常危险!务必确保资源一定不再使用后删除。
2263    ///
2264    /// # Arguments
2265    ///
2266    /// * `id` - The unique identifier of the resource
2267    ///
2268    /// # Returns
2269    ///
2270    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
2271    ///
2272    /// # 参数
2273    ///
2274    /// * `id` - 资源的唯一标识符
2275    ///
2276    /// # 返回值
2277    ///
2278    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
2279    pub fn drop_resource(&mut self, id: &RustConstructorId) -> Result<(), RustConstructorError> {
2280        if let Some(index) = self.check_resource_exists(id) {
2281            self.rust_constructor_resource.remove(index);
2282            if let Some(index) = self.active_list.iter().position(|x| &x.0 == id) {
2283                self.active_list.remove(index);
2284            };
2285            if let Some(index) = self
2286                .render_layer
2287                .iter()
2288                .position(|x| x.0.name == id.name && x.0.discern_type == id.discern_type)
2289            {
2290                self.render_layer.remove(index);
2291            };
2292            Ok(())
2293        } else {
2294            Err(RustConstructorError {
2295                error_id: "ResourceNotFound".to_string(),
2296                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2297            })
2298        }
2299    }
2300
2301    /// Replaces an existing resource with a new one in the application.
2302    ///
2303    /// 用应用程序中的新资源替换现有资源。
2304    ///
2305    /// # Arguments
2306    ///
2307    /// * `name` - The name of the resource to replace
2308    /// * `resource` - The new resource instance
2309    ///
2310    /// # Returns
2311    ///
2312    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found or replaced.
2313    ///
2314    /// # 参数
2315    ///
2316    /// * `name` - 要替换的资源名称
2317    /// * `resource` - 新的资源实例
2318    ///
2319    /// # 返回值
2320    ///
2321    /// 成功时返回 `Ok(())`,如果资源无法找到或替换则返回 `Err(RustConstructorError)`。
2322    pub fn replace_resource<T>(
2323        &mut self,
2324        name: &str,
2325        resource: T,
2326    ) -> Result<(), RustConstructorError>
2327    where
2328        T: RustConstructorResource + 'static,
2329    {
2330        let discern_type = &*type_processor(&resource);
2331        if let Some(index) = self.check_resource_exists(&RustConstructorId {
2332            name: name.to_string(),
2333            discern_type: discern_type.to_string(),
2334        }) {
2335            self.rust_constructor_resource[index] =
2336                RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
2337            Ok(())
2338        } else {
2339            Err(RustConstructorError {
2340                error_id: "ResourceNotFound".to_string(),
2341                description: format!("Resource '{name}({discern_type})' not found."),
2342            })
2343        }
2344    }
2345
2346    /// Obtain basic front resource from the list.
2347    ///
2348    /// 从列表中获取基本前端资源。
2349    ///
2350    /// If you want to use the basic front resource method, please call this method to retrieve the resource.
2351    ///
2352    /// 如果想要使用基本前端资源的方法,请调用此方法来取出资源。
2353    ///
2354    /// # Arguments
2355    ///
2356    /// * `id` - The unique identifier of the resource
2357    ///
2358    /// # Returns
2359    ///
2360    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2361    ///
2362    /// # 参数
2363    ///
2364    /// * `id` - 资源的唯一标识符
2365    ///
2366    /// # 返回值
2367    ///
2368    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2369    pub fn get_basic_front_resource(
2370        &self,
2371        id: &RustConstructorId,
2372    ) -> Result<&dyn BasicFrontResource, RustConstructorError> {
2373        match &*id.discern_type {
2374            "Image" => Ok(downcast_resource::<Image>(self.get_box_resource(id)?)?),
2375            "Text" => Ok(downcast_resource::<Text>(self.get_box_resource(id)?)?),
2376            "CustomRect" => Ok(downcast_resource::<CustomRect>(self.get_box_resource(id)?)?),
2377            _ => unreachable!(),
2378        }
2379    }
2380
2381    /// Obtain mutable basic front resource from the list.
2382    ///
2383    /// 从列表中获取可变基本前端资源。
2384    ///
2385    /// If you want to use the basic front resource method and modify the basic front resource, please call
2386    /// this method to retrieve the resource.
2387    ///
2388    /// 如果想要使用基本前端资源的方法并修改基本前端资源,请调用此方法来取出资源。
2389    ///
2390    /// # Arguments
2391    ///
2392    /// * `id` - The unique identifier of the resource
2393    ///
2394    /// # Returns
2395    ///
2396    /// If the resource is found, return the mutable reference of the resource; otherwise, return `Err(RustConstructorError)`.
2397    ///
2398    /// # 参数
2399    ///
2400    /// * `id` - 资源的唯一标识符
2401    ///
2402    /// # 返回值
2403    ///
2404    /// 如果找到资源,返回资源的可变引用,否则返回`Err(RustConstructorError)`。
2405    pub fn get_basic_front_resource_mut(
2406        &mut self,
2407        id: &RustConstructorId,
2408    ) -> Result<&mut dyn BasicFrontResource, RustConstructorError> {
2409        match &*id.discern_type {
2410            "Image" => Ok(downcast_resource_mut::<Image>(
2411                self.get_box_resource_mut(id)?,
2412            )?),
2413            "Text" => Ok(downcast_resource_mut::<Text>(
2414                self.get_box_resource_mut(id)?,
2415            )?),
2416            "CustomRect" => Ok(downcast_resource_mut::<CustomRect>(
2417                self.get_box_resource_mut(id)?,
2418            )?),
2419            _ => unreachable!(),
2420        }
2421    }
2422
2423    /// Obtain the boxed immutable resources from the list.
2424    ///
2425    /// 从列表中获取封装的不可变资源。
2426    ///
2427    /// If you need to use a resource without knowing its type, please use this method to retrieve the resource.
2428    ///
2429    /// 如果需要在不知道类型的情况下使用资源,请使用此方法取出资源。
2430    ///
2431    /// # Arguments
2432    ///
2433    /// * `id` - The unique identifier of the resource
2434    ///
2435    /// # Returns
2436    ///
2437    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2438    ///
2439    /// # 参数
2440    ///
2441    /// * `id` - 资源的唯一标识符
2442    ///
2443    /// # 返回值
2444    ///
2445    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2446    pub fn get_box_resource(
2447        &self,
2448        id: &RustConstructorId,
2449    ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
2450        if let Some(index) = self.check_resource_exists(id) {
2451            Ok(&*self.rust_constructor_resource[index].content)
2452        } else {
2453            Err(RustConstructorError {
2454                error_id: "ResourceNotFound".to_string(),
2455                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2456            })
2457        }
2458    }
2459
2460    /// Obtain the boxed mutable resources from the list.
2461    ///
2462    /// 从列表中获取封装的可变资源。
2463    ///
2464    /// If you need to use a resource without knowing its type, please use this method to retrieve the resource.
2465    ///
2466    /// 如果需要在不知道类型的情况下使用资源,请使用此方法取出资源。
2467    ///
2468    /// # Arguments
2469    ///
2470    /// * `id` - The unique identifier of the resource
2471    ///
2472    /// # Returns
2473    ///
2474    /// If the resource is found, return the mutable reference of the resource; otherwise, return `Err(RustConstructorError)`.
2475    ///
2476    /// # 参数
2477    ///
2478    /// * `id` - 资源的唯一标识符
2479    ///
2480    /// # 返回值
2481    ///
2482    /// 如果找到资源,返回资源的可变引用,否则返回`Err(RustConstructorError)`。
2483    pub fn get_box_resource_mut(
2484        &mut self,
2485        id: &RustConstructorId,
2486    ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
2487        if let Some(index) = self.check_resource_exists(id) {
2488            Ok(&mut *self.rust_constructor_resource[index].content)
2489        } else {
2490            Err(RustConstructorError {
2491                error_id: "ResourceNotFound".to_string(),
2492                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2493            })
2494        }
2495    }
2496
2497    /// Obtain the immutable resources from the list.
2498    ///
2499    /// 从列表中获取不可变资源。
2500    ///
2501    /// # Arguments
2502    ///
2503    /// * `id` - The unique identifier of the resource
2504    ///
2505    /// # Returns
2506    ///
2507    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2508    ///
2509    /// # 参数
2510    ///
2511    /// * `id` - 资源的唯一标识符
2512    ///
2513    /// # 返回值
2514    ///
2515    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2516    pub fn get_resource<T>(&self, id: &RustConstructorId) -> Result<&T, RustConstructorError>
2517    where
2518        T: RustConstructorResource + 'static,
2519    {
2520        downcast_resource(self.get_box_resource(id)?)
2521    }
2522
2523    /// Obtain the mutable resources from the list.
2524    ///
2525    /// 从列表中获取可变资源。
2526    ///
2527    /// # Arguments
2528    ///
2529    /// * `id` - The unique identifier of the resource
2530    ///
2531    /// # Returns
2532    ///
2533    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2534    ///
2535    /// # 参数
2536    ///
2537    /// * `id` - 资源的唯一标识符
2538    ///
2539    /// # 返回值
2540    ///
2541    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2542    pub fn get_resource_mut<T>(
2543        &mut self,
2544        id: &RustConstructorId,
2545    ) -> Result<&mut T, RustConstructorError>
2546    where
2547        T: RustConstructorResource + 'static,
2548    {
2549        downcast_resource_mut(self.get_box_resource_mut(id)?)
2550    }
2551
2552    /// Checks if a specific resource exists in the application.
2553    ///
2554    /// 检查应用程序中是否存在特定资源。
2555    ///
2556    /// # Arguments
2557    ///
2558    /// * `id` - The unique identifier of the resource
2559    ///
2560    /// # Returns
2561    ///
2562    /// Returns `Some(index)` if the resource exists, or `None` if not found.
2563    ///
2564    /// # 参数
2565    ///
2566    /// * `id` - 资源的唯一标识符
2567    ///
2568    /// # 返回值
2569    ///
2570    /// 如果资源存在则返回 `Some(索引)`,否则返回 `None`。
2571    pub fn check_resource_exists(&self, id: &RustConstructorId) -> Option<usize> {
2572        self.rust_constructor_resource
2573            .iter()
2574            .position(|x| &x.id == id)
2575    }
2576
2577    /// Quickly adds and uses a resource in one operation.
2578    ///
2579    /// 快速添加并使用资源。
2580    ///
2581    /// This method combines adding a resource to the application and immediately using it.
2582    ///
2583    /// 此方法将资源添加到应用程序并立即使用它。
2584    ///
2585    /// # Arguments
2586    ///
2587    /// * `name` - The name for the resource
2588    /// * `resource` - The resource instance to add and draw
2589    /// * `ui` - The UI context for drawing
2590    /// * `ctx` - The rendering context
2591    ///
2592    /// # Returns
2593    ///
2594    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be added or drawn.
2595    ///
2596    /// # 参数
2597    ///
2598    /// * `name` - 资源的名称
2599    /// * `resource` - 要添加和绘制的资源实例
2600    /// * `ui` - 用于绘制的UI上下文
2601    /// * `ctx` - 渲染上下文
2602    ///
2603    /// # 返回值
2604    ///
2605    /// 成功时返回 `Ok(())`,如果资源无法添加或绘制则返回 `Err(RustConstructorError)`。
2606    pub fn quick_place<T: RustConstructorResource + 'static>(
2607        &mut self,
2608        name: &str,
2609        resource: T,
2610        ui: &mut Ui,
2611        ctx: &Context,
2612    ) -> Result<(), RustConstructorError> {
2613        let discern_type = &*type_processor(&resource);
2614        if self
2615            .check_resource_exists(&RustConstructorId {
2616                name: name.to_string(),
2617                discern_type: discern_type.to_string(),
2618            })
2619            .is_none()
2620        {
2621            self.add_resource(name, resource)
2622        } else {
2623            self.use_resource(
2624                &RustConstructorId {
2625                    name: name.to_string(),
2626                    discern_type: discern_type.to_string(),
2627                },
2628                ui,
2629                ctx,
2630            )
2631        }
2632    }
2633
2634    /// Use the existing resources.
2635    ///
2636    /// 使用已存在的资源。
2637    ///
2638    /// This method invokes existing resources and performs operations.
2639    ///
2640    /// 此方法调用存在的资源并进行操作。
2641    ///
2642    /// # Arguments
2643    ///
2644    /// * `id` - The unique identifier of the resource
2645    /// * `ui` - The UI context for drawing
2646    /// * `ctx` - The rendering context
2647    ///
2648    /// # Returns
2649    ///
2650    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be handled.
2651    ///
2652    /// # 参数
2653    ///
2654    /// * `id` - 资源的唯一标识符
2655    /// * `ui` - 用于绘制的UI上下文
2656    /// * `ctx` - 渲染上下文
2657    ///
2658    /// # 返回值
2659    ///
2660    /// 成功时返回 `Ok(())`,如果资源无法处理则返回 `Err(RustConstructorError)`。
2661    pub fn use_resource(
2662        &mut self,
2663        id: &RustConstructorId,
2664        ui: &mut Ui,
2665        ctx: &Context,
2666    ) -> Result<(), RustConstructorError> {
2667        if self.check_resource_exists(id).is_some() {
2668            match &*id.discern_type {
2669                "CustomRect" | "Text" | "Image" => {
2670                    self.add_active_resource(id)?;
2671                }
2672                "PageData" => {
2673                    // 更新帧数
2674                    self.update_frame_stats();
2675                    // 更新渲染队列。
2676                    self.update_render_list();
2677                    // 绘制渲染队列中的资源。
2678                    for i in 0..self.render_list.len() {
2679                        self.draw_resource_by_index(ui, ctx, i)?;
2680                    }
2681                    // 更新渲染列表。
2682                    self.update_render_layer(ctx)?;
2683                    // 更新资源活跃状态。
2684                    self.active_list.clear();
2685                    // 更新字体加载情况。
2686                    if !self.loading_fonts.is_empty() {
2687                        self.loaded_fonts = self.loading_fonts.clone();
2688                        self.loading_fonts.clear();
2689                    };
2690                    // 更新资源启用状态。
2691                    for rcr in &mut self.rust_constructor_resource {
2692                        if let Some(display_info) = &mut rcr.content.display_display_info() {
2693                            rcr.content.modify_display_info(DisplayInfo {
2694                                enable: true,
2695                                hidden: display_info.hidden,
2696                                ignore_render_layer: display_info.ignore_render_layer,
2697                            });
2698                        };
2699                    }
2700                    // 更新计时器
2701                    self.update_timer();
2702                    let page_data = self.get_resource::<PageData>(&RustConstructorId {
2703                        name: self.current_page.clone(),
2704                        discern_type: "PageData".to_string(),
2705                    })?;
2706                    if page_data.forced_update {
2707                        ctx.request_repaint();
2708                    };
2709                }
2710                "Background" => {
2711                    let background = self.get_resource::<Background>(id)?.clone();
2712                    if background.auto_update {
2713                        match &background.background_type {
2714                            BackgroundType::CustomRect(config) => {
2715                                let mut custom_rect = self
2716                                    .get_resource::<CustomRect>(&RustConstructorId {
2717                                        name: id.name.clone(),
2718                                        discern_type: "CustomRect".to_string(),
2719                                    })?
2720                                    .clone()
2721                                    .from_config(config);
2722                                if background.use_background_tags {
2723                                    custom_rect.modify_tags(&background.tags, false);
2724                                };
2725                                self.replace_resource(&id.name, custom_rect)?;
2726                            }
2727                            BackgroundType::Image(config) => {
2728                                let mut image = self
2729                                    .get_resource::<Image>(&RustConstructorId {
2730                                        name: id.name.clone(),
2731                                        discern_type: "Image".to_string(),
2732                                    })?
2733                                    .clone()
2734                                    .from_config(config);
2735                                if background.use_background_tags {
2736                                    image.modify_tags(&background.tags, false);
2737                                };
2738                                self.replace_resource(&id.name, image)?;
2739                            }
2740                        };
2741                    };
2742                    match background.background_type {
2743                        BackgroundType::CustomRect(_) => self.use_resource(
2744                            &RustConstructorId {
2745                                name: id.name.clone(),
2746                                discern_type: "CustomRect".to_string(),
2747                            },
2748                            ui,
2749                            ctx,
2750                        ),
2751                        BackgroundType::Image(_) => self.use_resource(
2752                            &RustConstructorId {
2753                                name: id.name.clone(),
2754                                discern_type: "Image".to_string(),
2755                            },
2756                            ui,
2757                            ctx,
2758                        ),
2759                    }?;
2760                }
2761                "Switch" => {
2762                    let mut switch = self.get_resource::<Switch>(id)?.clone();
2763                    let mut background = self
2764                        .get_resource::<Background>(&RustConstructorId {
2765                            name: format!("{}Background", &id.name),
2766                            discern_type: "Background".to_string(),
2767                        })?
2768                        .clone();
2769                    let background_resource_type = match switch.background_type {
2770                        BackgroundType::CustomRect(_) => "CustomRect",
2771                        BackgroundType::Image(_) => "Image",
2772                    };
2773                    let background_resource =
2774                        self.get_basic_front_resource(&RustConstructorId {
2775                            name: format!("{}Background", &id.name),
2776                            discern_type: background_resource_type.to_string(),
2777                        })?;
2778                    let display_info = background_resource.display_display_info();
2779                    let mut text = self
2780                        .get_resource::<Text>(&RustConstructorId {
2781                            name: format!("{}Text", &id.name),
2782                            discern_type: "Text".to_string(),
2783                        })?
2784                        .clone();
2785                    let mut hint_text = self
2786                        .get_resource::<Text>(&RustConstructorId {
2787                            name: format!("{}HintText", &id.name),
2788                            discern_type: "Text".to_string(),
2789                        })?
2790                        .clone();
2791                    switch.switched = false;
2792                    let animation_count =
2793                        1 + switch.enable_animation.iter().filter(|x| **x).count();
2794                    let mut clicked = None;
2795                    let mut hovered = false;
2796                    let mut appearance_count = 0;
2797                    // 处理点击事件
2798                    if let Some(index) = self.get_render_layer_resource(&RustConstructorId {
2799                        name: format!("{}Background", &id.name),
2800                        discern_type: background_resource_type.to_string(),
2801                    }) && switch.enable
2802                        && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
2803                        && self.resource_get_focus(index, mouse_pos.into(), true, vec![])
2804                        && let Some(display_info) = background_resource.display_display_info()
2805                        && !display_info.hidden
2806                    {
2807                        if !switch.last_frame_hovered {
2808                            self.reset_split_time(&format!("{}StartHoverTime", &id.name))?;
2809                        } else if self.timer.total_time
2810                            - self.get_split_time(&format!("{}StartHoverTime", &id.name))?[1]
2811                            >= 2000
2812                            || hint_text.alpha != 0
2813                        {
2814                            hint_text.alpha = 255;
2815                            hint_text
2816                                .basic_front_resource_config
2817                                .position_size_config
2818                                .origin_position = [mouse_pos.x, mouse_pos.y];
2819                        };
2820                        hint_text
2821                            .basic_front_resource_config
2822                            .position_size_config
2823                            .display_method
2824                            .0 = if mouse_pos.x + hint_text.actual_size[0]
2825                            <= ctx.available_rect().width()
2826                        {
2827                            HorizontalAlign::Left
2828                        } else {
2829                            HorizontalAlign::Right
2830                        };
2831                        hint_text
2832                            .basic_front_resource_config
2833                            .position_size_config
2834                            .display_method
2835                            .1 = if mouse_pos.y + hint_text.actual_size[1]
2836                            <= ctx.available_rect().height()
2837                        {
2838                            VerticalAlign::Top
2839                        } else {
2840                            VerticalAlign::Bottom
2841                        };
2842                        hovered = true;
2843                        for (count, click_method) in switch.click_method.iter().enumerate() {
2844                            if ui.input(|i| {
2845                                switch.last_frame_clicked.is_none()
2846                                    && i.pointer.button_pressed(click_method.click_method)
2847                                    || switch.last_frame_clicked.is_some()
2848                                        && i.pointer.button_down(click_method.click_method)
2849                            }) {
2850                                clicked = Some(count);
2851                                break;
2852                            };
2853                        }
2854                        if let Some(clicked_index) = switch.last_frame_clicked
2855                            && clicked.is_none()
2856                        {
2857                            switch.switched = true;
2858                            if switch.click_method[clicked_index].action {
2859                                if !switch.radio_group.is_empty() {
2860                                    self.rust_constructor_resource
2861                                        .iter_mut()
2862                                        .filter(|x| &x.id.discern_type == "Switch")
2863                                        .for_each(|x| {
2864                                            if let Ok(check_switch) =
2865                                                downcast_resource_mut::<Switch>(&mut *x.content)
2866                                                && switch.radio_group == check_switch.radio_group
2867                                            {
2868                                                check_switch.state = 0;
2869                                            };
2870                                        });
2871                                };
2872                                if switch.radio_group.is_empty() || switch.state == 0 {
2873                                    if switch.state < switch.appearance.len() / animation_count - 1
2874                                    {
2875                                        switch.state += 1;
2876                                    } else {
2877                                        switch.state = 0;
2878                                    };
2879                                }
2880                            };
2881                        };
2882                        appearance_count = if clicked.is_some() {
2883                            match switch.enable_animation {
2884                                [true, true] => 2,
2885                                [true, false] | [false, true] => 1,
2886                                [false, false] => 0,
2887                            }
2888                        } else if switch.enable_animation[0] {
2889                            1
2890                        } else {
2891                            0
2892                        };
2893                    };
2894
2895                    // 若鼠标未悬挂在开关上,逐渐隐藏提示文本
2896                    if !hovered {
2897                        if switch.last_frame_hovered {
2898                            self.reset_split_time(&format!("{}HintFadeAnimation", &id.name))?;
2899                        };
2900                        if self.timer.total_time
2901                            - self.get_split_time(&format!("{}HintFadeAnimation", &id.name))?[1]
2902                            >= self.tick_interval
2903                        {
2904                            self.reset_split_time(&format!("{}HintFadeAnimation", &id.name))?;
2905                            hint_text.alpha = hint_text.alpha.saturating_sub(10);
2906                        };
2907                    };
2908
2909                    hint_text.display_info.hidden = hint_text.alpha == 0;
2910
2911                    // 更新Background样式。
2912                    background.background_type = switch.appearance
2913                        [switch.state * animation_count + appearance_count]
2914                        .background_config
2915                        .clone();
2916
2917                    background.modify_tags(
2918                        if switch.use_switch_tags {
2919                            &switch.tags
2920                        } else {
2921                            &[]
2922                        },
2923                        false,
2924                    );
2925
2926                    // 刷新提示Text。
2927                    let alpha = hint_text.alpha;
2928                    hint_text = hint_text
2929                        .from_config(
2930                            &switch.appearance[switch.state * animation_count + appearance_count]
2931                                .hint_text_config,
2932                        )
2933                        .ignore_render_layer(true);
2934                    hint_text.background_alpha = alpha;
2935                    hint_text.alpha = alpha;
2936                    hint_text.display_info.hidden = if let Some(display_info) = display_info
2937                        && display_info.hidden
2938                    {
2939                        true
2940                    } else {
2941                        hint_text.display_info.hidden
2942                    };
2943
2944                    // 更新Text样式。
2945                    text = text
2946                        .tags(
2947                            if switch.use_switch_tags {
2948                                &switch.tags
2949                            } else {
2950                                &[]
2951                            },
2952                            false,
2953                        )
2954                        .from_config(
2955                            &switch.appearance[switch.state * animation_count + appearance_count]
2956                                .text_config,
2957                        );
2958
2959                    switch.last_frame_hovered = hovered;
2960                    switch.last_frame_clicked = clicked;
2961
2962                    self.replace_resource(&format!("{}Text", &id.name), text)?;
2963                    self.replace_resource(&format!("{}HintText", &id.name), hint_text)?;
2964                    self.replace_resource(&id.name, switch)?;
2965                    self.replace_resource(&format!("{}Background", &id.name), background)?;
2966
2967                    self.use_resource(
2968                        &RustConstructorId {
2969                            name: format!("{}Background", &id.name),
2970                            discern_type: "Background".to_string(),
2971                        },
2972                        ui,
2973                        ctx,
2974                    )?;
2975                    self.use_resource(
2976                        &RustConstructorId {
2977                            name: format!("{}Text", &id.name),
2978                            discern_type: "Text".to_string(),
2979                        },
2980                        ui,
2981                        ctx,
2982                    )?;
2983                    if alpha != 0 {
2984                        self.try_request_jump_render_list(
2985                            RequestMethod::Id(RustConstructorId {
2986                                name: format!("{}HintText", &id.name),
2987                                discern_type: "Text".to_string(),
2988                            }),
2989                            RequestType::Top,
2990                        );
2991                        self.use_resource(
2992                            &RustConstructorId {
2993                                name: format!("{}HintText", &id.name),
2994                                discern_type: "Text".to_string(),
2995                            },
2996                            ui,
2997                            ctx,
2998                        )?;
2999                    };
3000                }
3001                "ResourcePanel" => {
3002                    let mut resource_panel = self
3003                        .get_resource::<ResourcePanel>(&RustConstructorId {
3004                            name: id.name.clone(),
3005                            discern_type: "ResourcePanel".to_string(),
3006                        })?
3007                        .clone();
3008                    let background = self
3009                        .get_resource::<Background>(&RustConstructorId {
3010                            name: format!("{}Background", &id.name),
3011                            discern_type: "Background".to_string(),
3012                        })?
3013                        .clone();
3014                    let background_resource: Box<dyn BasicFrontResource> =
3015                        match background.background_type.clone() {
3016                            BackgroundType::CustomRect(_) => Box::new(
3017                                self.get_resource::<CustomRect>(&RustConstructorId {
3018                                    name: format!("{}Background", &id.name),
3019                                    discern_type: "CustomRect".to_string(),
3020                                })?
3021                                .clone(),
3022                            ),
3023                            BackgroundType::Image(_) => Box::new(
3024                                self.get_resource::<Image>(&RustConstructorId {
3025                                    name: format!("{}Background", &id.name),
3026                                    discern_type: "Image".to_string(),
3027                                })?
3028                                .clone(),
3029                            ),
3030                        };
3031                    let (mut position_size_config, mut position, mut size) = (
3032                        background_resource
3033                            .display_basic_front_resource_config()
3034                            .position_size_config,
3035                        background_resource.display_position(),
3036                        background_resource.display_size(),
3037                    );
3038                    let rect = Rect::from_min_size(position.into(), size.into());
3039                    resource_panel.scrolled = [false, false];
3040                    if resource_panel.resizable.contains(&true)
3041                        || resource_panel.movable.contains(&true)
3042                    {
3043                        position_size_config.x_location_grid = [0_f32, 0_f32];
3044                        position_size_config.y_location_grid = [0_f32, 0_f32];
3045                        position_size_config.x_size_grid = [0_f32, 0_f32];
3046                        position_size_config.y_size_grid = [0_f32, 0_f32];
3047                        position_size_config.display_method =
3048                            (HorizontalAlign::Left, VerticalAlign::Top);
3049                    };
3050                    if resource_panel.min_size[0] < 10_f32 {
3051                        resource_panel.min_size[0] = 10_f32;
3052                    };
3053                    if resource_panel.min_size[1] < 10_f32 {
3054                        resource_panel.min_size[1] = 10_f32;
3055                    };
3056                    if position_size_config.origin_size[0] < resource_panel.min_size[0] {
3057                        position_size_config.origin_size[0] = resource_panel.min_size[0];
3058                    };
3059                    if position_size_config.origin_size[1] < resource_panel.min_size[1] {
3060                        position_size_config.origin_size[1] = resource_panel.min_size[1];
3061                    };
3062                    [position, size] = position_size_processor(position_size_config, ctx);
3063                    let scroll_delta: [f32; 2] = if resource_panel.use_smooth_scroll_delta {
3064                        ui.input(|i| i.smooth_scroll_delta).into()
3065                    } else {
3066                        ui.input(|i| i.raw_scroll_delta).into()
3067                    };
3068                    let [x_scroll_delta, y_scroll_delta] =
3069                        if scroll_delta[0].abs() >= scroll_delta[1].abs() {
3070                            [
3071                                if resource_panel.reverse_scroll_direction[0] {
3072                                    -scroll_delta[0]
3073                                } else {
3074                                    scroll_delta[0]
3075                                },
3076                                0_f32,
3077                            ]
3078                        } else {
3079                            [
3080                                0_f32,
3081                                if resource_panel.reverse_scroll_direction[1] {
3082                                    -scroll_delta[1]
3083                                } else {
3084                                    scroll_delta[1]
3085                                },
3086                            ]
3087                        };
3088                    let mut resource_get_focus = [false, false];
3089                    if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
3090                        && !resource_panel.hidden
3091                        && let Some(index) = self.get_render_layer_resource(&RustConstructorId {
3092                            name: format!("{}Background", &id.name),
3093                            discern_type: match background.background_type {
3094                                BackgroundType::CustomRect(_) => "CustomRect",
3095                                BackgroundType::Image(_) => "Image",
3096                            }
3097                            .to_string(),
3098                        })
3099                    {
3100                        resource_get_focus = [
3101                            self.resource_get_focus(index, mouse_pos.into(), false, vec![]),
3102                            self.resource_get_focus(
3103                                index,
3104                                mouse_pos.into(),
3105                                true,
3106                                vec![[index + 1, resource_panel.resource_storage.len()]],
3107                            ),
3108                        ];
3109                        if resource_get_focus[1] {
3110                            if resource_panel.scroll_length_method[0].is_some()
3111                                && x_scroll_delta != 0_f32
3112                            {
3113                                resource_panel.scrolled[0] = true;
3114                                resource_panel.scroll_progress[0] = if resource_panel
3115                                    .scroll_progress[0]
3116                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3117                                    > resource_panel.scroll_length[0]
3118                                {
3119                                    resource_panel.scroll_length[0]
3120                                } else if resource_panel.scroll_progress[0]
3121                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3122                                    > 0_f32
3123                                {
3124                                    resource_panel.scroll_progress[0]
3125                                        + -x_scroll_delta * resource_panel.scroll_sensitivity
3126                                } else {
3127                                    0_f32
3128                                };
3129                            };
3130                            if resource_panel.scroll_length_method[1].is_some()
3131                                && y_scroll_delta != 0_f32
3132                            {
3133                                resource_panel.scrolled[1] = true;
3134                                resource_panel.scroll_progress[1] = if resource_panel
3135                                    .scroll_progress[1]
3136                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3137                                    > resource_panel.scroll_length[1]
3138                                {
3139                                    resource_panel.scroll_length[1]
3140                                } else if resource_panel.scroll_progress[1]
3141                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3142                                    > 0_f32
3143                                {
3144                                    resource_panel.scroll_progress[1]
3145                                        + -y_scroll_delta * resource_panel.scroll_sensitivity
3146                                } else {
3147                                    0_f32
3148                                };
3149                            };
3150                            if resource_panel.raise_on_focus
3151                                && ui.input(|i| i.pointer.primary_pressed())
3152                            {
3153                                self.request_jump_render_list(
3154                                    RequestMethod::Id(RustConstructorId {
3155                                        name: format!("{}Background", &id.name),
3156                                        discern_type: match background.background_type {
3157                                            BackgroundType::CustomRect(_) => "CustomRect",
3158                                            BackgroundType::Image(_) => "Image",
3159                                        }
3160                                        .to_string(),
3161                                    }),
3162                                    RequestType::Top,
3163                                )
3164                                .unwrap();
3165                                let mut update_list = Vec::new();
3166                                for rcr in &self.rust_constructor_resource {
3167                                    if self
3168                                        .basic_front_resource_list
3169                                        .contains(&rcr.id.discern_type)
3170                                        && let Some(panel_name) =
3171                                            get_tag("panel_name", &rcr.content.display_tags())
3172                                        && panel_name.1 == id.name
3173                                    {
3174                                        update_list.push(rcr.id.clone());
3175                                    };
3176                                }
3177                                for id in update_list {
3178                                    self.try_request_jump_render_list(
3179                                        RequestMethod::Id(id),
3180                                        RequestType::Top,
3181                                    );
3182                                }
3183                                if let ScrollBarDisplayMethod::Always(ref background_type, _, _) =
3184                                    resource_panel.scroll_bar_display_method
3185                                {
3186                                    self.try_request_jump_render_list(
3187                                        RequestMethod::Id(RustConstructorId {
3188                                            name: format!("{}XScroll", &id.name),
3189                                            discern_type: match background_type {
3190                                                BackgroundType::CustomRect(_) => "CustomRect",
3191                                                BackgroundType::Image(_) => "Image",
3192                                            }
3193                                            .to_string(),
3194                                        }),
3195                                        RequestType::Top,
3196                                    );
3197                                    self.try_request_jump_render_list(
3198                                        RequestMethod::Id(RustConstructorId {
3199                                            name: format!("{}YScroll", &id.name),
3200                                            discern_type: match background_type {
3201                                                BackgroundType::CustomRect(_) => "CustomRect",
3202                                                BackgroundType::Image(_) => "Image",
3203                                            }
3204                                            .to_string(),
3205                                        }),
3206                                        RequestType::Top,
3207                                    );
3208                                };
3209                                if let ScrollBarDisplayMethod::OnlyScroll(
3210                                    ref background_type,
3211                                    _,
3212                                    _,
3213                                ) = resource_panel.scroll_bar_display_method
3214                                {
3215                                    self.try_request_jump_render_list(
3216                                        RequestMethod::Id(RustConstructorId {
3217                                            name: format!("{}XScroll", &id.name),
3218                                            discern_type: match background_type {
3219                                                BackgroundType::CustomRect(_) => "CustomRect",
3220                                                BackgroundType::Image(_) => "Image",
3221                                            }
3222                                            .to_string(),
3223                                        }),
3224                                        RequestType::Top,
3225                                    );
3226                                    self.try_request_jump_render_list(
3227                                        RequestMethod::Id(RustConstructorId {
3228                                            name: format!("{}YScroll", &id.name),
3229                                            discern_type: match background_type {
3230                                                BackgroundType::CustomRect(_) => "CustomRect",
3231                                                BackgroundType::Image(_) => "Image",
3232                                            }
3233                                            .to_string(),
3234                                        }),
3235                                        RequestType::Top,
3236                                    );
3237                                };
3238                            };
3239                        }
3240                        if resource_get_focus[0] {
3241                            let top_rect = Rect::from_min_size(
3242                                [position[0], position[1]].into(),
3243                                [size[0], 3_f32].into(),
3244                            );
3245                            let bottom_rect = Rect::from_min_size(
3246                                [position[0], position[1] + size[1] - 3_f32].into(),
3247                                [size[0], 3_f32].into(),
3248                            );
3249                            let left_rect = Rect::from_min_size(
3250                                [position[0], position[1]].into(),
3251                                [3_f32, size[1]].into(),
3252                            );
3253                            let right_rect = Rect::from_min_size(
3254                                [position[0] + size[0] - 3_f32, position[1]].into(),
3255                                [3_f32, size[1]].into(),
3256                            );
3257                            match [
3258                                top_rect.contains(mouse_pos),
3259                                bottom_rect.contains(mouse_pos),
3260                                left_rect.contains(mouse_pos),
3261                                right_rect.contains(mouse_pos),
3262                            ] {
3263                                [true, false, false, false] => {
3264                                    if resource_panel.resizable[0] {
3265                                        if resource_panel.last_frame_mouse_status.is_none()
3266                                            && ui.input(|i| i.pointer.primary_pressed())
3267                                        {
3268                                            resource_panel.last_frame_mouse_status = Some((
3269                                                mouse_pos.into(),
3270                                                ClickAim::TopResize,
3271                                                [
3272                                                    mouse_pos.x - position[0],
3273                                                    mouse_pos.y - position[1],
3274                                                ],
3275                                            ))
3276                                        };
3277                                        if size[1] > resource_panel.min_size[1]
3278                                            && (resource_panel.max_size.is_none()
3279                                                || size[1] < resource_panel.max_size.unwrap()[1])
3280                                        {
3281                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3282                                        } else if resource_panel.max_size.is_some()
3283                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3284                                        {
3285                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3286                                        } else {
3287                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3288                                        };
3289                                    };
3290                                }
3291                                [false, true, false, false] => {
3292                                    if resource_panel.resizable[1] {
3293                                        if resource_panel.last_frame_mouse_status.is_none()
3294                                            && ui.input(|i| i.pointer.primary_pressed())
3295                                        {
3296                                            resource_panel.last_frame_mouse_status = Some((
3297                                                mouse_pos.into(),
3298                                                ClickAim::BottomResize,
3299                                                [
3300                                                    mouse_pos.x - position[0],
3301                                                    mouse_pos.y - position[1],
3302                                                ],
3303                                            ))
3304                                        };
3305                                        if size[1] > resource_panel.min_size[1]
3306                                            && (resource_panel.max_size.is_none()
3307                                                || size[1] < resource_panel.max_size.unwrap()[1])
3308                                        {
3309                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3310                                        } else if resource_panel.max_size.is_some()
3311                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3312                                        {
3313                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3314                                        } else {
3315                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3316                                        };
3317                                    };
3318                                }
3319                                [false, false, true, false] => {
3320                                    if resource_panel.resizable[2] {
3321                                        if resource_panel.last_frame_mouse_status.is_none()
3322                                            && ui.input(|i| i.pointer.primary_pressed())
3323                                        {
3324                                            resource_panel.last_frame_mouse_status = Some((
3325                                                mouse_pos.into(),
3326                                                ClickAim::LeftResize,
3327                                                [
3328                                                    mouse_pos.x - position[0],
3329                                                    mouse_pos.y - position[1],
3330                                                ],
3331                                            ))
3332                                        };
3333                                        if size[0] > resource_panel.min_size[0]
3334                                            && (resource_panel.max_size.is_none()
3335                                                || size[0] < resource_panel.max_size.unwrap()[0])
3336                                        {
3337                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3338                                        } else if resource_panel.max_size.is_some()
3339                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3340                                        {
3341                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3342                                        } else {
3343                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3344                                        };
3345                                    };
3346                                }
3347                                [false, false, false, true] => {
3348                                    if resource_panel.resizable[3] {
3349                                        if resource_panel.last_frame_mouse_status.is_none()
3350                                            && ui.input(|i| i.pointer.primary_pressed())
3351                                        {
3352                                            resource_panel.last_frame_mouse_status = Some((
3353                                                mouse_pos.into(),
3354                                                ClickAim::RightResize,
3355                                                [
3356                                                    mouse_pos.x - position[0],
3357                                                    mouse_pos.y - position[1],
3358                                                ],
3359                                            ))
3360                                        };
3361                                        if size[0] > resource_panel.min_size[0]
3362                                            && (resource_panel.max_size.is_none()
3363                                                || size[0] < resource_panel.max_size.unwrap()[0])
3364                                        {
3365                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3366                                        } else if resource_panel.max_size.is_some()
3367                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3368                                        {
3369                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3370                                        } else {
3371                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3372                                        };
3373                                    };
3374                                }
3375                                [true, false, true, false] => {
3376                                    match [resource_panel.resizable[0], resource_panel.resizable[2]]
3377                                    {
3378                                        [true, true] => {
3379                                            if resource_panel.last_frame_mouse_status.is_none()
3380                                                && ui.input(|i| i.pointer.primary_pressed())
3381                                            {
3382                                                resource_panel.last_frame_mouse_status = Some((
3383                                                    mouse_pos.into(),
3384                                                    ClickAim::LeftTopResize,
3385                                                    [
3386                                                        mouse_pos.x - position[0],
3387                                                        mouse_pos.y - position[1],
3388                                                    ],
3389                                                ))
3390                                            };
3391                                            if size[0] > resource_panel.min_size[0]
3392                                                && (resource_panel.max_size.is_none()
3393                                                    || size[0]
3394                                                        < resource_panel.max_size.unwrap()[0])
3395                                                || size[1] > resource_panel.min_size[1]
3396                                                    && (resource_panel.max_size.is_none()
3397                                                        || size[1]
3398                                                            < resource_panel.max_size.unwrap()[1])
3399                                            {
3400                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3401                                            } else if resource_panel.max_size.is_some()
3402                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3403                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3404                                            {
3405                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3406                                            } else {
3407                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3408                                            };
3409                                        }
3410                                        [false, true] => {
3411                                            if resource_panel.last_frame_mouse_status.is_none()
3412                                                && ui.input(|i| i.pointer.primary_pressed())
3413                                            {
3414                                                resource_panel.last_frame_mouse_status = Some((
3415                                                    mouse_pos.into(),
3416                                                    ClickAim::LeftResize,
3417                                                    [
3418                                                        mouse_pos.x - position[0],
3419                                                        mouse_pos.y - position[1],
3420                                                    ],
3421                                                ))
3422                                            };
3423                                            if size[0] > resource_panel.min_size[0]
3424                                                && (resource_panel.max_size.is_none()
3425                                                    || size[0]
3426                                                        < resource_panel.max_size.unwrap()[0])
3427                                            {
3428                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3429                                            } else if resource_panel.max_size.is_some()
3430                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3431                                            {
3432                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3433                                            } else {
3434                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3435                                            };
3436                                        }
3437                                        [true, false] => {
3438                                            if resource_panel.last_frame_mouse_status.is_none()
3439                                                && ui.input(|i| i.pointer.primary_pressed())
3440                                            {
3441                                                resource_panel.last_frame_mouse_status = Some((
3442                                                    mouse_pos.into(),
3443                                                    ClickAim::TopResize,
3444                                                    [
3445                                                        mouse_pos.x - position[0],
3446                                                        mouse_pos.y - position[1],
3447                                                    ],
3448                                                ))
3449                                            };
3450                                            if size[1] > resource_panel.min_size[1]
3451                                                && (resource_panel.max_size.is_none()
3452                                                    || size[1]
3453                                                        < resource_panel.max_size.unwrap()[1])
3454                                            {
3455                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3456                                            } else if resource_panel.max_size.is_some()
3457                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3458                                            {
3459                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3460                                            } else {
3461                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3462                                            };
3463                                        }
3464                                        [false, false] => {}
3465                                    }
3466                                }
3467                                [false, true, false, true] => {
3468                                    match [resource_panel.resizable[1], resource_panel.resizable[3]]
3469                                    {
3470                                        [true, true] => {
3471                                            if resource_panel.last_frame_mouse_status.is_none()
3472                                                && ui.input(|i| i.pointer.primary_pressed())
3473                                            {
3474                                                resource_panel.last_frame_mouse_status = Some((
3475                                                    mouse_pos.into(),
3476                                                    ClickAim::RightBottomResize,
3477                                                    [
3478                                                        mouse_pos.x - position[0],
3479                                                        mouse_pos.y - position[1],
3480                                                    ],
3481                                                ))
3482                                            };
3483                                            if size[0] > resource_panel.min_size[0]
3484                                                && (resource_panel.max_size.is_none()
3485                                                    || size[0]
3486                                                        < resource_panel.max_size.unwrap()[0])
3487                                                || size[1] > resource_panel.min_size[1]
3488                                                    && (resource_panel.max_size.is_none()
3489                                                        || size[1]
3490                                                            < resource_panel.max_size.unwrap()[1])
3491                                            {
3492                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3493                                            } else if resource_panel.max_size.is_some()
3494                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3495                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3496                                            {
3497                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3498                                            } else {
3499                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3500                                            };
3501                                        }
3502                                        [false, true] => {
3503                                            if resource_panel.last_frame_mouse_status.is_none()
3504                                                && ui.input(|i| i.pointer.primary_pressed())
3505                                            {
3506                                                resource_panel.last_frame_mouse_status = Some((
3507                                                    mouse_pos.into(),
3508                                                    ClickAim::RightResize,
3509                                                    [
3510                                                        mouse_pos.x - position[0],
3511                                                        mouse_pos.y - position[1],
3512                                                    ],
3513                                                ))
3514                                            };
3515                                            if size[0] > resource_panel.min_size[0]
3516                                                && (resource_panel.max_size.is_none()
3517                                                    || size[0]
3518                                                        < resource_panel.max_size.unwrap()[0])
3519                                            {
3520                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3521                                            } else if resource_panel.max_size.is_some()
3522                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3523                                            {
3524                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3525                                            } else {
3526                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3527                                            };
3528                                        }
3529                                        [true, false] => {
3530                                            if resource_panel.last_frame_mouse_status.is_none()
3531                                                && ui.input(|i| i.pointer.primary_pressed())
3532                                            {
3533                                                resource_panel.last_frame_mouse_status = Some((
3534                                                    mouse_pos.into(),
3535                                                    ClickAim::BottomResize,
3536                                                    [
3537                                                        mouse_pos.x - position[0],
3538                                                        mouse_pos.y - position[1],
3539                                                    ],
3540                                                ))
3541                                            };
3542                                            if size[1] > resource_panel.min_size[1]
3543                                                && (resource_panel.max_size.is_none()
3544                                                    || size[1]
3545                                                        < resource_panel.max_size.unwrap()[1])
3546                                            {
3547                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3548                                            } else if resource_panel.max_size.is_some()
3549                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3550                                            {
3551                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3552                                            } else {
3553                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3554                                            };
3555                                        }
3556                                        [false, false] => {}
3557                                    }
3558                                }
3559                                [true, false, false, true] => {
3560                                    match [resource_panel.resizable[0], resource_panel.resizable[3]]
3561                                    {
3562                                        [true, true] => {
3563                                            if resource_panel.last_frame_mouse_status.is_none()
3564                                                && ui.input(|i| i.pointer.primary_pressed())
3565                                            {
3566                                                resource_panel.last_frame_mouse_status = Some((
3567                                                    mouse_pos.into(),
3568                                                    ClickAim::RightTopResize,
3569                                                    [
3570                                                        mouse_pos.x - position[0],
3571                                                        mouse_pos.y - position[1],
3572                                                    ],
3573                                                ))
3574                                            };
3575                                            if size[0] > resource_panel.min_size[0]
3576                                                && (resource_panel.max_size.is_none()
3577                                                    || size[0]
3578                                                        < resource_panel.max_size.unwrap()[0])
3579                                                || size[1] > resource_panel.min_size[1]
3580                                                    && (resource_panel.max_size.is_none()
3581                                                        || size[1]
3582                                                            < resource_panel.max_size.unwrap()[1])
3583                                            {
3584                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3585                                            } else if resource_panel.max_size.is_some()
3586                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3587                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3588                                            {
3589                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3590                                            } else {
3591                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3592                                            };
3593                                        }
3594                                        [false, true] => {
3595                                            if resource_panel.last_frame_mouse_status.is_none()
3596                                                && ui.input(|i| i.pointer.primary_pressed())
3597                                            {
3598                                                resource_panel.last_frame_mouse_status = Some((
3599                                                    mouse_pos.into(),
3600                                                    ClickAim::RightResize,
3601                                                    [
3602                                                        mouse_pos.x - position[0],
3603                                                        mouse_pos.y - position[1],
3604                                                    ],
3605                                                ))
3606                                            };
3607                                            if size[0] > resource_panel.min_size[0]
3608                                                && (resource_panel.max_size.is_none()
3609                                                    || size[0]
3610                                                        < resource_panel.max_size.unwrap()[0])
3611                                            {
3612                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3613                                            } else if resource_panel.max_size.is_some()
3614                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3615                                            {
3616                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3617                                            } else {
3618                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3619                                            };
3620                                        }
3621                                        [true, false] => {
3622                                            if resource_panel.last_frame_mouse_status.is_none()
3623                                                && ui.input(|i| i.pointer.primary_pressed())
3624                                            {
3625                                                resource_panel.last_frame_mouse_status = Some((
3626                                                    mouse_pos.into(),
3627                                                    ClickAim::TopResize,
3628                                                    [
3629                                                        mouse_pos.x - position[0],
3630                                                        mouse_pos.y - position[1],
3631                                                    ],
3632                                                ))
3633                                            };
3634                                            if size[1] > resource_panel.min_size[1]
3635                                                && (resource_panel.max_size.is_none()
3636                                                    || size[1]
3637                                                        < resource_panel.max_size.unwrap()[1])
3638                                            {
3639                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3640                                            } else if resource_panel.max_size.is_some()
3641                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3642                                            {
3643                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3644                                            } else {
3645                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3646                                            };
3647                                        }
3648                                        [false, false] => {}
3649                                    }
3650                                }
3651                                [false, true, true, false] => {
3652                                    match [resource_panel.resizable[1], resource_panel.resizable[2]]
3653                                    {
3654                                        [true, true] => {
3655                                            if resource_panel.last_frame_mouse_status.is_none()
3656                                                && ui.input(|i| i.pointer.primary_pressed())
3657                                            {
3658                                                resource_panel.last_frame_mouse_status = Some((
3659                                                    mouse_pos.into(),
3660                                                    ClickAim::LeftBottomResize,
3661                                                    [
3662                                                        mouse_pos.x - position[0],
3663                                                        mouse_pos.y - position[1],
3664                                                    ],
3665                                                ))
3666                                            };
3667                                            if size[0] > resource_panel.min_size[0]
3668                                                && (resource_panel.max_size.is_none()
3669                                                    || size[0]
3670                                                        < resource_panel.max_size.unwrap()[0])
3671                                                || size[1] > resource_panel.min_size[1]
3672                                                    && (resource_panel.max_size.is_none()
3673                                                        || size[1]
3674                                                            < resource_panel.max_size.unwrap()[1])
3675                                            {
3676                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3677                                            } else if resource_panel.max_size.is_some()
3678                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3679                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3680                                            {
3681                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
3682                                            } else {
3683                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
3684                                            };
3685                                        }
3686                                        [false, true] => {
3687                                            if resource_panel.last_frame_mouse_status.is_none()
3688                                                && ui.input(|i| i.pointer.primary_pressed())
3689                                            {
3690                                                resource_panel.last_frame_mouse_status = Some((
3691                                                    mouse_pos.into(),
3692                                                    ClickAim::LeftResize,
3693                                                    [
3694                                                        mouse_pos.x - position[0],
3695                                                        mouse_pos.y - position[1],
3696                                                    ],
3697                                                ))
3698                                            };
3699                                            if size[0] > resource_panel.min_size[0]
3700                                                && (resource_panel.max_size.is_none()
3701                                                    || size[0]
3702                                                        < resource_panel.max_size.unwrap()[0])
3703                                            {
3704                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3705                                            } else if resource_panel.max_size.is_some()
3706                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3707                                            {
3708                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3709                                            } else {
3710                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3711                                            };
3712                                        }
3713                                        [true, false] => {
3714                                            if resource_panel.last_frame_mouse_status.is_none()
3715                                                && ui.input(|i| i.pointer.primary_pressed())
3716                                            {
3717                                                resource_panel.last_frame_mouse_status = Some((
3718                                                    mouse_pos.into(),
3719                                                    ClickAim::BottomResize,
3720                                                    [
3721                                                        mouse_pos.x - position[0],
3722                                                        mouse_pos.y - position[1],
3723                                                    ],
3724                                                ))
3725                                            };
3726                                            if size[1] > resource_panel.min_size[1]
3727                                                && (resource_panel.max_size.is_none()
3728                                                    || size[1]
3729                                                        < resource_panel.max_size.unwrap()[1])
3730                                            {
3731                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3732                                            } else if resource_panel.max_size.is_some()
3733                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3734                                            {
3735                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3736                                            } else {
3737                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3738                                            };
3739                                        }
3740                                        [false, false] => {}
3741                                    }
3742                                }
3743                                _ => {}
3744                            };
3745                            resource_panel.last_frame_mouse_status =
3746                                if resource_panel.last_frame_mouse_status.is_none()
3747                                    && rect.contains(mouse_pos)
3748                                    && ui.input(|i| i.pointer.primary_pressed())
3749                                {
3750                                    Some((
3751                                        [mouse_pos.x, mouse_pos.y],
3752                                        ClickAim::Move,
3753                                        [mouse_pos.x - position[0], mouse_pos.y - position[1]],
3754                                    ))
3755                                } else if resource_panel.last_frame_mouse_status.is_some()
3756                                    && !ui.input(|i| i.pointer.primary_released())
3757                                {
3758                                    Some((
3759                                        [mouse_pos.x, mouse_pos.y],
3760                                        resource_panel.last_frame_mouse_status.unwrap().1,
3761                                        resource_panel.last_frame_mouse_status.unwrap().2,
3762                                    ))
3763                                } else {
3764                                    None
3765                                };
3766                        } else if ui.input(|i| i.pointer.primary_released()) {
3767                            resource_panel.last_frame_mouse_status = None;
3768                        };
3769                    };
3770                    if let Some((mouse_pos, click_aim, offset)) =
3771                        resource_panel.last_frame_mouse_status
3772                    {
3773                        match click_aim {
3774                            ClickAim::LeftTopResize => {
3775                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3776                                    && (resource_panel.max_size.is_none()
3777                                        || position[0] - mouse_pos[0] + size[0]
3778                                            < resource_panel.max_size.unwrap()[0])
3779                                {
3780                                    position_size_config.origin_size[0] +=
3781                                        position[0] - mouse_pos[0];
3782                                    position_size_config.origin_position[0] = mouse_pos[0];
3783                                } else if resource_panel.max_size.is_some()
3784                                    && position[0] - mouse_pos[0] + size[0]
3785                                        >= resource_panel.max_size.unwrap()[0]
3786                                {
3787                                    position_size_config.origin_position[0] -=
3788                                        resource_panel.max_size.unwrap()[0]
3789                                            - position_size_config.origin_size[0];
3790                                    position_size_config.origin_size[0] =
3791                                        resource_panel.max_size.unwrap()[0];
3792                                } else {
3793                                    position_size_config.origin_position[0] += position_size_config
3794                                        .origin_size[0]
3795                                        - resource_panel.min_size[0];
3796                                    position_size_config.origin_size[0] =
3797                                        resource_panel.min_size[0];
3798                                };
3799                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3800                                    && (resource_panel.max_size.is_none()
3801                                        || position[1] - mouse_pos[1] + size[1]
3802                                            < resource_panel.max_size.unwrap()[1])
3803                                {
3804                                    position_size_config.origin_size[1] +=
3805                                        position[1] - mouse_pos[1];
3806                                    position_size_config.origin_position[1] = mouse_pos[1];
3807                                } else if resource_panel.max_size.is_some()
3808                                    && position[1] - mouse_pos[1] + size[1]
3809                                        >= resource_panel.max_size.unwrap()[1]
3810                                {
3811                                    position_size_config.origin_position[1] -=
3812                                        resource_panel.max_size.unwrap()[1]
3813                                            - position_size_config.origin_size[1];
3814                                    position_size_config.origin_size[1] =
3815                                        resource_panel.max_size.unwrap()[1];
3816                                } else {
3817                                    position_size_config.origin_position[1] += position_size_config
3818                                        .origin_size[1]
3819                                        - resource_panel.min_size[1];
3820                                    position_size_config.origin_size[1] =
3821                                        resource_panel.min_size[1];
3822                                };
3823                                if size[0] > resource_panel.min_size[0]
3824                                    && (resource_panel.max_size.is_none()
3825                                        || size[0] < resource_panel.max_size.unwrap()[0])
3826                                    || size[1] > resource_panel.min_size[1]
3827                                        && (resource_panel.max_size.is_none()
3828                                            || size[1] < resource_panel.max_size.unwrap()[1])
3829                                {
3830                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3831                                } else if resource_panel.max_size.is_some()
3832                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3833                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3834                                {
3835                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3836                                } else {
3837                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3838                                };
3839                            }
3840                            ClickAim::RightBottomResize => {
3841                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3842                                    && (resource_panel.max_size.is_none()
3843                                        || mouse_pos[0] - position[0]
3844                                            < resource_panel.max_size.unwrap()[0])
3845                                {
3846                                    position_size_config.origin_size[0] =
3847                                        mouse_pos[0] - position[0];
3848                                } else if resource_panel.max_size.is_some()
3849                                    && mouse_pos[0] - position[0]
3850                                        >= resource_panel.max_size.unwrap()[0]
3851                                {
3852                                    position_size_config.origin_size[0] =
3853                                        resource_panel.max_size.unwrap()[0];
3854                                } else {
3855                                    position_size_config.origin_size[0] =
3856                                        resource_panel.min_size[0];
3857                                };
3858                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3859                                    && (resource_panel.max_size.is_none()
3860                                        || mouse_pos[1] - position[1]
3861                                            < resource_panel.max_size.unwrap()[1])
3862                                {
3863                                    position_size_config.origin_size[1] =
3864                                        mouse_pos[1] - position[1];
3865                                } else if resource_panel.max_size.is_some()
3866                                    && mouse_pos[1] - position[1]
3867                                        >= resource_panel.max_size.unwrap()[1]
3868                                {
3869                                    position_size_config.origin_size[1] =
3870                                        resource_panel.max_size.unwrap()[1];
3871                                } else {
3872                                    position_size_config.origin_size[1] =
3873                                        resource_panel.min_size[1];
3874                                };
3875                                if size[0] > resource_panel.min_size[0]
3876                                    && (resource_panel.max_size.is_none()
3877                                        || size[0] < resource_panel.max_size.unwrap()[0])
3878                                    || size[1] > resource_panel.min_size[1]
3879                                        && (resource_panel.max_size.is_none()
3880                                            || size[1] < resource_panel.max_size.unwrap()[1])
3881                                {
3882                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3883                                } else if resource_panel.max_size.is_some()
3884                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3885                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3886                                {
3887                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3888                                } else {
3889                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3890                                };
3891                            }
3892                            ClickAim::RightTopResize => {
3893                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3894                                    && (resource_panel.max_size.is_none()
3895                                        || mouse_pos[0] - position[0]
3896                                            < resource_panel.max_size.unwrap()[0])
3897                                {
3898                                    position_size_config.origin_size[0] =
3899                                        mouse_pos[0] - position[0];
3900                                } else if resource_panel.max_size.is_some()
3901                                    && mouse_pos[0] - position[0]
3902                                        >= resource_panel.max_size.unwrap()[0]
3903                                {
3904                                    position_size_config.origin_size[0] =
3905                                        resource_panel.max_size.unwrap()[0];
3906                                } else {
3907                                    position_size_config.origin_size[0] =
3908                                        resource_panel.min_size[0];
3909                                };
3910                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3911                                    && (resource_panel.max_size.is_none()
3912                                        || position[1] - mouse_pos[1] + size[1]
3913                                            < resource_panel.max_size.unwrap()[1])
3914                                {
3915                                    position_size_config.origin_size[1] +=
3916                                        position[1] - mouse_pos[1];
3917                                    position_size_config.origin_position[1] = mouse_pos[1];
3918                                } else if resource_panel.max_size.is_some()
3919                                    && position[1] - mouse_pos[1] + size[1]
3920                                        >= resource_panel.max_size.unwrap()[1]
3921                                {
3922                                    position_size_config.origin_position[1] -=
3923                                        resource_panel.max_size.unwrap()[1]
3924                                            - position_size_config.origin_size[1];
3925                                    position_size_config.origin_size[1] =
3926                                        resource_panel.max_size.unwrap()[1];
3927                                } else {
3928                                    position_size_config.origin_position[1] += position_size_config
3929                                        .origin_size[1]
3930                                        - resource_panel.min_size[1];
3931                                    position_size_config.origin_size[1] =
3932                                        resource_panel.min_size[1];
3933                                };
3934                                if size[0] > resource_panel.min_size[0]
3935                                    && (resource_panel.max_size.is_none()
3936                                        || size[0] < resource_panel.max_size.unwrap()[0])
3937                                    || size[1] > resource_panel.min_size[1]
3938                                        && (resource_panel.max_size.is_none()
3939                                            || size[1] < resource_panel.max_size.unwrap()[1])
3940                                {
3941                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3942                                } else if resource_panel.max_size.is_some()
3943                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3944                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3945                                {
3946                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3947                                } else {
3948                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3949                                };
3950                            }
3951                            ClickAim::LeftBottomResize => {
3952                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3953                                    && (resource_panel.max_size.is_none()
3954                                        || position[0] - mouse_pos[0] + size[0]
3955                                            < resource_panel.max_size.unwrap()[0])
3956                                {
3957                                    position_size_config.origin_size[0] +=
3958                                        position[0] - mouse_pos[0];
3959                                    position_size_config.origin_position[0] = mouse_pos[0];
3960                                } else if resource_panel.max_size.is_some()
3961                                    && position[0] - mouse_pos[0] + size[0]
3962                                        >= resource_panel.max_size.unwrap()[0]
3963                                {
3964                                    position_size_config.origin_position[0] -=
3965                                        resource_panel.max_size.unwrap()[0]
3966                                            - position_size_config.origin_size[0];
3967                                    position_size_config.origin_size[0] =
3968                                        resource_panel.max_size.unwrap()[0];
3969                                } else {
3970                                    position_size_config.origin_position[0] += position_size_config
3971                                        .origin_size[0]
3972                                        - resource_panel.min_size[0];
3973                                    position_size_config.origin_size[0] =
3974                                        resource_panel.min_size[0];
3975                                };
3976                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3977                                    && (resource_panel.max_size.is_none()
3978                                        || mouse_pos[1] - position[1]
3979                                            < resource_panel.max_size.unwrap()[1])
3980                                {
3981                                    position_size_config.origin_size[1] =
3982                                        mouse_pos[1] - position[1];
3983                                } else if resource_panel.max_size.is_some()
3984                                    && mouse_pos[1] - position[1]
3985                                        >= resource_panel.max_size.unwrap()[1]
3986                                {
3987                                    position_size_config.origin_size[1] =
3988                                        resource_panel.max_size.unwrap()[1];
3989                                } else {
3990                                    position_size_config.origin_size[1] =
3991                                        resource_panel.min_size[1];
3992                                };
3993                                if size[0] > resource_panel.min_size[0]
3994                                    && (resource_panel.max_size.is_none()
3995                                        || size[0] < resource_panel.max_size.unwrap()[0])
3996                                    || size[1] > resource_panel.min_size[1]
3997                                        && (resource_panel.max_size.is_none()
3998                                            || size[1] < resource_panel.max_size.unwrap()[1])
3999                                {
4000                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
4001                                } else if resource_panel.max_size.is_some()
4002                                    && size[0] >= resource_panel.max_size.unwrap()[0]
4003                                    && size[1] >= resource_panel.max_size.unwrap()[1]
4004                                {
4005                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
4006                                } else {
4007                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
4008                                };
4009                            }
4010                            ClickAim::TopResize => {
4011                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
4012                                    && (resource_panel.max_size.is_none()
4013                                        || position[1] - mouse_pos[1] + size[1]
4014                                            < resource_panel.max_size.unwrap()[1])
4015                                {
4016                                    position_size_config.origin_size[1] +=
4017                                        position[1] - mouse_pos[1];
4018                                    position_size_config.origin_position[1] = mouse_pos[1];
4019                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4020                                } else if resource_panel.max_size.is_some()
4021                                    && position[1] - mouse_pos[1] + size[1]
4022                                        >= resource_panel.max_size.unwrap()[1]
4023                                {
4024                                    position_size_config.origin_position[1] -=
4025                                        resource_panel.max_size.unwrap()[1]
4026                                            - position_size_config.origin_size[1];
4027                                    position_size_config.origin_size[1] =
4028                                        resource_panel.max_size.unwrap()[1];
4029                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4030                                } else {
4031                                    position_size_config.origin_position[1] += position_size_config
4032                                        .origin_size[1]
4033                                        - resource_panel.min_size[1];
4034                                    position_size_config.origin_size[1] =
4035                                        resource_panel.min_size[1];
4036                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4037                                };
4038                            }
4039                            ClickAim::BottomResize => {
4040                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
4041                                    && (resource_panel.max_size.is_none()
4042                                        || mouse_pos[1] - position[1]
4043                                            < resource_panel.max_size.unwrap()[1])
4044                                {
4045                                    position_size_config.origin_size[1] =
4046                                        mouse_pos[1] - position[1];
4047                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4048                                } else if resource_panel.max_size.is_some()
4049                                    && mouse_pos[1] - position[1]
4050                                        >= resource_panel.max_size.unwrap()[1]
4051                                {
4052                                    position_size_config.origin_size[1] =
4053                                        resource_panel.max_size.unwrap()[1];
4054                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4055                                } else {
4056                                    position_size_config.origin_size[1] =
4057                                        resource_panel.min_size[1];
4058                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4059                                };
4060                            }
4061                            ClickAim::LeftResize => {
4062                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
4063                                    && (resource_panel.max_size.is_none()
4064                                        || position[0] - mouse_pos[0] + size[0]
4065                                            < resource_panel.max_size.unwrap()[0])
4066                                {
4067                                    position_size_config.origin_size[0] +=
4068                                        position[0] - mouse_pos[0];
4069                                    position_size_config.origin_position[0] = mouse_pos[0];
4070                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4071                                } else if resource_panel.max_size.is_some()
4072                                    && position[0] - mouse_pos[0] + size[0]
4073                                        >= resource_panel.max_size.unwrap()[0]
4074                                {
4075                                    position_size_config.origin_position[0] -=
4076                                        resource_panel.max_size.unwrap()[0]
4077                                            - position_size_config.origin_size[0];
4078                                    position_size_config.origin_size[0] =
4079                                        resource_panel.max_size.unwrap()[0];
4080                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
4081                                } else {
4082                                    position_size_config.origin_position[0] += position_size_config
4083                                        .origin_size[0]
4084                                        - resource_panel.min_size[0];
4085                                    position_size_config.origin_size[0] =
4086                                        resource_panel.min_size[0];
4087                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
4088                                };
4089                            }
4090                            ClickAim::RightResize => {
4091                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
4092                                    && (resource_panel.max_size.is_none()
4093                                        || mouse_pos[0] - position[0]
4094                                            < resource_panel.max_size.unwrap()[0])
4095                                {
4096                                    position_size_config.origin_size[0] =
4097                                        mouse_pos[0] - position[0];
4098                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4099                                } else if resource_panel.max_size.is_some()
4100                                    && mouse_pos[0] - position[0]
4101                                        >= resource_panel.max_size.unwrap()[0]
4102                                {
4103                                    position_size_config.origin_size[0] =
4104                                        resource_panel.max_size.unwrap()[0];
4105                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
4106                                } else {
4107                                    position_size_config.origin_size[0] =
4108                                        resource_panel.min_size[0];
4109                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
4110                                };
4111                            }
4112                            ClickAim::Move => {
4113                                ctx.set_cursor_icon(match resource_panel.movable {
4114                                    [true, true] => CursorIcon::Move,
4115                                    [true, false] => CursorIcon::ResizeColumn,
4116                                    [false, true] => CursorIcon::ResizeRow,
4117                                    [false, false] => CursorIcon::NotAllowed,
4118                                });
4119                                if resource_panel.movable[0] {
4120                                    position_size_config.origin_position[0] =
4121                                        mouse_pos[0] - offset[0];
4122                                };
4123                                if resource_panel.movable[1] {
4124                                    position_size_config.origin_position[1] =
4125                                        mouse_pos[1] - offset[1];
4126                                };
4127                            }
4128                        };
4129                    };
4130                    [position, size] = position_size_processor(position_size_config, ctx);
4131                    let background_type = match background.background_type.clone() {
4132                        BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
4133                            config
4134                                .position_size_config(Some(position_size_config))
4135                                .hidden(Some(resource_panel.hidden)),
4136                        ),
4137                        BackgroundType::Image(config) => BackgroundType::Image(
4138                            config
4139                                .position_size_config(Some(position_size_config))
4140                                .hidden(Some(resource_panel.hidden)),
4141                        ),
4142                    };
4143                    self.replace_resource(
4144                        &format!("{}Background", &id.name),
4145                        background.clone().background_type(&background_type).clone(),
4146                    )?;
4147                    self.use_resource(
4148                        &RustConstructorId {
4149                            name: format!("{}Background", &id.name),
4150                            discern_type: "Background".to_string(),
4151                        },
4152                        ui,
4153                        ctx,
4154                    )?;
4155                    type PointList = Vec<([f32; 2], [f32; 2], [bool; 2], Option<String>)>;
4156                    let mut resource_point_list: PointList = Vec::new();
4157                    let mut use_resource_list = Vec::new();
4158                    let mut replace_resource_list = Vec::new();
4159                    for rcr in &self.rust_constructor_resource {
4160                        if self
4161                            .basic_front_resource_list
4162                            .contains(&rcr.id.discern_type)
4163                            && let Some(panel_name) =
4164                                get_tag("panel_name", &rcr.content.display_tags())
4165                            && panel_name.1 == id.name
4166                        {
4167                            if let [Some(citer_name), Some(citer_type)] = [
4168                                get_tag("citer_name", &rcr.content.display_tags()),
4169                                get_tag("citer_type", &rcr.content.display_tags()),
4170                            ] {
4171                                if !use_resource_list
4172                                    .iter()
4173                                    .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
4174                                {
4175                                    use_resource_list.push([citer_name.1, citer_type.1]);
4176                                };
4177                            } else if !use_resource_list
4178                                .iter()
4179                                .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
4180                            {
4181                                use_resource_list
4182                                    .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
4183                            };
4184                            let mut basic_front_resource: Box<dyn BasicFrontResource> =
4185                                match &*rcr.id.discern_type {
4186                                    "Image" => {
4187                                        Box::new(downcast_resource::<Image>(&*rcr.content)?.clone())
4188                                    }
4189                                    "Text" => {
4190                                        Box::new(downcast_resource::<Text>(&*rcr.content)?.clone())
4191                                    }
4192                                    "CustomRect" => Box::new(
4193                                        downcast_resource::<CustomRect>(&*rcr.content)?.clone(),
4194                                    ),
4195                                    _ => {
4196                                        unreachable!()
4197                                    }
4198                                };
4199                            if !resource_panel
4200                                .resource_storage
4201                                .iter()
4202                                .any(|x| x.id == rcr.id)
4203                            {
4204                                resource_panel.resource_storage.push(PanelStorage {
4205                                    id: rcr.id.clone(),
4206                                    ignore_render_layer: if let Some(display_info) =
4207                                        basic_front_resource.display_display_info()
4208                                    {
4209                                        display_info.ignore_render_layer
4210                                    } else {
4211                                        false
4212                                    },
4213                                    hidden: if let Some(display_info) =
4214                                        basic_front_resource.display_display_info()
4215                                    {
4216                                        display_info.hidden
4217                                    } else {
4218                                        false
4219                                    },
4220                                });
4221                            };
4222                            let enable_scrolling = [
4223                                get_tag("disable_x_scrolling", &rcr.content.display_tags())
4224                                    .is_none(),
4225                                get_tag("disable_y_scrolling", &rcr.content.display_tags())
4226                                    .is_none(),
4227                            ];
4228                            let offset = basic_front_resource.display_position_size_config().offset;
4229                            basic_front_resource.modify_position_size_config(
4230                                basic_front_resource
4231                                    .display_position_size_config()
4232                                    .x_location_grid(0_f32, 0_f32)
4233                                    .y_location_grid(0_f32, 0_f32)
4234                                    .x_size_grid(0_f32, 0_f32)
4235                                    .y_size_grid(0_f32, 0_f32)
4236                                    .offset(
4237                                        if enable_scrolling[0] {
4238                                            -resource_panel.scroll_progress[0]
4239                                        } else {
4240                                            offset[0]
4241                                        },
4242                                        if enable_scrolling[1] {
4243                                            -resource_panel.scroll_progress[1]
4244                                        } else {
4245                                            offset[1]
4246                                        },
4247                                    ),
4248                            );
4249                            let mut layout = resource_panel.overall_layout;
4250                            for custom_layout in &resource_panel.custom_layout {
4251                                match custom_layout {
4252                                    CustomPanelLayout::Id(layout_id, panel_layout) => {
4253                                        if rcr.id.cmp(layout_id) == Ordering::Equal {
4254                                            layout = *panel_layout;
4255                                            break;
4256                                        };
4257                                    }
4258                                    CustomPanelLayout::Type(layout_type, panel_layout) => {
4259                                        if *layout_type == rcr.id.discern_type {
4260                                            layout = *panel_layout;
4261                                        }
4262                                    }
4263                                };
4264                            }
4265                            let panel_layout_group = if let Some(panel_layout_group) =
4266                                get_tag("panel_layout_group", &basic_front_resource.display_tags())
4267                            {
4268                                Some(panel_layout_group.1)
4269                            } else {
4270                                None
4271                            };
4272                            match layout.panel_margin {
4273                                PanelMargin::Vertical(
4274                                    [top, bottom, left, right],
4275                                    move_to_bottom,
4276                                ) => {
4277                                    let mut modify_y = 0_f32;
4278                                    let [default_x_position, default_y_position] =
4279                                        match layout.panel_location {
4280                                            PanelLocation::Absolute([x, y]) => {
4281                                                [position[0] + x, position[1] + y]
4282                                            }
4283                                            PanelLocation::Relative([x, y]) => [
4284                                                position[0]
4285                                                    + if x[1] != 0_f32 {
4286                                                        size[0] / x[1] * x[0]
4287                                                    } else {
4288                                                        0_f32
4289                                                    },
4290                                                position[1]
4291                                                    + if y[1] != 0_f32 {
4292                                                        size[1] / y[1] * y[0]
4293                                                    } else {
4294                                                        0_f32
4295                                                    },
4296                                            ],
4297                                        };
4298                                    let default_x_position = match basic_front_resource
4299                                        .display_position_size_config()
4300                                        .display_method
4301                                        .0
4302                                    {
4303                                        HorizontalAlign::Left => default_x_position,
4304                                        HorizontalAlign::Center => {
4305                                            default_x_position
4306                                                - basic_front_resource.display_size()[0] / 2.0
4307                                        }
4308                                        HorizontalAlign::Right => {
4309                                            default_x_position
4310                                                - basic_front_resource.display_size()[0]
4311                                        }
4312                                    };
4313                                    let default_y_position = match basic_front_resource
4314                                        .display_position_size_config()
4315                                        .display_method
4316                                        .1
4317                                    {
4318                                        VerticalAlign::Top => default_y_position,
4319                                        VerticalAlign::Center => {
4320                                            default_y_position
4321                                                - basic_front_resource.display_size()[1] / 2.0
4322                                        }
4323                                        VerticalAlign::Bottom => {
4324                                            default_y_position
4325                                                - basic_front_resource.display_size()[1]
4326                                        }
4327                                    };
4328                                    for point in &resource_point_list {
4329                                        if let Some(ref point_panel_layout_group) = point.3
4330                                            && let Some(ref panel_layout_group) = panel_layout_group
4331                                            && panel_layout_group == point_panel_layout_group
4332                                        {
4333                                            continue;
4334                                        };
4335                                        if default_x_position - left < point.1[0]
4336                                            && default_y_position - top + modify_y < point.1[1]
4337                                            && default_x_position
4338                                                + basic_front_resource.display_size()[0]
4339                                                + right
4340                                                > point.0[0]
4341                                            && default_y_position
4342                                                + basic_front_resource.display_size()[1]
4343                                                + bottom
4344                                                + modify_y
4345                                                > point.0[1]
4346                                        {
4347                                            if move_to_bottom
4348                                                && point.1[1] - default_y_position + top > modify_y
4349                                            {
4350                                                modify_y = point.1[1] - default_y_position + top;
4351                                            } else if !move_to_bottom
4352                                                && point.0[1]
4353                                                    - default_y_position
4354                                                    - basic_front_resource.display_size()[1]
4355                                                    - bottom
4356                                                    < modify_y
4357                                            {
4358                                                modify_y = point.0[1]
4359                                                    - default_y_position
4360                                                    - basic_front_resource.display_size()[1]
4361                                                    - bottom;
4362                                            };
4363                                        };
4364                                    }
4365                                    let real_x_position = match basic_front_resource
4366                                        .display_position_size_config()
4367                                        .display_method
4368                                        .0
4369                                    {
4370                                        HorizontalAlign::Left => default_x_position,
4371                                        HorizontalAlign::Center => {
4372                                            default_x_position
4373                                                + basic_front_resource.display_size()[0] / 2.0
4374                                        }
4375                                        HorizontalAlign::Right => {
4376                                            default_x_position
4377                                                + basic_front_resource.display_size()[0]
4378                                        }
4379                                    };
4380                                    let real_y_position = match basic_front_resource
4381                                        .display_position_size_config()
4382                                        .display_method
4383                                        .1
4384                                    {
4385                                        VerticalAlign::Top => default_y_position + modify_y,
4386                                        VerticalAlign::Center => {
4387                                            default_y_position
4388                                                + modify_y
4389                                                + basic_front_resource.display_size()[1] / 2.0
4390                                        }
4391                                        VerticalAlign::Bottom => {
4392                                            default_y_position
4393                                                + modify_y
4394                                                + basic_front_resource.display_size()[1]
4395                                        }
4396                                    };
4397                                    basic_front_resource.modify_position_size_config(
4398                                        basic_front_resource
4399                                            .display_position_size_config()
4400                                            .origin_position(
4401                                                real_x_position
4402                                                    + left
4403                                                    + resource_panel.inner_margin[2],
4404                                                real_y_position
4405                                                    + top
4406                                                    + resource_panel.inner_margin[0],
4407                                            ),
4408                                    );
4409                                    replace_resource_list.push((
4410                                        basic_front_resource.display_position_size_config(),
4411                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4412                                    ));
4413                                    resource_point_list.push((
4414                                        [real_x_position - left, real_y_position - top],
4415                                        [
4416                                            real_x_position
4417                                                + basic_front_resource.display_size()[0]
4418                                                + right,
4419                                            real_y_position
4420                                                + basic_front_resource.display_size()[1]
4421                                                + bottom,
4422                                        ],
4423                                        enable_scrolling,
4424                                        panel_layout_group,
4425                                    ));
4426                                }
4427                                PanelMargin::Horizontal(
4428                                    [top, bottom, left, right],
4429                                    move_to_right,
4430                                ) => {
4431                                    let mut modify_x = 0_f32;
4432                                    let [default_x_position, default_y_position] =
4433                                        match layout.panel_location {
4434                                            PanelLocation::Absolute([x, y]) => {
4435                                                [position[0] + x, position[1] + y]
4436                                            }
4437                                            PanelLocation::Relative([x, y]) => [
4438                                                position[0]
4439                                                    + if x[1] != 0_f32 {
4440                                                        size[0] / x[1] * x[0]
4441                                                    } else {
4442                                                        0_f32
4443                                                    },
4444                                                position[1]
4445                                                    + if y[1] != 0_f32 {
4446                                                        size[1] / y[1] * y[0]
4447                                                    } else {
4448                                                        0_f32
4449                                                    },
4450                                            ],
4451                                        };
4452                                    let default_x_position = match basic_front_resource
4453                                        .display_position_size_config()
4454                                        .display_method
4455                                        .0
4456                                    {
4457                                        HorizontalAlign::Left => default_x_position,
4458                                        HorizontalAlign::Center => {
4459                                            default_x_position
4460                                                - basic_front_resource.display_size()[0] / 2.0
4461                                        }
4462                                        HorizontalAlign::Right => {
4463                                            default_x_position
4464                                                - basic_front_resource.display_size()[0]
4465                                        }
4466                                    };
4467                                    let default_y_position = match basic_front_resource
4468                                        .display_position_size_config()
4469                                        .display_method
4470                                        .1
4471                                    {
4472                                        VerticalAlign::Top => default_y_position,
4473                                        VerticalAlign::Center => {
4474                                            default_y_position
4475                                                - basic_front_resource.display_size()[1] / 2.0
4476                                        }
4477                                        VerticalAlign::Bottom => {
4478                                            default_y_position
4479                                                - basic_front_resource.display_size()[1]
4480                                        }
4481                                    };
4482                                    for point in &resource_point_list {
4483                                        if let Some(ref point_panel_layout_group) = point.3
4484                                            && let Some(ref panel_layout_group) = panel_layout_group
4485                                            && panel_layout_group == point_panel_layout_group
4486                                        {
4487                                            continue;
4488                                        };
4489                                        if default_x_position - left + modify_x < point.1[0]
4490                                            && default_y_position - top < point.1[1]
4491                                            && default_x_position
4492                                                + basic_front_resource.display_size()[0]
4493                                                + right
4494                                                + modify_x
4495                                                > point.0[0]
4496                                            && default_y_position
4497                                                + basic_front_resource.display_size()[1]
4498                                                + bottom
4499                                                > point.0[1]
4500                                        {
4501                                            if move_to_right
4502                                                && point.1[0] - default_x_position + left > modify_x
4503                                            {
4504                                                modify_x = point.1[0] - default_x_position + left;
4505                                            } else if !move_to_right
4506                                                && point.0[0]
4507                                                    - default_x_position
4508                                                    - basic_front_resource.display_size()[0]
4509                                                    - right
4510                                                    < modify_x
4511                                            {
4512                                                modify_x = point.0[0]
4513                                                    - default_x_position
4514                                                    - basic_front_resource.display_size()[0]
4515                                                    - right;
4516                                            };
4517                                        };
4518                                    }
4519                                    let real_x_position = match basic_front_resource
4520                                        .display_position_size_config()
4521                                        .display_method
4522                                        .0
4523                                    {
4524                                        HorizontalAlign::Left => default_x_position + modify_x,
4525                                        HorizontalAlign::Center => {
4526                                            default_x_position
4527                                                + modify_x
4528                                                + basic_front_resource.display_size()[0] / 2.0
4529                                        }
4530                                        HorizontalAlign::Right => {
4531                                            default_x_position
4532                                                + modify_x
4533                                                + basic_front_resource.display_size()[0]
4534                                        }
4535                                    };
4536                                    let real_y_position = match basic_front_resource
4537                                        .display_position_size_config()
4538                                        .display_method
4539                                        .1
4540                                    {
4541                                        VerticalAlign::Top => default_y_position,
4542                                        VerticalAlign::Center => {
4543                                            default_y_position
4544                                                + basic_front_resource.display_size()[1] / 2.0
4545                                        }
4546                                        VerticalAlign::Bottom => {
4547                                            default_y_position
4548                                                + basic_front_resource.display_size()[1]
4549                                        }
4550                                    };
4551                                    basic_front_resource.modify_position_size_config(
4552                                        basic_front_resource
4553                                            .display_position_size_config()
4554                                            .origin_position(
4555                                                real_x_position
4556                                                    + left
4557                                                    + resource_panel.inner_margin[2],
4558                                                real_y_position
4559                                                    + top
4560                                                    + resource_panel.inner_margin[0],
4561                                            ),
4562                                    );
4563                                    replace_resource_list.push((
4564                                        basic_front_resource.display_position_size_config(),
4565                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4566                                    ));
4567                                    resource_point_list.push((
4568                                        [real_x_position - left, real_y_position - top],
4569                                        [
4570                                            real_x_position
4571                                                + basic_front_resource.display_size()[0]
4572                                                + right,
4573                                            real_y_position
4574                                                + basic_front_resource.display_size()[1]
4575                                                + bottom,
4576                                        ],
4577                                        enable_scrolling,
4578                                        panel_layout_group,
4579                                    ));
4580                                }
4581                                PanelMargin::None([top, bottom, left, right], influence_layout) => {
4582                                    let [default_x_position, default_y_position] =
4583                                        match layout.panel_location {
4584                                            PanelLocation::Absolute([x, y]) => {
4585                                                [position[0] + x, position[1] + y]
4586                                            }
4587                                            PanelLocation::Relative([x, y]) => [
4588                                                position[0]
4589                                                    + if x[1] != 0_f32 {
4590                                                        size[0] / x[1] * x[0]
4591                                                    } else {
4592                                                        0_f32
4593                                                    },
4594                                                position[1]
4595                                                    + if y[1] != 0_f32 {
4596                                                        size[1] / y[1] * y[0]
4597                                                    } else {
4598                                                        0_f32
4599                                                    },
4600                                            ],
4601                                        };
4602                                    basic_front_resource.modify_position_size_config(
4603                                        basic_front_resource
4604                                            .display_position_size_config()
4605                                            .origin_position(
4606                                                default_x_position
4607                                                    + left
4608                                                    + resource_panel.inner_margin[2],
4609                                                default_y_position
4610                                                    + top
4611                                                    + resource_panel.inner_margin[0],
4612                                            ),
4613                                    );
4614                                    replace_resource_list.push((
4615                                        basic_front_resource.display_position_size_config(),
4616                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4617                                    ));
4618                                    if influence_layout {
4619                                        resource_point_list.push((
4620                                            [default_x_position - left, default_y_position - top],
4621                                            [
4622                                                default_x_position
4623                                                    + basic_front_resource.display_size()[0]
4624                                                    + right,
4625                                                default_y_position
4626                                                    + basic_front_resource.display_size()[1]
4627                                                    + bottom,
4628                                            ],
4629                                            enable_scrolling,
4630                                            panel_layout_group,
4631                                        ));
4632                                    };
4633                                }
4634                            };
4635                        };
4636                    }
4637                    for (new_position_size_config, [name, discern_type]) in replace_resource_list {
4638                        let id = RustConstructorId {
4639                            name: name.clone(),
4640                            discern_type: discern_type.clone(),
4641                        };
4642                        let default_storage = if let Some(resource_storage) =
4643                            resource_panel.resource_storage.iter().find(|x| x.id == id)
4644                        {
4645                            [
4646                                true,
4647                                resource_storage.ignore_render_layer,
4648                                resource_storage.hidden,
4649                            ]
4650                        } else {
4651                            [false, true, true]
4652                        };
4653                        let basic_front_resource = self.get_basic_front_resource_mut(&id)?;
4654                        basic_front_resource.modify_position_size_config(new_position_size_config);
4655                        basic_front_resource.modify_clip_rect(Some(
4656                            position_size_config
4657                                .origin_size(
4658                                    position_size_config.origin_size[0]
4659                                        - resource_panel.inner_margin[2]
4660                                        - resource_panel.inner_margin[3],
4661                                    position_size_config.origin_size[1]
4662                                        - resource_panel.inner_margin[0]
4663                                        - resource_panel.inner_margin[1],
4664                                )
4665                                .origin_position(
4666                                    position_size_config.origin_position[0]
4667                                        + resource_panel.inner_margin[2],
4668                                    position_size_config.origin_position[1]
4669                                        + resource_panel.inner_margin[0],
4670                                ),
4671                        ));
4672                        basic_front_resource.modify_display_info({
4673                            let mut display_info =
4674                                basic_front_resource.display_display_info().unwrap();
4675                            display_info.ignore_render_layer =
4676                                if resource_panel.last_frame_mouse_status.is_some()
4677                                    && resource_get_focus[1]
4678                                {
4679                                    true
4680                                } else if default_storage[0] {
4681                                    default_storage[1]
4682                                } else {
4683                                    display_info.ignore_render_layer
4684                                };
4685                            display_info.hidden = if resource_panel.hidden {
4686                                true
4687                            } else if default_storage[0] {
4688                                default_storage[2]
4689                            } else {
4690                                display_info.hidden
4691                            };
4692                            display_info
4693                        });
4694                    }
4695                    for info in use_resource_list {
4696                        self.use_resource(
4697                            &RustConstructorId {
4698                                name: info[0].clone(),
4699                                discern_type: info[1].clone(),
4700                            },
4701                            ui,
4702                            ctx,
4703                        )?;
4704                    }
4705                    let mut resource_length = [None, None];
4706                    for point in resource_point_list {
4707                        resource_length = [
4708                            if resource_length[0].is_none()
4709                                || resource_length[0].is_some()
4710                                    && point.1[0] > resource_length[0].unwrap()
4711                                    && point.2[0]
4712                            {
4713                                Some(point.1[0])
4714                            } else {
4715                                resource_length[0]
4716                            },
4717                            if resource_length[1].is_none()
4718                                || resource_length[1].is_some()
4719                                    && point.1[1] > resource_length[1].unwrap()
4720                                    && point.2[1]
4721                            {
4722                                Some(point.1[1])
4723                            } else {
4724                                resource_length[1]
4725                            },
4726                        ]
4727                    }
4728                    if let Some(horizontal_scroll_length_method) =
4729                        resource_panel.scroll_length_method[0]
4730                    {
4731                        let margin = match resource_panel.overall_layout.panel_margin {
4732                            PanelMargin::Horizontal([_, _, left, right], _) => left + right,
4733                            PanelMargin::Vertical([_, _, left, right], _) => left + right,
4734                            PanelMargin::None([_, _, left, right], _) => left + right,
4735                        };
4736                        resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
4737                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4738                            ScrollLengthMethod::AutoFit(expand) => {
4739                                if let Some(max) = resource_length[0] {
4740                                    let width = max - position[0];
4741                                    if width - size[0]
4742                                        + expand
4743                                        + margin
4744                                        + resource_panel.inner_margin[3]
4745                                        + resource_panel.inner_margin[2]
4746                                        > 0_f32
4747                                    {
4748                                        width - size[0]
4749                                            + expand
4750                                            + margin
4751                                            + resource_panel.inner_margin[3]
4752                                            + resource_panel.inner_margin[2]
4753                                    } else {
4754                                        0_f32
4755                                    }
4756                                } else {
4757                                    0_f32
4758                                }
4759                            }
4760                        };
4761                        if resource_panel.scroll_progress[0] > resource_panel.scroll_length[0] {
4762                            resource_panel.scroll_progress[0] = resource_panel.scroll_length[0];
4763                        };
4764                    };
4765                    if let Some(vertical_scroll_length_method) =
4766                        resource_panel.scroll_length_method[1]
4767                    {
4768                        let margin = match resource_panel.overall_layout.panel_margin {
4769                            PanelMargin::Horizontal([top, bottom, _, _], _) => top + bottom,
4770                            PanelMargin::Vertical([top, bottom, _, _], _) => top + bottom,
4771                            PanelMargin::None([top, bottom, _, _], _) => top + bottom,
4772                        };
4773                        resource_panel.scroll_length[1] = match vertical_scroll_length_method {
4774                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4775                            ScrollLengthMethod::AutoFit(expand) => {
4776                                if let Some(max) = resource_length[1] {
4777                                    let height = max - position[1];
4778                                    if height - size[1]
4779                                        + expand
4780                                        + margin
4781                                        + resource_panel.inner_margin[1]
4782                                        + resource_panel.inner_margin[0]
4783                                        > 0_f32
4784                                    {
4785                                        height - size[1]
4786                                            + expand
4787                                            + margin
4788                                            + resource_panel.inner_margin[1]
4789                                            + resource_panel.inner_margin[0]
4790                                    } else {
4791                                        0_f32
4792                                    }
4793                                } else {
4794                                    0_f32
4795                                }
4796                            }
4797                        };
4798                        if resource_panel.scroll_progress[1] > resource_panel.scroll_length[1] {
4799                            resource_panel.scroll_progress[1] = resource_panel.scroll_length[1];
4800                        };
4801                    };
4802                    match resource_panel.scroll_bar_display_method {
4803                        ScrollBarDisplayMethod::Always(ref config, margin, width) => {
4804                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4805                                (size[0] - margin[0] * 2_f32)
4806                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4807                            } else {
4808                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4809                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4810                            };
4811                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
4812                                position[0]
4813                                    + margin[0]
4814                                    + (size[0] - margin[0] * 2_f32 - line_length)
4815                                        * (resource_panel.scroll_progress[0]
4816                                            / resource_panel.scroll_length[0])
4817                            } else {
4818                                position[0]
4819                                    + margin[0]
4820                                    + (size[0]
4821                                        - margin[0] * 2_f32
4822                                        - width
4823                                        - margin[1]
4824                                        - line_length)
4825                                        * (resource_panel.scroll_progress[0]
4826                                            / resource_panel.scroll_length[0])
4827                            };
4828                            self.replace_resource(
4829                                &format!("{}XScroll", &id.name),
4830                                background.clone().background_type(&match config.clone() {
4831                                    BackgroundType::CustomRect(config) => {
4832                                        BackgroundType::CustomRect(
4833                                            config
4834                                                .ignore_render_layer(Some(true))
4835                                                .hidden(Some(resource_panel.hidden))
4836                                                .position_size_config(Some(
4837                                                    PositionSizeConfig::default()
4838                                                        .display_method(
4839                                                            HorizontalAlign::Left,
4840                                                            VerticalAlign::Bottom,
4841                                                        )
4842                                                        .origin_position(
4843                                                            line_position,
4844                                                            position[1] + size[1] - margin[1],
4845                                                        )
4846                                                        .origin_size(line_length, width),
4847                                                )),
4848                                        )
4849                                    }
4850                                    BackgroundType::Image(config) => BackgroundType::Image(
4851                                        config
4852                                            .ignore_render_layer(Some(true))
4853                                            .hidden(Some(resource_panel.hidden))
4854                                            .position_size_config(Some(
4855                                                PositionSizeConfig::default()
4856                                                    .display_method(
4857                                                        HorizontalAlign::Left,
4858                                                        VerticalAlign::Bottom,
4859                                                    )
4860                                                    .origin_position(
4861                                                        line_position,
4862                                                        position[1] + size[1] - margin[1],
4863                                                    )
4864                                                    .origin_size(line_length, width),
4865                                            )),
4866                                    ),
4867                                }),
4868                            )?;
4869                            self.use_resource(
4870                                &RustConstructorId {
4871                                    name: format!("{}XScroll", &id.name),
4872                                    discern_type: "Background".to_string(),
4873                                },
4874                                ui,
4875                                ctx,
4876                            )?;
4877                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
4878                                (size[1] - margin[0] * 2_f32)
4879                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4880                            } else {
4881                                (size[1] - width - margin[1] - margin[0] * 2_f32)
4882                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4883                            };
4884                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
4885                                position[1]
4886                                    + margin[0]
4887                                    + (size[1] - margin[0] * 2_f32 - line_length)
4888                                        * (resource_panel.scroll_progress[1]
4889                                            / resource_panel.scroll_length[1])
4890                            } else {
4891                                position[1]
4892                                    + margin[0]
4893                                    + (size[1]
4894                                        - margin[0] * 2_f32
4895                                        - width
4896                                        - margin[1]
4897                                        - line_length)
4898                                        * (resource_panel.scroll_progress[1]
4899                                            / resource_panel.scroll_length[1])
4900                            };
4901                            self.replace_resource(
4902                                &format!("{}YScroll", &id.name),
4903                                background.background_type(&match config.clone() {
4904                                    BackgroundType::CustomRect(config) => {
4905                                        BackgroundType::CustomRect(
4906                                            config
4907                                                .ignore_render_layer(Some(true))
4908                                                .hidden(Some(resource_panel.hidden))
4909                                                .position_size_config(Some(
4910                                                    PositionSizeConfig::default()
4911                                                        .display_method(
4912                                                            HorizontalAlign::Right,
4913                                                            VerticalAlign::Top,
4914                                                        )
4915                                                        .origin_position(
4916                                                            position[0] + size[0] - margin[1],
4917                                                            line_position,
4918                                                        )
4919                                                        .origin_size(width, line_length),
4920                                                )),
4921                                        )
4922                                    }
4923                                    BackgroundType::Image(config) => BackgroundType::Image(
4924                                        config
4925                                            .ignore_render_layer(Some(true))
4926                                            .hidden(Some(resource_panel.hidden))
4927                                            .position_size_config(Some(
4928                                                PositionSizeConfig::default()
4929                                                    .display_method(
4930                                                        HorizontalAlign::Right,
4931                                                        VerticalAlign::Top,
4932                                                    )
4933                                                    .origin_position(
4934                                                        position[0] + size[0] - margin[1],
4935                                                        line_position,
4936                                                    )
4937                                                    .origin_size(width, line_length),
4938                                            )),
4939                                    ),
4940                                }),
4941                            )?;
4942                            self.use_resource(
4943                                &RustConstructorId {
4944                                    name: format!("{}YScroll", &id.name),
4945                                    discern_type: "Background".to_string(),
4946                                },
4947                                ui,
4948                                ctx,
4949                            )?;
4950                        }
4951                        ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
4952                            resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
4953                                self.reset_split_time(&format!(
4954                                    "{}ScrollBarXAlphaStart",
4955                                    &id.name
4956                                ))?;
4957                                255
4958                            } else if self.timer.now_time
4959                                - self
4960                                    .get_split_time(&format!("{}ScrollBarXAlphaStart", &id.name))?
4961                                    [0]
4962                                >= 1000
4963                                && self.timer.now_time
4964                                    - self
4965                                        .get_split_time(&format!("{}ScrollBarXAlpha", &id.name))?[0]
4966                                    >= self.tick_interval
4967                            {
4968                                self.reset_split_time(&format!("{}ScrollBarXAlpha", &id.name))?;
4969                                resource_panel.scroll_bar_alpha[0].saturating_sub(10)
4970                            } else {
4971                                resource_panel.scroll_bar_alpha[0]
4972                            };
4973                            resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
4974                                self.reset_split_time(&format!(
4975                                    "{}ScrollBarYAlphaStart",
4976                                    &id.name
4977                                ))?;
4978                                255
4979                            } else if self.timer.now_time
4980                                - self
4981                                    .get_split_time(&format!("{}ScrollBarYAlphaStart", &id.name))?
4982                                    [0]
4983                                >= 1000
4984                                && self.timer.now_time
4985                                    - self
4986                                        .get_split_time(&format!("{}ScrollBarYAlpha", &id.name))?[0]
4987                                    >= self.tick_interval
4988                            {
4989                                self.reset_split_time(&format!("{}ScrollBarYAlpha", &id.name))?;
4990                                resource_panel.scroll_bar_alpha[1].saturating_sub(10)
4991                            } else {
4992                                resource_panel.scroll_bar_alpha[1]
4993                            };
4994                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4995                                (size[0] - margin[0] * 2_f32)
4996                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4997                            } else {
4998                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4999                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
5000                            };
5001                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
5002                                position[0]
5003                                    + margin[0]
5004                                    + (size[0] - margin[0] * 2_f32 - line_length)
5005                                        * (resource_panel.scroll_progress[0]
5006                                            / resource_panel.scroll_length[0])
5007                            } else {
5008                                position[0]
5009                                    + margin[0]
5010                                    + (size[0]
5011                                        - margin[0] * 2_f32
5012                                        - width
5013                                        - margin[1]
5014                                        - line_length)
5015                                        * (resource_panel.scroll_progress[0]
5016                                            / resource_panel.scroll_length[0])
5017                            };
5018                            self.replace_resource(
5019                                &format!("{}XScroll", &id.name),
5020                                background.clone().background_type(&match config.clone() {
5021                                    BackgroundType::CustomRect(config) => {
5022                                        BackgroundType::CustomRect(
5023                                            config
5024                                                .ignore_render_layer(Some(true))
5025                                                .hidden(Some(resource_panel.hidden))
5026                                                .position_size_config(Some(
5027                                                    PositionSizeConfig::default()
5028                                                        .display_method(
5029                                                            HorizontalAlign::Left,
5030                                                            VerticalAlign::Bottom,
5031                                                        )
5032                                                        .origin_position(
5033                                                            line_position,
5034                                                            position[1] + size[1] - margin[1],
5035                                                        )
5036                                                        .origin_size(line_length, width),
5037                                                ))
5038                                                .alpha(Some(resource_panel.scroll_bar_alpha[0]))
5039                                                .border_alpha(Some(
5040                                                    resource_panel.scroll_bar_alpha[0],
5041                                                )),
5042                                        )
5043                                    }
5044                                    BackgroundType::Image(config) => BackgroundType::Image(
5045                                        config
5046                                            .ignore_render_layer(Some(true))
5047                                            .hidden(Some(resource_panel.hidden))
5048                                            .position_size_config(Some(
5049                                                PositionSizeConfig::default()
5050                                                    .display_method(
5051                                                        HorizontalAlign::Left,
5052                                                        VerticalAlign::Bottom,
5053                                                    )
5054                                                    .origin_position(
5055                                                        line_position,
5056                                                        position[1] + size[1] - margin[1],
5057                                                    )
5058                                                    .origin_size(line_length, width),
5059                                            ))
5060                                            .alpha(Some(resource_panel.scroll_bar_alpha[0]))
5061                                            .background_alpha(Some(
5062                                                resource_panel.scroll_bar_alpha[0],
5063                                            ))
5064                                            .overlay_alpha(Some(
5065                                                resource_panel.scroll_bar_alpha[0],
5066                                            )),
5067                                    ),
5068                                }),
5069                            )?;
5070                            self.use_resource(
5071                                &RustConstructorId {
5072                                    name: format!("{}XScroll", &id.name),
5073                                    discern_type: "Background".to_string(),
5074                                },
5075                                ui,
5076                                ctx,
5077                            )?;
5078                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
5079                                (size[1] - margin[0] * 2_f32)
5080                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5081                            } else {
5082                                (size[1] - width - margin[1] - margin[0] * 2_f32)
5083                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5084                            };
5085                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
5086                                position[1]
5087                                    + margin[0]
5088                                    + (size[1] - margin[0] * 2_f32 - line_length)
5089                                        * (resource_panel.scroll_progress[1]
5090                                            / resource_panel.scroll_length[1])
5091                            } else {
5092                                position[1]
5093                                    + margin[0]
5094                                    + (size[1]
5095                                        - margin[0] * 2_f32
5096                                        - width
5097                                        - margin[1]
5098                                        - line_length)
5099                                        * (resource_panel.scroll_progress[1]
5100                                            / resource_panel.scroll_length[1])
5101                            };
5102                            self.replace_resource(
5103                                &format!("{}YScroll", &id.name),
5104                                background.clone().background_type(&match config.clone() {
5105                                    BackgroundType::CustomRect(config) => {
5106                                        BackgroundType::CustomRect(
5107                                            config
5108                                                .ignore_render_layer(Some(true))
5109                                                .hidden(Some(resource_panel.hidden))
5110                                                .position_size_config(Some(
5111                                                    PositionSizeConfig::default()
5112                                                        .display_method(
5113                                                            HorizontalAlign::Right,
5114                                                            VerticalAlign::Top,
5115                                                        )
5116                                                        .origin_position(
5117                                                            position[0] + size[0] - margin[1],
5118                                                            line_position,
5119                                                        )
5120                                                        .origin_size(width, line_length),
5121                                                ))
5122                                                .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5123                                                .border_alpha(Some(
5124                                                    resource_panel.scroll_bar_alpha[1],
5125                                                )),
5126                                        )
5127                                    }
5128                                    BackgroundType::Image(config) => BackgroundType::Image(
5129                                        config
5130                                            .ignore_render_layer(Some(true))
5131                                            .hidden(Some(resource_panel.hidden))
5132                                            .position_size_config(Some(
5133                                                PositionSizeConfig::default()
5134                                                    .display_method(
5135                                                        HorizontalAlign::Right,
5136                                                        VerticalAlign::Top,
5137                                                    )
5138                                                    .origin_position(
5139                                                        position[0] + size[0] - margin[1],
5140                                                        line_position,
5141                                                    )
5142                                                    .origin_size(width, line_length),
5143                                            ))
5144                                            .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5145                                            .background_alpha(Some(
5146                                                resource_panel.scroll_bar_alpha[1],
5147                                            ))
5148                                            .overlay_alpha(Some(
5149                                                resource_panel.scroll_bar_alpha[1],
5150                                            )),
5151                                    ),
5152                                }),
5153                            )?;
5154                            self.use_resource(
5155                                &RustConstructorId {
5156                                    name: format!("{}YScroll", &id.name),
5157                                    discern_type: "Background".to_string(),
5158                                },
5159                                ui,
5160                                ctx,
5161                            )?;
5162                        }
5163                        ScrollBarDisplayMethod::Hidden => {}
5164                    };
5165                    self.replace_resource(&id.name, resource_panel.clone())?;
5166                }
5167                _ => {}
5168            };
5169            Ok(())
5170        } else {
5171            Err(RustConstructorError {
5172                error_id: "ResourceNotFound".to_string(),
5173                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
5174            })
5175        }
5176    }
5177
5178    /// Switches to a different page and resets page-specific state.
5179    ///
5180    /// 切换到不同页面并重置页面特定状态。
5181    ///
5182    /// # Arguments
5183    ///
5184    /// * `name` - The name of the page to switch to
5185    ///
5186    /// # Returns
5187    ///
5188    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the page cannot be found.
5189    ///
5190    /// # 参数
5191    ///
5192    /// * `name` - 要切换到的页面名称
5193    ///
5194    /// # 返回值
5195    ///
5196    /// 成功时返回 `Ok(())`,如果页面无法找到则返回 `Err(RustConstructorError)`。
5197    pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
5198        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5199            name: name.to_string(),
5200            discern_type: "PageData".to_string(),
5201        })?;
5202        page_data.enter_page_updated = false;
5203        self.timer.start_time = self.timer.total_time;
5204        self.current_page = name.to_string();
5205        self.update_timer();
5206        Ok(())
5207    }
5208
5209    /// Try to register all fonts in the egui context.
5210    ///
5211    /// 尝试向egui上下文中注册所有字体。
5212    ///
5213    /// This method loads and registers all fonts with the egui rendering system for
5214    /// text display.
5215    ///
5216    /// 此方法加载并注册所有字体到egui渲染系统中,用于文本显示。
5217    ///
5218    /// # Arguments
5219    ///
5220    /// * `ctx` - The egui context for font registration
5221    /// * `font_info` - Font information, including font names and paths
5222    ///
5223    /// # 参数
5224    ///
5225    /// * `ctx` - 用于字体注册的egui上下文
5226    /// * `font_info` - 字体信息,包含字体名称和路径
5227    pub fn try_register_all_fonts(&mut self, ctx: &Context, font_info: Vec<[&str; 2]>) {
5228        let mut font_definitions_amount = FontDefinitions::default();
5229        let mut loaded_fonts = Vec::new();
5230        for font_info in font_info {
5231            let mut font = FontDefinitions::default();
5232            if let Ok(font_read_data) = read(font_info[1]) {
5233                let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
5234                font.font_data.insert(
5235                    font_info[0].to_owned(),
5236                    Arc::new(FontData::from_owned(
5237                        Arc::try_unwrap(font_data).ok().unwrap(),
5238                    )),
5239                );
5240                // 将字体添加到字体列表中
5241                font.families
5242                    .entry(FontFamily::Proportional)
5243                    .or_default()
5244                    .insert(0, font_info[0].to_owned());
5245
5246                font.families
5247                    .entry(FontFamily::Monospace)
5248                    .or_default()
5249                    .insert(0, font_info[0].to_owned());
5250                if let Some(font_data) = font.font_data.get(font_info[0]) {
5251                    font_definitions_amount
5252                        .font_data
5253                        .insert(font_info[0].to_string(), Arc::clone(font_data));
5254                    font_definitions_amount
5255                        .families
5256                        .entry(FontFamily::Name(font_info[0].into()))
5257                        .or_default()
5258                        .push(font_info[0].to_string());
5259                    // 将字体添加到字体列表中
5260                    font_definitions_amount
5261                        .families
5262                        .entry(FontFamily::Proportional)
5263                        .or_default()
5264                        .insert(0, font_info[0].to_owned());
5265
5266                    font_definitions_amount
5267                        .families
5268                        .entry(FontFamily::Monospace)
5269                        .or_default()
5270                        .insert(0, font_info[0].to_owned());
5271                    loaded_fonts.push(font_info);
5272                };
5273            }
5274        }
5275        self.loading_fonts = loaded_fonts
5276            .iter()
5277            .map(|x| [x[0].to_string(), x[1].to_string()])
5278            .collect();
5279        ctx.set_fonts(font_definitions_amount);
5280    }
5281
5282    /// Registers all fonts with the egui context.
5283    ///
5284    /// 向egui上下文中注册所有字体。
5285    ///
5286    /// This method loads and registers all fonts with the egui rendering system for
5287    /// text display.
5288    ///
5289    /// 此方法加载并注册所有字体到egui渲染系统中,用于文本显示。
5290    ///
5291    /// # Arguments
5292    ///
5293    /// * `ctx` - The egui context for font registration
5294    /// * `font_info` - Font information, including font names and paths
5295    ///
5296    /// # Returns
5297    ///
5298    /// If the loading is successfully completed, return `Ok(())`; otherwise,
5299    /// return `Err(RustConstructorError)`.
5300    ///
5301    /// # 参数
5302    ///
5303    /// * `ctx` - 用于字体注册的egui上下文
5304    /// * `font_info` - 字体信息,包含字体名称和路径
5305    ///
5306    /// # 返回值
5307    ///
5308    /// 如果成功完成加载返回`Ok(())`,否则返回`Err(RustConstructorError)`。
5309    pub fn register_all_fonts(
5310        &mut self,
5311        ctx: &Context,
5312        font_info: Vec<[&str; 2]>,
5313    ) -> Result<(), RustConstructorError> {
5314        let mut font_definitions_amount = FontDefinitions::default();
5315        let mut loaded_fonts = Vec::new();
5316        for font_info in font_info {
5317            let mut font = FontDefinitions::default();
5318            if let Ok(font_read_data) = read(font_info[1]) {
5319                let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
5320                font.font_data.insert(
5321                    font_info[0].to_owned(),
5322                    Arc::new(FontData::from_owned(
5323                        Arc::try_unwrap(font_data).ok().unwrap(),
5324                    )),
5325                );
5326                // 将字体添加到字体列表中
5327                font.families
5328                    .entry(FontFamily::Proportional)
5329                    .or_default()
5330                    .insert(0, font_info[0].to_owned());
5331
5332                font.families
5333                    .entry(FontFamily::Monospace)
5334                    .or_default()
5335                    .insert(0, font_info[0].to_owned());
5336                if let Some(font_data) = font.font_data.get(font_info[0]) {
5337                    font_definitions_amount
5338                        .font_data
5339                        .insert(font_info[0].to_string(), Arc::clone(font_data));
5340                    font_definitions_amount
5341                        .families
5342                        .entry(FontFamily::Name(font_info[0].into()))
5343                        .or_default()
5344                        .push(font_info[0].to_string());
5345                    // 将字体添加到字体列表中
5346                    font_definitions_amount
5347                        .families
5348                        .entry(FontFamily::Proportional)
5349                        .or_default()
5350                        .insert(0, font_info[0].to_owned());
5351
5352                    font_definitions_amount
5353                        .families
5354                        .entry(FontFamily::Monospace)
5355                        .or_default()
5356                        .insert(0, font_info[0].to_owned());
5357                    loaded_fonts.push(font_info);
5358                };
5359            } else {
5360                return Err(RustConstructorError {
5361                    error_id: "FontLoadFailed".to_string(),
5362                    description: format!("Failed to load a font from the path '{}'.", font_info[1]),
5363                });
5364            }
5365        }
5366        self.loading_fonts = loaded_fonts
5367            .iter()
5368            .map(|x| [x[0].to_string(), x[1].to_string()])
5369            .collect();
5370        ctx.set_fonts(font_definitions_amount);
5371        Ok(())
5372    }
5373
5374    /// Checks if a page has completed its initial loading phase.
5375    ///
5376    /// 检查页面是否已完成首次加载。
5377    ///
5378    /// # Arguments
5379    ///
5380    /// * `name` - The name of the page to check
5381    ///
5382    /// # Returns
5383    ///
5384    /// Returns `Ok(true)` if the page has completed loading, or `Ok(false)` if the page has not completed loading.
5385    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5386    ///
5387    /// # 参数
5388    ///
5389    /// * `name` - 要检查的页面名称
5390    ///
5391    /// # 返回值
5392    ///
5393    /// 如果页面已完成加载则返回 `Ok(true)`,如果未加载则返回 `Ok(false)`。
5394    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5395    pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5396        let page_data = self
5397            .get_resource::<PageData>(&RustConstructorId {
5398                name: name.to_string(),
5399                discern_type: "PageData".to_string(),
5400            })?
5401            .clone();
5402        if !page_data.change_page_updated {
5403            self.new_page_update(name)?;
5404        };
5405        Ok(page_data.change_page_updated)
5406    }
5407
5408    /// Checks if a page has completed its enter transition.
5409    ///
5410    /// 检查页面是否已完成进入过渡。
5411    ///
5412    /// # Arguments
5413    ///
5414    /// * `name` - The name of the page to check
5415    ///
5416    /// # Returns
5417    ///
5418    /// Returns `Ok(true)` if the page has completed entering, or `Ok(false)` if the page has not completed entering.
5419    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5420    ///
5421    /// # 参数
5422    ///
5423    /// * `name` - 要检查的页面名称
5424    ///
5425    /// # 返回值
5426    ///
5427    /// 如果页面已完成进入则返回 `Ok(true)`,如果未过渡则返回 `Ok(false)`。
5428    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5429    pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5430        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5431            name: name.to_string(),
5432            discern_type: "PageData".to_string(),
5433        })?;
5434        page_data.enter_page_updated = true;
5435        Ok(page_data.enter_page_updated)
5436    }
5437
5438    /// Updates when entering a new page.
5439    ///
5440    /// 进入新页面时的更新。
5441    ///
5442    /// This method is used to ensure the accuracy of the content based on the page, and the Rust Constructor will automatically call this method.
5443    ///
5444    /// 此方法用于确保基于页面的内容的准确性,Rust Constructor会自动调用此方法。
5445    ///
5446    /// # Arguments
5447    ///
5448    /// * `name` - The name of the page to be updated
5449    ///
5450    /// # Returns
5451    ///
5452    /// If the update is successful, return `Ok(())`; if the resource is not found, return `Err(RustConstructorError)`.
5453    ///
5454    /// # 参数
5455    ///
5456    /// * `name` - 要更新的页面名称
5457    ///
5458    /// # 返回值
5459    ///
5460    /// 如果更新成功则返回`Ok(())`,找不到资源则返回`Err(RustConstructorError)`。
5461    pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
5462        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5463            name: name.to_string(),
5464            discern_type: "PageData".to_string(),
5465        })?;
5466        page_data.change_page_updated = true;
5467        self.timer.start_time = self.timer.total_time;
5468        self.update_timer();
5469        Ok(())
5470    }
5471
5472    /// Updates frame timing statistics for performance monitoring.
5473    ///
5474    /// 更新帧数统计信息用于性能监控。
5475    ///
5476    /// This method maintains a rolling window of frame times and calculates
5477    /// performance metrics like frame rate.
5478    ///
5479    /// 此方法维护帧时间的滚动窗口并计算帧率等性能指标。
5480    pub fn update_frame_stats(&mut self) {
5481        let current_time = self.timer.total_time;
5482        if let Some(last) = self.last_frame_time {
5483            let delta = current_time - last;
5484            self.frame_times.push(delta);
5485            if self.frame_times.len() > 120 {
5486                self.frame_times.drain(0..120);
5487            }
5488        }
5489        self.last_frame_time = Some(current_time);
5490    }
5491
5492    /// Update the frame rate.
5493    ///
5494    /// 更新帧数。
5495    ///
5496    /// This method is used to obtain the number of program frames and conduct analysis.
5497    ///
5498    /// 此方法用于获取程序帧数并进行分析。
5499    ///
5500    /// # Returns
5501    ///
5502    /// Return the number of frames.
5503    ///
5504    /// # 返回值
5505    ///
5506    /// 返回帧数。
5507    pub fn current_fps(&self) -> f32 {
5508        if self.frame_times.is_empty() {
5509            0.0
5510        } else {
5511            1000_f32
5512                / (self.frame_times.iter().sum::<u128>() as f32 / self.frame_times.len() as f32)
5513        }
5514    }
5515
5516    /// Resets the split time for a specific resource.
5517    ///
5518    /// 重置特定资源的分段计时器。
5519    ///
5520    /// # Arguments
5521    ///
5522    /// * `name` - The name of the split time resource to reset
5523    ///
5524    /// # Returns
5525    ///
5526    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5527    ///
5528    /// # 参数
5529    ///
5530    /// * `name` - 要重置的分段时间资源名称
5531    ///
5532    /// # 返回值
5533    ///
5534    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5535    pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
5536        let new_time = [self.timer.now_time, self.timer.total_time];
5537        let split_time = self.get_resource_mut::<SplitTime>(&RustConstructorId {
5538            name: name.to_string(),
5539            discern_type: "SplitTime".to_string(),
5540        })?;
5541        split_time.time = new_time;
5542        Ok(())
5543    }
5544
5545    /// Retrieves the timing information from a split time resource.
5546    ///
5547    /// 获取分段计时器资源的时间信息。
5548    ///
5549    /// # Arguments
5550    ///
5551    /// * `name` - The name of the split time resource
5552    ///
5553    /// # Returns
5554    ///
5555    /// Returns `Ok([page_runtime, total_runtime])` if found, or `Err(RustConstructorError)` if not found.
5556    ///
5557    /// # 参数
5558    ///
5559    /// * `name` - 分段计时器资源的名称
5560    ///
5561    /// # 返回值
5562    ///
5563    /// 如果找到则返回 `Ok([页面运行时间, 总运行时间])`,否则返回 `Err(RustConstructorError)`。
5564    pub fn get_split_time(&self, name: &str) -> Result<[u128; 2], RustConstructorError> {
5565        let split_time = self.get_resource::<SplitTime>(&RustConstructorId {
5566            name: name.to_string(),
5567            discern_type: "SplitTime".to_string(),
5568        })?;
5569        Ok(split_time.time)
5570    }
5571
5572    /// Updates the application timer with current timing information.
5573    ///
5574    /// 更新应用程序计时器的当前时间信息。
5575    ///
5576    /// This method updates both the total runtime and current page runtime.
5577    ///
5578    /// 此方法更新总运行时间和当前页面运行时间。
5579    pub fn update_timer(&mut self) {
5580        let elapsed = self.timer.timer.elapsed();
5581        self.timer.total_time = elapsed.as_millis();
5582        self.timer.now_time = self.timer.total_time - self.timer.start_time
5583    }
5584
5585    /// Modifies the value of a variable resource.
5586    ///
5587    /// 修改变量资源的值。
5588    ///
5589    /// # Arguments
5590    ///
5591    /// * `name` - The name of the variable resource
5592    /// * `value` - The new value to set (use `None` to clear)
5593    ///
5594    /// # Returns
5595    ///
5596    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5597    ///
5598    /// # 参数
5599    ///
5600    /// * `name` - 变量资源的名称
5601    /// * `value` - 要设置的新值(使用 `None` 来清除)
5602    ///
5603    /// # 返回值
5604    ///
5605    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5606    pub fn modify_variable<T: Debug + 'static>(
5607        &mut self,
5608        name: &str,
5609        value: Option<T>,
5610    ) -> Result<(), RustConstructorError> {
5611        let variable = self.get_resource_mut::<Variable<T>>(&RustConstructorId {
5612            name: name.to_string(),
5613            discern_type: "Variable".to_string(),
5614        })?;
5615        variable.value = value;
5616        Ok(())
5617    }
5618
5619    /// Take the variable out of the list.
5620    ///
5621    /// 从列表中取出变量。
5622    ///
5623    /// # Arguments
5624    ///
5625    /// * `name` - The name of the variable resource
5626    ///
5627    /// # Returns
5628    ///
5629    /// Returns `Ok(Option<T>)` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5630    ///
5631    /// # 参数
5632    ///
5633    /// * `name` - 变量资源的名称
5634    ///
5635    /// # 返回值
5636    ///
5637    /// 成功时返回 `Ok(Option<T>)`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5638    pub fn get_variable<T: Debug + Clone + 'static>(
5639        &self,
5640        name: &str,
5641    ) -> Result<Option<T>, RustConstructorError> {
5642        if let Ok(variable) = self.get_resource::<Variable<T>>(&RustConstructorId {
5643            name: name.to_string(),
5644            discern_type: "Variable".to_string(),
5645        }) {
5646            Ok(variable.value.clone())
5647        } else if self
5648            .check_resource_exists(&RustConstructorId {
5649                name: name.to_string(),
5650                discern_type: "Variable".to_string(),
5651            })
5652            .is_none()
5653        {
5654            Err(RustConstructorError {
5655                error_id: "ResourceNotFound".to_string(),
5656                description: format!("Resource '{name}(Variable<T>)' not found."),
5657            })
5658        } else {
5659            Err(RustConstructorError {
5660                error_id: "ResourceGenericMismatch".to_string(),
5661                description: format!(
5662                    "The generic type of the resource '{name}(Variable<T>)' is mismatched."
5663                ),
5664            })
5665        }
5666    }
5667
5668    /// Modify the enable status of the switch.
5669    ///
5670    /// 修改开关的启用状态。
5671    ///
5672    /// # Arguments
5673    ///
5674    /// * `name` - The name of the switch resource
5675    /// * `enable` - The new enable status
5676    ///
5677    /// # Returns
5678    ///
5679    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5680    ///
5681    /// # 参数
5682    ///
5683    /// * `name` - 开关资源的名称
5684    /// * `enable` - 新的启用状态
5685    ///
5686    /// # 返回值
5687    ///
5688    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5689    pub fn set_switch_enable(
5690        &mut self,
5691        name: &str,
5692        enable: bool,
5693    ) -> Result<(), RustConstructorError> {
5694        let switch = self.get_resource_mut::<Switch>(&RustConstructorId {
5695            name: name.to_string(),
5696            discern_type: "Switch".to_string(),
5697        })?;
5698        switch.enable = enable;
5699        Ok(())
5700    }
5701
5702    /// Retrieves the current state and interaction data from a switch resource.
5703    ///
5704    /// 获取开关资源的当前状态和交互数据。
5705    ///
5706    /// # Arguments
5707    ///
5708    /// * `name` - The name of the switch resource
5709    ///
5710    /// # Returns
5711    ///
5712    /// Returns `Ok(SwitchData)` containing the switch state and interaction history,
5713    /// or `Err(RustConstructorError)` if the resource cannot be found.
5714    ///
5715    /// # 参数
5716    ///
5717    /// * `name` - 开关资源的名称
5718    ///
5719    /// # 返回值
5720    ///
5721    /// 返回包含开关状态和交互历史的 `Ok(SwitchData)`,
5722    /// 如果资源无法找到则返回 `Err(RustConstructorError)`。
5723    pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
5724        let switch = self.get_resource::<Switch>(&RustConstructorId {
5725            name: name.to_string(),
5726            discern_type: "Switch".to_string(),
5727        })?;
5728        Ok(SwitchData {
5729            switched: switch.switched,
5730            last_frame_clicked: switch.last_frame_clicked,
5731            state: switch.state,
5732        })
5733    }
5734
5735    /// Find out which switch in the radio switch group is activated.
5736    ///
5737    /// 查找单选开关组中哪个开关被激活了。
5738    ///
5739    /// # Arguments
5740    ///
5741    /// * `radio_group` - The name of the radio switch group
5742    ///
5743    /// # Returns
5744    ///
5745    /// Returns the name of the activated switch. If there is no activated switch or the
5746    /// radio switch group does not exist, return an empty string.
5747    ///
5748    /// # 参数
5749    ///
5750    /// * `radio_group` - 单选开关组的名称
5751    ///
5752    /// # 返回值
5753    ///
5754    /// 返回激活的开关的名称,如果没有激活的开关或单选开关组不存在则返回空字符串。
5755    pub fn check_radio_switch(&self, radio_group: &str) -> String {
5756        let mut activate_switch = String::new();
5757        for rcr in &self.rust_constructor_resource {
5758            if let Ok(switch) = downcast_resource::<Switch>(&*rcr.content)
5759                && switch.radio_group == radio_group
5760                && switch.state == 1
5761            {
5762                activate_switch = rcr.id.name.clone();
5763                break;
5764            };
5765        }
5766        activate_switch
5767    }
5768}