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 seconds.
49    ///
50    /// 资源更新的刷新率(秒)。
51    pub tick_interval: f32,
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<f32>,
67
68    /// Time taken to render the previous frame in seconds.
69    ///
70    /// 渲染上一帧所用的时间(秒)。
71    pub last_frame_time: Option<f32>,
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: 0.05,
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: f32) -> 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                            >= 2_f32
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                            && resource_panel.raise_on_focus
3111                            && ui.input(|i| i.pointer.primary_pressed())
3112                        {
3113                            self.request_jump_render_list(
3114                                RequestMethod::Id(RustConstructorId {
3115                                    name: format!("{}Background", &id.name),
3116                                    discern_type: match background.background_type {
3117                                        BackgroundType::CustomRect(_) => "CustomRect",
3118                                        BackgroundType::Image(_) => "Image",
3119                                    }
3120                                    .to_string(),
3121                                }),
3122                                RequestType::Top,
3123                            )
3124                            .unwrap();
3125                            let mut update_list = Vec::new();
3126                            for rcr in &self.rust_constructor_resource {
3127                                if self
3128                                    .basic_front_resource_list
3129                                    .contains(&rcr.id.discern_type)
3130                                    && let Some(panel_name) =
3131                                        get_tag("panel_name", &rcr.content.display_tags())
3132                                    && panel_name.1 == id.name
3133                                {
3134                                    update_list.push(rcr.id.clone());
3135                                };
3136                            }
3137                            for id in update_list {
3138                                self.try_request_jump_render_list(
3139                                    RequestMethod::Id(id),
3140                                    RequestType::Top,
3141                                );
3142                            }
3143                            if let ScrollBarDisplayMethod::Always(ref background_type, _, _) =
3144                                resource_panel.scroll_bar_display_method
3145                            {
3146                                self.try_request_jump_render_list(
3147                                    RequestMethod::Id(RustConstructorId {
3148                                        name: format!("{}XScroll", &id.name),
3149                                        discern_type: match background_type {
3150                                            BackgroundType::CustomRect(_) => "CustomRect",
3151                                            BackgroundType::Image(_) => "Image",
3152                                        }
3153                                        .to_string(),
3154                                    }),
3155                                    RequestType::Top,
3156                                );
3157                                self.try_request_jump_render_list(
3158                                    RequestMethod::Id(RustConstructorId {
3159                                        name: format!("{}YScroll", &id.name),
3160                                        discern_type: match background_type {
3161                                            BackgroundType::CustomRect(_) => "CustomRect",
3162                                            BackgroundType::Image(_) => "Image",
3163                                        }
3164                                        .to_string(),
3165                                    }),
3166                                    RequestType::Top,
3167                                );
3168                            };
3169                            if let ScrollBarDisplayMethod::OnlyScroll(ref background_type, _, _) =
3170                                resource_panel.scroll_bar_display_method
3171                            {
3172                                self.try_request_jump_render_list(
3173                                    RequestMethod::Id(RustConstructorId {
3174                                        name: format!("{}XScroll", &id.name),
3175                                        discern_type: match background_type {
3176                                            BackgroundType::CustomRect(_) => "CustomRect",
3177                                            BackgroundType::Image(_) => "Image",
3178                                        }
3179                                        .to_string(),
3180                                    }),
3181                                    RequestType::Top,
3182                                );
3183                                self.try_request_jump_render_list(
3184                                    RequestMethod::Id(RustConstructorId {
3185                                        name: format!("{}YScroll", &id.name),
3186                                        discern_type: match background_type {
3187                                            BackgroundType::CustomRect(_) => "CustomRect",
3188                                            BackgroundType::Image(_) => "Image",
3189                                        }
3190                                        .to_string(),
3191                                    }),
3192                                    RequestType::Top,
3193                                );
3194                            };
3195                        };
3196                        if resource_get_focus[0] {
3197                            let top_rect = Rect::from_min_size(
3198                                [position[0], position[1]].into(),
3199                                [size[0], 3_f32].into(),
3200                            );
3201                            let bottom_rect = Rect::from_min_size(
3202                                [position[0], position[1] + size[1] - 3_f32].into(),
3203                                [size[0], 3_f32].into(),
3204                            );
3205                            let left_rect = Rect::from_min_size(
3206                                [position[0], position[1]].into(),
3207                                [3_f32, size[1]].into(),
3208                            );
3209                            let right_rect = Rect::from_min_size(
3210                                [position[0] + size[0] - 3_f32, position[1]].into(),
3211                                [3_f32, size[1]].into(),
3212                            );
3213                            match [
3214                                top_rect.contains(mouse_pos),
3215                                bottom_rect.contains(mouse_pos),
3216                                left_rect.contains(mouse_pos),
3217                                right_rect.contains(mouse_pos),
3218                            ] {
3219                                [true, false, false, false] => {
3220                                    if resource_panel.resizable[0] {
3221                                        if resource_panel.last_frame_mouse_status.is_none()
3222                                            && ui.input(|i| i.pointer.primary_pressed())
3223                                        {
3224                                            resource_panel.last_frame_mouse_status = Some((
3225                                                mouse_pos.into(),
3226                                                ClickAim::TopResize,
3227                                                [
3228                                                    mouse_pos.x - position[0],
3229                                                    mouse_pos.y - position[1],
3230                                                ],
3231                                            ))
3232                                        };
3233                                        if size[1] > resource_panel.min_size[1]
3234                                            && (resource_panel.max_size.is_none()
3235                                                || size[1] < resource_panel.max_size.unwrap()[1])
3236                                        {
3237                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3238                                        } else if resource_panel.max_size.is_some()
3239                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3240                                        {
3241                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3242                                        } else {
3243                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3244                                        };
3245                                    };
3246                                }
3247                                [false, true, false, false] => {
3248                                    if resource_panel.resizable[1] {
3249                                        if resource_panel.last_frame_mouse_status.is_none()
3250                                            && ui.input(|i| i.pointer.primary_pressed())
3251                                        {
3252                                            resource_panel.last_frame_mouse_status = Some((
3253                                                mouse_pos.into(),
3254                                                ClickAim::BottomResize,
3255                                                [
3256                                                    mouse_pos.x - position[0],
3257                                                    mouse_pos.y - position[1],
3258                                                ],
3259                                            ))
3260                                        };
3261                                        if size[1] > resource_panel.min_size[1]
3262                                            && (resource_panel.max_size.is_none()
3263                                                || size[1] < resource_panel.max_size.unwrap()[1])
3264                                        {
3265                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3266                                        } else if resource_panel.max_size.is_some()
3267                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3268                                        {
3269                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3270                                        } else {
3271                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3272                                        };
3273                                    };
3274                                }
3275                                [false, false, true, false] => {
3276                                    if resource_panel.resizable[2] {
3277                                        if resource_panel.last_frame_mouse_status.is_none()
3278                                            && ui.input(|i| i.pointer.primary_pressed())
3279                                        {
3280                                            resource_panel.last_frame_mouse_status = Some((
3281                                                mouse_pos.into(),
3282                                                ClickAim::LeftResize,
3283                                                [
3284                                                    mouse_pos.x - position[0],
3285                                                    mouse_pos.y - position[1],
3286                                                ],
3287                                            ))
3288                                        };
3289                                        if size[0] > resource_panel.min_size[0]
3290                                            && (resource_panel.max_size.is_none()
3291                                                || size[0] < resource_panel.max_size.unwrap()[0])
3292                                        {
3293                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3294                                        } else if resource_panel.max_size.is_some()
3295                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3296                                        {
3297                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3298                                        } else {
3299                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3300                                        };
3301                                    };
3302                                }
3303                                [false, false, false, true] => {
3304                                    if resource_panel.resizable[3] {
3305                                        if resource_panel.last_frame_mouse_status.is_none()
3306                                            && ui.input(|i| i.pointer.primary_pressed())
3307                                        {
3308                                            resource_panel.last_frame_mouse_status = Some((
3309                                                mouse_pos.into(),
3310                                                ClickAim::RightResize,
3311                                                [
3312                                                    mouse_pos.x - position[0],
3313                                                    mouse_pos.y - position[1],
3314                                                ],
3315                                            ))
3316                                        };
3317                                        if size[0] > resource_panel.min_size[0]
3318                                            && (resource_panel.max_size.is_none()
3319                                                || size[0] < resource_panel.max_size.unwrap()[0])
3320                                        {
3321                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3322                                        } else if resource_panel.max_size.is_some()
3323                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3324                                        {
3325                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3326                                        } else {
3327                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3328                                        };
3329                                    };
3330                                }
3331                                [true, false, true, false] => {
3332                                    match [resource_panel.resizable[0], resource_panel.resizable[2]]
3333                                    {
3334                                        [true, true] => {
3335                                            if resource_panel.last_frame_mouse_status.is_none()
3336                                                && ui.input(|i| i.pointer.primary_pressed())
3337                                            {
3338                                                resource_panel.last_frame_mouse_status = Some((
3339                                                    mouse_pos.into(),
3340                                                    ClickAim::LeftTopResize,
3341                                                    [
3342                                                        mouse_pos.x - position[0],
3343                                                        mouse_pos.y - position[1],
3344                                                    ],
3345                                                ))
3346                                            };
3347                                            if size[0] > resource_panel.min_size[0]
3348                                                && (resource_panel.max_size.is_none()
3349                                                    || size[0]
3350                                                        < resource_panel.max_size.unwrap()[0])
3351                                                || size[1] > resource_panel.min_size[1]
3352                                                    && (resource_panel.max_size.is_none()
3353                                                        || size[1]
3354                                                            < resource_panel.max_size.unwrap()[1])
3355                                            {
3356                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3357                                            } else if resource_panel.max_size.is_some()
3358                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3359                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3360                                            {
3361                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3362                                            } else {
3363                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3364                                            };
3365                                        }
3366                                        [false, true] => {
3367                                            if resource_panel.last_frame_mouse_status.is_none()
3368                                                && ui.input(|i| i.pointer.primary_pressed())
3369                                            {
3370                                                resource_panel.last_frame_mouse_status = Some((
3371                                                    mouse_pos.into(),
3372                                                    ClickAim::LeftResize,
3373                                                    [
3374                                                        mouse_pos.x - position[0],
3375                                                        mouse_pos.y - position[1],
3376                                                    ],
3377                                                ))
3378                                            };
3379                                            if size[0] > resource_panel.min_size[0]
3380                                                && (resource_panel.max_size.is_none()
3381                                                    || size[0]
3382                                                        < resource_panel.max_size.unwrap()[0])
3383                                            {
3384                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3385                                            } else if resource_panel.max_size.is_some()
3386                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3387                                            {
3388                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3389                                            } else {
3390                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3391                                            };
3392                                        }
3393                                        [true, false] => {
3394                                            if resource_panel.last_frame_mouse_status.is_none()
3395                                                && ui.input(|i| i.pointer.primary_pressed())
3396                                            {
3397                                                resource_panel.last_frame_mouse_status = Some((
3398                                                    mouse_pos.into(),
3399                                                    ClickAim::TopResize,
3400                                                    [
3401                                                        mouse_pos.x - position[0],
3402                                                        mouse_pos.y - position[1],
3403                                                    ],
3404                                                ))
3405                                            };
3406                                            if size[1] > resource_panel.min_size[1]
3407                                                && (resource_panel.max_size.is_none()
3408                                                    || size[1]
3409                                                        < resource_panel.max_size.unwrap()[1])
3410                                            {
3411                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3412                                            } else if resource_panel.max_size.is_some()
3413                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3414                                            {
3415                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3416                                            } else {
3417                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3418                                            };
3419                                        }
3420                                        [false, false] => {}
3421                                    }
3422                                }
3423                                [false, true, false, true] => {
3424                                    match [resource_panel.resizable[1], resource_panel.resizable[3]]
3425                                    {
3426                                        [true, true] => {
3427                                            if resource_panel.last_frame_mouse_status.is_none()
3428                                                && ui.input(|i| i.pointer.primary_pressed())
3429                                            {
3430                                                resource_panel.last_frame_mouse_status = Some((
3431                                                    mouse_pos.into(),
3432                                                    ClickAim::RightBottomResize,
3433                                                    [
3434                                                        mouse_pos.x - position[0],
3435                                                        mouse_pos.y - position[1],
3436                                                    ],
3437                                                ))
3438                                            };
3439                                            if size[0] > resource_panel.min_size[0]
3440                                                && (resource_panel.max_size.is_none()
3441                                                    || size[0]
3442                                                        < resource_panel.max_size.unwrap()[0])
3443                                                || size[1] > resource_panel.min_size[1]
3444                                                    && (resource_panel.max_size.is_none()
3445                                                        || size[1]
3446                                                            < resource_panel.max_size.unwrap()[1])
3447                                            {
3448                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3449                                            } else if resource_panel.max_size.is_some()
3450                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3451                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3452                                            {
3453                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3454                                            } else {
3455                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3456                                            };
3457                                        }
3458                                        [false, true] => {
3459                                            if resource_panel.last_frame_mouse_status.is_none()
3460                                                && ui.input(|i| i.pointer.primary_pressed())
3461                                            {
3462                                                resource_panel.last_frame_mouse_status = Some((
3463                                                    mouse_pos.into(),
3464                                                    ClickAim::RightResize,
3465                                                    [
3466                                                        mouse_pos.x - position[0],
3467                                                        mouse_pos.y - position[1],
3468                                                    ],
3469                                                ))
3470                                            };
3471                                            if size[0] > resource_panel.min_size[0]
3472                                                && (resource_panel.max_size.is_none()
3473                                                    || size[0]
3474                                                        < resource_panel.max_size.unwrap()[0])
3475                                            {
3476                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3477                                            } else if resource_panel.max_size.is_some()
3478                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3479                                            {
3480                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3481                                            } else {
3482                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3483                                            };
3484                                        }
3485                                        [true, false] => {
3486                                            if resource_panel.last_frame_mouse_status.is_none()
3487                                                && ui.input(|i| i.pointer.primary_pressed())
3488                                            {
3489                                                resource_panel.last_frame_mouse_status = Some((
3490                                                    mouse_pos.into(),
3491                                                    ClickAim::BottomResize,
3492                                                    [
3493                                                        mouse_pos.x - position[0],
3494                                                        mouse_pos.y - position[1],
3495                                                    ],
3496                                                ))
3497                                            };
3498                                            if size[1] > resource_panel.min_size[1]
3499                                                && (resource_panel.max_size.is_none()
3500                                                    || size[1]
3501                                                        < resource_panel.max_size.unwrap()[1])
3502                                            {
3503                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3504                                            } else if resource_panel.max_size.is_some()
3505                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3506                                            {
3507                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3508                                            } else {
3509                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3510                                            };
3511                                        }
3512                                        [false, false] => {}
3513                                    }
3514                                }
3515                                [true, false, false, true] => {
3516                                    match [resource_panel.resizable[0], resource_panel.resizable[3]]
3517                                    {
3518                                        [true, true] => {
3519                                            if resource_panel.last_frame_mouse_status.is_none()
3520                                                && ui.input(|i| i.pointer.primary_pressed())
3521                                            {
3522                                                resource_panel.last_frame_mouse_status = Some((
3523                                                    mouse_pos.into(),
3524                                                    ClickAim::RightTopResize,
3525                                                    [
3526                                                        mouse_pos.x - position[0],
3527                                                        mouse_pos.y - position[1],
3528                                                    ],
3529                                                ))
3530                                            };
3531                                            if size[0] > resource_panel.min_size[0]
3532                                                && (resource_panel.max_size.is_none()
3533                                                    || size[0]
3534                                                        < resource_panel.max_size.unwrap()[0])
3535                                                || size[1] > resource_panel.min_size[1]
3536                                                    && (resource_panel.max_size.is_none()
3537                                                        || size[1]
3538                                                            < resource_panel.max_size.unwrap()[1])
3539                                            {
3540                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3541                                            } else if resource_panel.max_size.is_some()
3542                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3543                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3544                                            {
3545                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3546                                            } else {
3547                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3548                                            };
3549                                        }
3550                                        [false, true] => {
3551                                            if resource_panel.last_frame_mouse_status.is_none()
3552                                                && ui.input(|i| i.pointer.primary_pressed())
3553                                            {
3554                                                resource_panel.last_frame_mouse_status = Some((
3555                                                    mouse_pos.into(),
3556                                                    ClickAim::RightResize,
3557                                                    [
3558                                                        mouse_pos.x - position[0],
3559                                                        mouse_pos.y - position[1],
3560                                                    ],
3561                                                ))
3562                                            };
3563                                            if size[0] > resource_panel.min_size[0]
3564                                                && (resource_panel.max_size.is_none()
3565                                                    || size[0]
3566                                                        < resource_panel.max_size.unwrap()[0])
3567                                            {
3568                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3569                                            } else if resource_panel.max_size.is_some()
3570                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3571                                            {
3572                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3573                                            } else {
3574                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3575                                            };
3576                                        }
3577                                        [true, false] => {
3578                                            if resource_panel.last_frame_mouse_status.is_none()
3579                                                && ui.input(|i| i.pointer.primary_pressed())
3580                                            {
3581                                                resource_panel.last_frame_mouse_status = Some((
3582                                                    mouse_pos.into(),
3583                                                    ClickAim::TopResize,
3584                                                    [
3585                                                        mouse_pos.x - position[0],
3586                                                        mouse_pos.y - position[1],
3587                                                    ],
3588                                                ))
3589                                            };
3590                                            if size[1] > resource_panel.min_size[1]
3591                                                && (resource_panel.max_size.is_none()
3592                                                    || size[1]
3593                                                        < resource_panel.max_size.unwrap()[1])
3594                                            {
3595                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3596                                            } else if resource_panel.max_size.is_some()
3597                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3598                                            {
3599                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3600                                            } else {
3601                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3602                                            };
3603                                        }
3604                                        [false, false] => {}
3605                                    }
3606                                }
3607                                [false, true, true, false] => {
3608                                    match [resource_panel.resizable[1], resource_panel.resizable[2]]
3609                                    {
3610                                        [true, true] => {
3611                                            if resource_panel.last_frame_mouse_status.is_none()
3612                                                && ui.input(|i| i.pointer.primary_pressed())
3613                                            {
3614                                                resource_panel.last_frame_mouse_status = Some((
3615                                                    mouse_pos.into(),
3616                                                    ClickAim::LeftBottomResize,
3617                                                    [
3618                                                        mouse_pos.x - position[0],
3619                                                        mouse_pos.y - position[1],
3620                                                    ],
3621                                                ))
3622                                            };
3623                                            if size[0] > resource_panel.min_size[0]
3624                                                && (resource_panel.max_size.is_none()
3625                                                    || size[0]
3626                                                        < resource_panel.max_size.unwrap()[0])
3627                                                || size[1] > resource_panel.min_size[1]
3628                                                    && (resource_panel.max_size.is_none()
3629                                                        || size[1]
3630                                                            < resource_panel.max_size.unwrap()[1])
3631                                            {
3632                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3633                                            } else if resource_panel.max_size.is_some()
3634                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3635                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3636                                            {
3637                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
3638                                            } else {
3639                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
3640                                            };
3641                                        }
3642                                        [false, true] => {
3643                                            if resource_panel.last_frame_mouse_status.is_none()
3644                                                && ui.input(|i| i.pointer.primary_pressed())
3645                                            {
3646                                                resource_panel.last_frame_mouse_status = Some((
3647                                                    mouse_pos.into(),
3648                                                    ClickAim::LeftResize,
3649                                                    [
3650                                                        mouse_pos.x - position[0],
3651                                                        mouse_pos.y - position[1],
3652                                                    ],
3653                                                ))
3654                                            };
3655                                            if size[0] > resource_panel.min_size[0]
3656                                                && (resource_panel.max_size.is_none()
3657                                                    || size[0]
3658                                                        < resource_panel.max_size.unwrap()[0])
3659                                            {
3660                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3661                                            } else if resource_panel.max_size.is_some()
3662                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3663                                            {
3664                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3665                                            } else {
3666                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3667                                            };
3668                                        }
3669                                        [true, false] => {
3670                                            if resource_panel.last_frame_mouse_status.is_none()
3671                                                && ui.input(|i| i.pointer.primary_pressed())
3672                                            {
3673                                                resource_panel.last_frame_mouse_status = Some((
3674                                                    mouse_pos.into(),
3675                                                    ClickAim::BottomResize,
3676                                                    [
3677                                                        mouse_pos.x - position[0],
3678                                                        mouse_pos.y - position[1],
3679                                                    ],
3680                                                ))
3681                                            };
3682                                            if size[1] > resource_panel.min_size[1]
3683                                                && (resource_panel.max_size.is_none()
3684                                                    || size[1]
3685                                                        < resource_panel.max_size.unwrap()[1])
3686                                            {
3687                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3688                                            } else if resource_panel.max_size.is_some()
3689                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3690                                            {
3691                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3692                                            } else {
3693                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3694                                            };
3695                                        }
3696                                        [false, false] => {}
3697                                    }
3698                                }
3699                                _ => {}
3700                            };
3701                            resource_panel.last_frame_mouse_status =
3702                                if resource_panel.last_frame_mouse_status.is_none()
3703                                    && rect.contains(mouse_pos)
3704                                    && ui.input(|i| i.pointer.primary_pressed())
3705                                {
3706                                    Some((
3707                                        [mouse_pos.x, mouse_pos.y],
3708                                        ClickAim::Move,
3709                                        [mouse_pos.x - position[0], mouse_pos.y - position[1]],
3710                                    ))
3711                                } else if resource_panel.last_frame_mouse_status.is_some()
3712                                    && !ui.input(|i| i.pointer.primary_released())
3713                                {
3714                                    Some((
3715                                        [mouse_pos.x, mouse_pos.y],
3716                                        resource_panel.last_frame_mouse_status.unwrap().1,
3717                                        resource_panel.last_frame_mouse_status.unwrap().2,
3718                                    ))
3719                                } else {
3720                                    None
3721                                };
3722                            if resource_panel.scroll_length_method[0].is_some()
3723                                && x_scroll_delta != 0_f32
3724                                && rect.contains(mouse_pos)
3725                            {
3726                                resource_panel.scrolled[0] = true;
3727                                resource_panel.scroll_progress[0] = if resource_panel
3728                                    .scroll_progress[0]
3729                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3730                                    > resource_panel.scroll_length[0]
3731                                {
3732                                    resource_panel.scroll_length[0]
3733                                } else if resource_panel.scroll_progress[0]
3734                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3735                                    > 0_f32
3736                                {
3737                                    resource_panel.scroll_progress[0]
3738                                        + -x_scroll_delta * resource_panel.scroll_sensitivity
3739                                } else {
3740                                    0_f32
3741                                };
3742                            };
3743                            if resource_panel.scroll_length_method[1].is_some()
3744                                && y_scroll_delta != 0_f32
3745                                && rect.contains(mouse_pos)
3746                            {
3747                                resource_panel.scrolled[1] = true;
3748                                resource_panel.scroll_progress[1] = if resource_panel
3749                                    .scroll_progress[1]
3750                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3751                                    > resource_panel.scroll_length[1]
3752                                {
3753                                    resource_panel.scroll_length[1]
3754                                } else if resource_panel.scroll_progress[1]
3755                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3756                                    > 0_f32
3757                                {
3758                                    resource_panel.scroll_progress[1]
3759                                        + -y_scroll_delta * resource_panel.scroll_sensitivity
3760                                } else {
3761                                    0_f32
3762                                };
3763                            };
3764                        } else if ui.input(|i| i.pointer.primary_released()) {
3765                            resource_panel.last_frame_mouse_status = None;
3766                        };
3767                    };
3768                    if let Some((mouse_pos, click_aim, offset)) =
3769                        resource_panel.last_frame_mouse_status
3770                    {
3771                        match click_aim {
3772                            ClickAim::LeftTopResize => {
3773                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3774                                    && (resource_panel.max_size.is_none()
3775                                        || position[0] - mouse_pos[0] + size[0]
3776                                            < resource_panel.max_size.unwrap()[0])
3777                                {
3778                                    position_size_config.origin_size[0] +=
3779                                        position[0] - mouse_pos[0];
3780                                    position_size_config.origin_position[0] = mouse_pos[0];
3781                                } else if resource_panel.max_size.is_some()
3782                                    && position[0] - mouse_pos[0] + size[0]
3783                                        >= resource_panel.max_size.unwrap()[0]
3784                                {
3785                                    position_size_config.origin_position[0] -=
3786                                        resource_panel.max_size.unwrap()[0]
3787                                            - position_size_config.origin_size[0];
3788                                    position_size_config.origin_size[0] =
3789                                        resource_panel.max_size.unwrap()[0];
3790                                } else {
3791                                    position_size_config.origin_position[0] += position_size_config
3792                                        .origin_size[0]
3793                                        - resource_panel.min_size[0];
3794                                    position_size_config.origin_size[0] =
3795                                        resource_panel.min_size[0];
3796                                };
3797                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3798                                    && (resource_panel.max_size.is_none()
3799                                        || position[1] - mouse_pos[1] + size[1]
3800                                            < resource_panel.max_size.unwrap()[1])
3801                                {
3802                                    position_size_config.origin_size[1] +=
3803                                        position[1] - mouse_pos[1];
3804                                    position_size_config.origin_position[1] = mouse_pos[1];
3805                                } else if resource_panel.max_size.is_some()
3806                                    && position[1] - mouse_pos[1] + size[1]
3807                                        >= resource_panel.max_size.unwrap()[1]
3808                                {
3809                                    position_size_config.origin_position[1] -=
3810                                        resource_panel.max_size.unwrap()[1]
3811                                            - position_size_config.origin_size[1];
3812                                    position_size_config.origin_size[1] =
3813                                        resource_panel.max_size.unwrap()[1];
3814                                } else {
3815                                    position_size_config.origin_position[1] += position_size_config
3816                                        .origin_size[1]
3817                                        - resource_panel.min_size[1];
3818                                    position_size_config.origin_size[1] =
3819                                        resource_panel.min_size[1];
3820                                };
3821                                if size[0] > resource_panel.min_size[0]
3822                                    && (resource_panel.max_size.is_none()
3823                                        || size[0] < resource_panel.max_size.unwrap()[0])
3824                                    || size[1] > resource_panel.min_size[1]
3825                                        && (resource_panel.max_size.is_none()
3826                                            || size[1] < resource_panel.max_size.unwrap()[1])
3827                                {
3828                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3829                                } else if resource_panel.max_size.is_some()
3830                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3831                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3832                                {
3833                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3834                                } else {
3835                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3836                                };
3837                            }
3838                            ClickAim::RightBottomResize => {
3839                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3840                                    && (resource_panel.max_size.is_none()
3841                                        || mouse_pos[0] - position[0]
3842                                            < resource_panel.max_size.unwrap()[0])
3843                                {
3844                                    position_size_config.origin_size[0] =
3845                                        mouse_pos[0] - position[0];
3846                                } else if resource_panel.max_size.is_some()
3847                                    && mouse_pos[0] - position[0]
3848                                        >= resource_panel.max_size.unwrap()[0]
3849                                {
3850                                    position_size_config.origin_size[0] =
3851                                        resource_panel.max_size.unwrap()[0];
3852                                } else {
3853                                    position_size_config.origin_size[0] =
3854                                        resource_panel.min_size[0];
3855                                };
3856                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3857                                    && (resource_panel.max_size.is_none()
3858                                        || mouse_pos[1] - position[1]
3859                                            < resource_panel.max_size.unwrap()[1])
3860                                {
3861                                    position_size_config.origin_size[1] =
3862                                        mouse_pos[1] - position[1];
3863                                } else if resource_panel.max_size.is_some()
3864                                    && mouse_pos[1] - position[1]
3865                                        >= resource_panel.max_size.unwrap()[1]
3866                                {
3867                                    position_size_config.origin_size[1] =
3868                                        resource_panel.max_size.unwrap()[1];
3869                                } else {
3870                                    position_size_config.origin_size[1] =
3871                                        resource_panel.min_size[1];
3872                                };
3873                                if size[0] > resource_panel.min_size[0]
3874                                    && (resource_panel.max_size.is_none()
3875                                        || size[0] < resource_panel.max_size.unwrap()[0])
3876                                    || size[1] > resource_panel.min_size[1]
3877                                        && (resource_panel.max_size.is_none()
3878                                            || size[1] < resource_panel.max_size.unwrap()[1])
3879                                {
3880                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3881                                } else if resource_panel.max_size.is_some()
3882                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3883                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3884                                {
3885                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3886                                } else {
3887                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3888                                };
3889                            }
3890                            ClickAim::RightTopResize => {
3891                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3892                                    && (resource_panel.max_size.is_none()
3893                                        || mouse_pos[0] - position[0]
3894                                            < resource_panel.max_size.unwrap()[0])
3895                                {
3896                                    position_size_config.origin_size[0] =
3897                                        mouse_pos[0] - position[0];
3898                                } else if resource_panel.max_size.is_some()
3899                                    && mouse_pos[0] - position[0]
3900                                        >= resource_panel.max_size.unwrap()[0]
3901                                {
3902                                    position_size_config.origin_size[0] =
3903                                        resource_panel.max_size.unwrap()[0];
3904                                } else {
3905                                    position_size_config.origin_size[0] =
3906                                        resource_panel.min_size[0];
3907                                };
3908                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3909                                    && (resource_panel.max_size.is_none()
3910                                        || position[1] - mouse_pos[1] + size[1]
3911                                            < resource_panel.max_size.unwrap()[1])
3912                                {
3913                                    position_size_config.origin_size[1] +=
3914                                        position[1] - mouse_pos[1];
3915                                    position_size_config.origin_position[1] = mouse_pos[1];
3916                                } else if resource_panel.max_size.is_some()
3917                                    && position[1] - mouse_pos[1] + size[1]
3918                                        >= resource_panel.max_size.unwrap()[1]
3919                                {
3920                                    position_size_config.origin_position[1] -=
3921                                        resource_panel.max_size.unwrap()[1]
3922                                            - position_size_config.origin_size[1];
3923                                    position_size_config.origin_size[1] =
3924                                        resource_panel.max_size.unwrap()[1];
3925                                } else {
3926                                    position_size_config.origin_position[1] += position_size_config
3927                                        .origin_size[1]
3928                                        - resource_panel.min_size[1];
3929                                    position_size_config.origin_size[1] =
3930                                        resource_panel.min_size[1];
3931                                };
3932                                if size[0] > resource_panel.min_size[0]
3933                                    && (resource_panel.max_size.is_none()
3934                                        || size[0] < resource_panel.max_size.unwrap()[0])
3935                                    || size[1] > resource_panel.min_size[1]
3936                                        && (resource_panel.max_size.is_none()
3937                                            || size[1] < resource_panel.max_size.unwrap()[1])
3938                                {
3939                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3940                                } else if resource_panel.max_size.is_some()
3941                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3942                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3943                                {
3944                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3945                                } else {
3946                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3947                                };
3948                            }
3949                            ClickAim::LeftBottomResize => {
3950                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3951                                    && (resource_panel.max_size.is_none()
3952                                        || position[0] - mouse_pos[0] + size[0]
3953                                            < resource_panel.max_size.unwrap()[0])
3954                                {
3955                                    position_size_config.origin_size[0] +=
3956                                        position[0] - mouse_pos[0];
3957                                    position_size_config.origin_position[0] = mouse_pos[0];
3958                                } else if resource_panel.max_size.is_some()
3959                                    && position[0] - mouse_pos[0] + size[0]
3960                                        >= resource_panel.max_size.unwrap()[0]
3961                                {
3962                                    position_size_config.origin_position[0] -=
3963                                        resource_panel.max_size.unwrap()[0]
3964                                            - position_size_config.origin_size[0];
3965                                    position_size_config.origin_size[0] =
3966                                        resource_panel.max_size.unwrap()[0];
3967                                } else {
3968                                    position_size_config.origin_position[0] += position_size_config
3969                                        .origin_size[0]
3970                                        - resource_panel.min_size[0];
3971                                    position_size_config.origin_size[0] =
3972                                        resource_panel.min_size[0];
3973                                };
3974                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3975                                    && (resource_panel.max_size.is_none()
3976                                        || mouse_pos[1] - position[1]
3977                                            < resource_panel.max_size.unwrap()[1])
3978                                {
3979                                    position_size_config.origin_size[1] =
3980                                        mouse_pos[1] - position[1];
3981                                } else if resource_panel.max_size.is_some()
3982                                    && mouse_pos[1] - position[1]
3983                                        >= resource_panel.max_size.unwrap()[1]
3984                                {
3985                                    position_size_config.origin_size[1] =
3986                                        resource_panel.max_size.unwrap()[1];
3987                                } else {
3988                                    position_size_config.origin_size[1] =
3989                                        resource_panel.min_size[1];
3990                                };
3991                                if size[0] > resource_panel.min_size[0]
3992                                    && (resource_panel.max_size.is_none()
3993                                        || size[0] < resource_panel.max_size.unwrap()[0])
3994                                    || size[1] > resource_panel.min_size[1]
3995                                        && (resource_panel.max_size.is_none()
3996                                            || size[1] < resource_panel.max_size.unwrap()[1])
3997                                {
3998                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3999                                } else if resource_panel.max_size.is_some()
4000                                    && size[0] >= resource_panel.max_size.unwrap()[0]
4001                                    && size[1] >= resource_panel.max_size.unwrap()[1]
4002                                {
4003                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
4004                                } else {
4005                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
4006                                };
4007                            }
4008                            ClickAim::TopResize => {
4009                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
4010                                    && (resource_panel.max_size.is_none()
4011                                        || position[1] - mouse_pos[1] + size[1]
4012                                            < resource_panel.max_size.unwrap()[1])
4013                                {
4014                                    position_size_config.origin_size[1] +=
4015                                        position[1] - mouse_pos[1];
4016                                    position_size_config.origin_position[1] = mouse_pos[1];
4017                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4018                                } else if resource_panel.max_size.is_some()
4019                                    && position[1] - mouse_pos[1] + size[1]
4020                                        >= resource_panel.max_size.unwrap()[1]
4021                                {
4022                                    position_size_config.origin_position[1] -=
4023                                        resource_panel.max_size.unwrap()[1]
4024                                            - position_size_config.origin_size[1];
4025                                    position_size_config.origin_size[1] =
4026                                        resource_panel.max_size.unwrap()[1];
4027                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4028                                } else {
4029                                    position_size_config.origin_position[1] += position_size_config
4030                                        .origin_size[1]
4031                                        - resource_panel.min_size[1];
4032                                    position_size_config.origin_size[1] =
4033                                        resource_panel.min_size[1];
4034                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4035                                };
4036                            }
4037                            ClickAim::BottomResize => {
4038                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
4039                                    && (resource_panel.max_size.is_none()
4040                                        || mouse_pos[1] - position[1]
4041                                            < resource_panel.max_size.unwrap()[1])
4042                                {
4043                                    position_size_config.origin_size[1] =
4044                                        mouse_pos[1] - position[1];
4045                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
4046                                } else if resource_panel.max_size.is_some()
4047                                    && mouse_pos[1] - position[1]
4048                                        >= resource_panel.max_size.unwrap()[1]
4049                                {
4050                                    position_size_config.origin_size[1] =
4051                                        resource_panel.max_size.unwrap()[1];
4052                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
4053                                } else {
4054                                    position_size_config.origin_size[1] =
4055                                        resource_panel.min_size[1];
4056                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
4057                                };
4058                            }
4059                            ClickAim::LeftResize => {
4060                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
4061                                    && (resource_panel.max_size.is_none()
4062                                        || position[0] - mouse_pos[0] + size[0]
4063                                            < resource_panel.max_size.unwrap()[0])
4064                                {
4065                                    position_size_config.origin_size[0] +=
4066                                        position[0] - mouse_pos[0];
4067                                    position_size_config.origin_position[0] = mouse_pos[0];
4068                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4069                                } else if resource_panel.max_size.is_some()
4070                                    && position[0] - mouse_pos[0] + size[0]
4071                                        >= resource_panel.max_size.unwrap()[0]
4072                                {
4073                                    position_size_config.origin_position[0] -=
4074                                        resource_panel.max_size.unwrap()[0]
4075                                            - position_size_config.origin_size[0];
4076                                    position_size_config.origin_size[0] =
4077                                        resource_panel.max_size.unwrap()[0];
4078                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
4079                                } else {
4080                                    position_size_config.origin_position[0] += position_size_config
4081                                        .origin_size[0]
4082                                        - resource_panel.min_size[0];
4083                                    position_size_config.origin_size[0] =
4084                                        resource_panel.min_size[0];
4085                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
4086                                };
4087                            }
4088                            ClickAim::RightResize => {
4089                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
4090                                    && (resource_panel.max_size.is_none()
4091                                        || mouse_pos[0] - position[0]
4092                                            < resource_panel.max_size.unwrap()[0])
4093                                {
4094                                    position_size_config.origin_size[0] =
4095                                        mouse_pos[0] - position[0];
4096                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4097                                } else if resource_panel.max_size.is_some()
4098                                    && mouse_pos[0] - position[0]
4099                                        >= resource_panel.max_size.unwrap()[0]
4100                                {
4101                                    position_size_config.origin_size[0] =
4102                                        resource_panel.max_size.unwrap()[0];
4103                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
4104                                } else {
4105                                    position_size_config.origin_size[0] =
4106                                        resource_panel.min_size[0];
4107                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
4108                                };
4109                            }
4110                            ClickAim::Move => {
4111                                ctx.set_cursor_icon(match resource_panel.movable {
4112                                    [true, true] => CursorIcon::Move,
4113                                    [true, false] => CursorIcon::ResizeColumn,
4114                                    [false, true] => CursorIcon::ResizeRow,
4115                                    [false, false] => CursorIcon::NotAllowed,
4116                                });
4117                                if resource_panel.movable[0] {
4118                                    position_size_config.origin_position[0] =
4119                                        mouse_pos[0] - offset[0];
4120                                };
4121                                if resource_panel.movable[1] {
4122                                    position_size_config.origin_position[1] =
4123                                        mouse_pos[1] - offset[1];
4124                                };
4125                            }
4126                        };
4127                    };
4128                    [position, size] = position_size_processor(position_size_config, ctx);
4129                    let background_type = match background.background_type.clone() {
4130                        BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
4131                            config
4132                                .position_size_config(Some(position_size_config))
4133                                .hidden(Some(resource_panel.hidden)),
4134                        ),
4135                        BackgroundType::Image(config) => BackgroundType::Image(
4136                            config
4137                                .position_size_config(Some(position_size_config))
4138                                .hidden(Some(resource_panel.hidden)),
4139                        ),
4140                    };
4141                    self.replace_resource(
4142                        &format!("{}Background", &id.name),
4143                        background.clone().background_type(&background_type).clone(),
4144                    )?;
4145                    self.use_resource(
4146                        &RustConstructorId {
4147                            name: format!("{}Background", &id.name),
4148                            discern_type: "Background".to_string(),
4149                        },
4150                        ui,
4151                        ctx,
4152                    )?;
4153                    type PointList = Vec<([f32; 2], [f32; 2], [bool; 2], Option<String>)>;
4154                    let mut resource_point_list: PointList = Vec::new();
4155                    let mut use_resource_list = Vec::new();
4156                    let mut replace_resource_list = Vec::new();
4157                    for rcr in &self.rust_constructor_resource {
4158                        if self
4159                            .basic_front_resource_list
4160                            .contains(&rcr.id.discern_type)
4161                            && let Some(panel_name) =
4162                                get_tag("panel_name", &rcr.content.display_tags())
4163                            && panel_name.1 == id.name
4164                        {
4165                            if let [Some(citer_name), Some(citer_type)] = [
4166                                get_tag("citer_name", &rcr.content.display_tags()),
4167                                get_tag("citer_type", &rcr.content.display_tags()),
4168                            ] {
4169                                if !use_resource_list
4170                                    .iter()
4171                                    .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
4172                                {
4173                                    use_resource_list.push([citer_name.1, citer_type.1]);
4174                                };
4175                            } else if !use_resource_list
4176                                .iter()
4177                                .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
4178                            {
4179                                use_resource_list
4180                                    .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
4181                            };
4182                            let mut basic_front_resource: Box<dyn BasicFrontResource> =
4183                                match &*rcr.id.discern_type {
4184                                    "Image" => {
4185                                        Box::new(downcast_resource::<Image>(&*rcr.content)?.clone())
4186                                    }
4187                                    "Text" => {
4188                                        Box::new(downcast_resource::<Text>(&*rcr.content)?.clone())
4189                                    }
4190                                    "CustomRect" => Box::new(
4191                                        downcast_resource::<CustomRect>(&*rcr.content)?.clone(),
4192                                    ),
4193                                    _ => {
4194                                        unreachable!()
4195                                    }
4196                                };
4197                            if !resource_panel
4198                                .resource_storage
4199                                .iter()
4200                                .any(|x| x.id == rcr.id)
4201                            {
4202                                resource_panel.resource_storage.push(PanelStorage {
4203                                    id: rcr.id.clone(),
4204                                    ignore_render_layer: if let Some(display_info) =
4205                                        basic_front_resource.display_display_info()
4206                                    {
4207                                        display_info.ignore_render_layer
4208                                    } else {
4209                                        false
4210                                    },
4211                                    hidden: if let Some(display_info) =
4212                                        basic_front_resource.display_display_info()
4213                                    {
4214                                        display_info.hidden
4215                                    } else {
4216                                        false
4217                                    },
4218                                });
4219                            };
4220                            let enable_scrolling = [
4221                                get_tag("disable_x_scrolling", &rcr.content.display_tags())
4222                                    .is_none(),
4223                                get_tag("disable_y_scrolling", &rcr.content.display_tags())
4224                                    .is_none(),
4225                            ];
4226                            let offset = basic_front_resource.display_position_size_config().offset;
4227                            basic_front_resource.modify_position_size_config(
4228                                basic_front_resource
4229                                    .display_position_size_config()
4230                                    .x_location_grid(0_f32, 0_f32)
4231                                    .y_location_grid(0_f32, 0_f32)
4232                                    .x_size_grid(0_f32, 0_f32)
4233                                    .y_size_grid(0_f32, 0_f32)
4234                                    .offset(
4235                                        if enable_scrolling[0] {
4236                                            -resource_panel.scroll_progress[0]
4237                                        } else {
4238                                            offset[0]
4239                                        },
4240                                        if enable_scrolling[1] {
4241                                            -resource_panel.scroll_progress[1]
4242                                        } else {
4243                                            offset[1]
4244                                        },
4245                                    ),
4246                            );
4247                            let mut layout = resource_panel.overall_layout;
4248                            for custom_layout in &resource_panel.custom_layout {
4249                                match custom_layout {
4250                                    CustomPanelLayout::Id(layout_id, panel_layout) => {
4251                                        if rcr.id.cmp(layout_id) == Ordering::Equal {
4252                                            layout = *panel_layout;
4253                                            break;
4254                                        };
4255                                    }
4256                                    CustomPanelLayout::Type(layout_type, panel_layout) => {
4257                                        if *layout_type == rcr.id.discern_type {
4258                                            layout = *panel_layout;
4259                                        }
4260                                    }
4261                                };
4262                            }
4263                            let panel_layout_group = if let Some(panel_layout_group) =
4264                                get_tag("panel_layout_group", &basic_front_resource.display_tags())
4265                            {
4266                                Some(panel_layout_group.1)
4267                            } else {
4268                                None
4269                            };
4270                            match layout.panel_margin {
4271                                PanelMargin::Vertical(
4272                                    [top, bottom, left, right],
4273                                    move_to_bottom,
4274                                ) => {
4275                                    let mut modify_y = 0_f32;
4276                                    let [default_x_position, default_y_position] =
4277                                        match layout.panel_location {
4278                                            PanelLocation::Absolute([x, y]) => {
4279                                                [position[0] + x, position[1] + y]
4280                                            }
4281                                            PanelLocation::Relative([x, y]) => [
4282                                                position[0]
4283                                                    + if x[1] != 0_f32 {
4284                                                        size[0] / x[1] * x[0]
4285                                                    } else {
4286                                                        0_f32
4287                                                    },
4288                                                position[1]
4289                                                    + if y[1] != 0_f32 {
4290                                                        size[1] / y[1] * y[0]
4291                                                    } else {
4292                                                        0_f32
4293                                                    },
4294                                            ],
4295                                        };
4296                                    let default_x_position = match basic_front_resource
4297                                        .display_position_size_config()
4298                                        .display_method
4299                                        .0
4300                                    {
4301                                        HorizontalAlign::Left => default_x_position,
4302                                        HorizontalAlign::Center => {
4303                                            default_x_position
4304                                                - basic_front_resource.display_size()[0] / 2.0
4305                                        }
4306                                        HorizontalAlign::Right => {
4307                                            default_x_position
4308                                                - basic_front_resource.display_size()[0]
4309                                        }
4310                                    };
4311                                    let default_y_position = match basic_front_resource
4312                                        .display_position_size_config()
4313                                        .display_method
4314                                        .1
4315                                    {
4316                                        VerticalAlign::Top => default_y_position,
4317                                        VerticalAlign::Center => {
4318                                            default_y_position
4319                                                - basic_front_resource.display_size()[1] / 2.0
4320                                        }
4321                                        VerticalAlign::Bottom => {
4322                                            default_y_position
4323                                                - basic_front_resource.display_size()[1]
4324                                        }
4325                                    };
4326                                    for point in &resource_point_list {
4327                                        if let Some(ref point_panel_layout_group) = point.3
4328                                            && let Some(ref panel_layout_group) = panel_layout_group
4329                                            && panel_layout_group == point_panel_layout_group
4330                                        {
4331                                            continue;
4332                                        };
4333                                        if default_x_position - left < point.1[0]
4334                                            && default_y_position - top + modify_y < point.1[1]
4335                                            && default_x_position
4336                                                + basic_front_resource.display_size()[0]
4337                                                + right
4338                                                > point.0[0]
4339                                            && default_y_position
4340                                                + basic_front_resource.display_size()[1]
4341                                                + bottom
4342                                                + modify_y
4343                                                > point.0[1]
4344                                        {
4345                                            if move_to_bottom
4346                                                && point.1[1] - default_y_position + top > modify_y
4347                                            {
4348                                                modify_y = point.1[1] - default_y_position + top;
4349                                            } else if !move_to_bottom
4350                                                && point.0[1]
4351                                                    - default_y_position
4352                                                    - basic_front_resource.display_size()[1]
4353                                                    - bottom
4354                                                    < modify_y
4355                                            {
4356                                                modify_y = point.0[1]
4357                                                    - default_y_position
4358                                                    - basic_front_resource.display_size()[1]
4359                                                    - bottom;
4360                                            };
4361                                        };
4362                                    }
4363                                    let real_x_position = match basic_front_resource
4364                                        .display_position_size_config()
4365                                        .display_method
4366                                        .0
4367                                    {
4368                                        HorizontalAlign::Left => default_x_position,
4369                                        HorizontalAlign::Center => {
4370                                            default_x_position
4371                                                + basic_front_resource.display_size()[0] / 2.0
4372                                        }
4373                                        HorizontalAlign::Right => {
4374                                            default_x_position
4375                                                + basic_front_resource.display_size()[0]
4376                                        }
4377                                    };
4378                                    let real_y_position = match basic_front_resource
4379                                        .display_position_size_config()
4380                                        .display_method
4381                                        .1
4382                                    {
4383                                        VerticalAlign::Top => default_y_position + modify_y,
4384                                        VerticalAlign::Center => {
4385                                            default_y_position
4386                                                + modify_y
4387                                                + basic_front_resource.display_size()[1] / 2.0
4388                                        }
4389                                        VerticalAlign::Bottom => {
4390                                            default_y_position
4391                                                + modify_y
4392                                                + basic_front_resource.display_size()[1]
4393                                        }
4394                                    };
4395                                    basic_front_resource.modify_position_size_config(
4396                                        basic_front_resource
4397                                            .display_position_size_config()
4398                                            .origin_position(
4399                                                real_x_position
4400                                                    + left
4401                                                    + resource_panel.inner_margin[2],
4402                                                real_y_position
4403                                                    + top
4404                                                    + resource_panel.inner_margin[0],
4405                                            ),
4406                                    );
4407                                    replace_resource_list.push((
4408                                        basic_front_resource.display_position_size_config(),
4409                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4410                                    ));
4411                                    resource_point_list.push((
4412                                        [real_x_position - left, real_y_position - top],
4413                                        [
4414                                            real_x_position
4415                                                + basic_front_resource.display_size()[0]
4416                                                + right,
4417                                            real_y_position
4418                                                + basic_front_resource.display_size()[1]
4419                                                + bottom,
4420                                        ],
4421                                        enable_scrolling,
4422                                        panel_layout_group,
4423                                    ));
4424                                }
4425                                PanelMargin::Horizontal(
4426                                    [top, bottom, left, right],
4427                                    move_to_right,
4428                                ) => {
4429                                    let mut modify_x = 0_f32;
4430                                    let [default_x_position, default_y_position] =
4431                                        match layout.panel_location {
4432                                            PanelLocation::Absolute([x, y]) => {
4433                                                [position[0] + x, position[1] + y]
4434                                            }
4435                                            PanelLocation::Relative([x, y]) => [
4436                                                position[0]
4437                                                    + if x[1] != 0_f32 {
4438                                                        size[0] / x[1] * x[0]
4439                                                    } else {
4440                                                        0_f32
4441                                                    },
4442                                                position[1]
4443                                                    + if y[1] != 0_f32 {
4444                                                        size[1] / y[1] * y[0]
4445                                                    } else {
4446                                                        0_f32
4447                                                    },
4448                                            ],
4449                                        };
4450                                    let default_x_position = match basic_front_resource
4451                                        .display_position_size_config()
4452                                        .display_method
4453                                        .0
4454                                    {
4455                                        HorizontalAlign::Left => default_x_position,
4456                                        HorizontalAlign::Center => {
4457                                            default_x_position
4458                                                - basic_front_resource.display_size()[0] / 2.0
4459                                        }
4460                                        HorizontalAlign::Right => {
4461                                            default_x_position
4462                                                - basic_front_resource.display_size()[0]
4463                                        }
4464                                    };
4465                                    let default_y_position = match basic_front_resource
4466                                        .display_position_size_config()
4467                                        .display_method
4468                                        .1
4469                                    {
4470                                        VerticalAlign::Top => default_y_position,
4471                                        VerticalAlign::Center => {
4472                                            default_y_position
4473                                                - basic_front_resource.display_size()[1] / 2.0
4474                                        }
4475                                        VerticalAlign::Bottom => {
4476                                            default_y_position
4477                                                - basic_front_resource.display_size()[1]
4478                                        }
4479                                    };
4480                                    for point in &resource_point_list {
4481                                        if let Some(ref point_panel_layout_group) = point.3
4482                                            && let Some(ref panel_layout_group) = panel_layout_group
4483                                            && panel_layout_group == point_panel_layout_group
4484                                        {
4485                                            continue;
4486                                        };
4487                                        if default_x_position - left + modify_x < point.1[0]
4488                                            && default_y_position - top < point.1[1]
4489                                            && default_x_position
4490                                                + basic_front_resource.display_size()[0]
4491                                                + right
4492                                                + modify_x
4493                                                > point.0[0]
4494                                            && default_y_position
4495                                                + basic_front_resource.display_size()[1]
4496                                                + bottom
4497                                                > point.0[1]
4498                                        {
4499                                            if move_to_right
4500                                                && point.1[0] - default_x_position + left > modify_x
4501                                            {
4502                                                modify_x = point.1[0] - default_x_position + left;
4503                                            } else if !move_to_right
4504                                                && point.0[0]
4505                                                    - default_x_position
4506                                                    - basic_front_resource.display_size()[0]
4507                                                    - right
4508                                                    < modify_x
4509                                            {
4510                                                modify_x = point.0[0]
4511                                                    - default_x_position
4512                                                    - basic_front_resource.display_size()[0]
4513                                                    - right;
4514                                            };
4515                                        };
4516                                    }
4517                                    let real_x_position = match basic_front_resource
4518                                        .display_position_size_config()
4519                                        .display_method
4520                                        .0
4521                                    {
4522                                        HorizontalAlign::Left => default_x_position + modify_x,
4523                                        HorizontalAlign::Center => {
4524                                            default_x_position
4525                                                + modify_x
4526                                                + basic_front_resource.display_size()[0] / 2.0
4527                                        }
4528                                        HorizontalAlign::Right => {
4529                                            default_x_position
4530                                                + modify_x
4531                                                + basic_front_resource.display_size()[0]
4532                                        }
4533                                    };
4534                                    let real_y_position = match basic_front_resource
4535                                        .display_position_size_config()
4536                                        .display_method
4537                                        .1
4538                                    {
4539                                        VerticalAlign::Top => default_y_position,
4540                                        VerticalAlign::Center => {
4541                                            default_y_position
4542                                                + basic_front_resource.display_size()[1] / 2.0
4543                                        }
4544                                        VerticalAlign::Bottom => {
4545                                            default_y_position
4546                                                + basic_front_resource.display_size()[1]
4547                                        }
4548                                    };
4549                                    basic_front_resource.modify_position_size_config(
4550                                        basic_front_resource
4551                                            .display_position_size_config()
4552                                            .origin_position(
4553                                                real_x_position
4554                                                    + left
4555                                                    + resource_panel.inner_margin[2],
4556                                                real_y_position
4557                                                    + top
4558                                                    + resource_panel.inner_margin[0],
4559                                            ),
4560                                    );
4561                                    replace_resource_list.push((
4562                                        basic_front_resource.display_position_size_config(),
4563                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4564                                    ));
4565                                    resource_point_list.push((
4566                                        [real_x_position - left, real_y_position - top],
4567                                        [
4568                                            real_x_position
4569                                                + basic_front_resource.display_size()[0]
4570                                                + right,
4571                                            real_y_position
4572                                                + basic_front_resource.display_size()[1]
4573                                                + bottom,
4574                                        ],
4575                                        enable_scrolling,
4576                                        panel_layout_group,
4577                                    ));
4578                                }
4579                                PanelMargin::None([top, bottom, left, right], influence_layout) => {
4580                                    let [default_x_position, default_y_position] =
4581                                        match layout.panel_location {
4582                                            PanelLocation::Absolute([x, y]) => {
4583                                                [position[0] + x, position[1] + y]
4584                                            }
4585                                            PanelLocation::Relative([x, y]) => [
4586                                                position[0]
4587                                                    + if x[1] != 0_f32 {
4588                                                        size[0] / x[1] * x[0]
4589                                                    } else {
4590                                                        0_f32
4591                                                    },
4592                                                position[1]
4593                                                    + if y[1] != 0_f32 {
4594                                                        size[1] / y[1] * y[0]
4595                                                    } else {
4596                                                        0_f32
4597                                                    },
4598                                            ],
4599                                        };
4600                                    basic_front_resource.modify_position_size_config(
4601                                        basic_front_resource
4602                                            .display_position_size_config()
4603                                            .origin_position(
4604                                                default_x_position
4605                                                    + left
4606                                                    + resource_panel.inner_margin[2],
4607                                                default_y_position
4608                                                    + top
4609                                                    + resource_panel.inner_margin[0],
4610                                            ),
4611                                    );
4612                                    replace_resource_list.push((
4613                                        basic_front_resource.display_position_size_config(),
4614                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4615                                    ));
4616                                    if influence_layout {
4617                                        resource_point_list.push((
4618                                            [default_x_position - left, default_y_position - top],
4619                                            [
4620                                                default_x_position
4621                                                    + basic_front_resource.display_size()[0]
4622                                                    + right,
4623                                                default_y_position
4624                                                    + basic_front_resource.display_size()[1]
4625                                                    + bottom,
4626                                            ],
4627                                            enable_scrolling,
4628                                            panel_layout_group,
4629                                        ));
4630                                    };
4631                                }
4632                            };
4633                        };
4634                    }
4635                    for (new_position_size_config, [name, discern_type]) in replace_resource_list {
4636                        let id = RustConstructorId {
4637                            name: name.clone(),
4638                            discern_type: discern_type.clone(),
4639                        };
4640                        let default_storage = if let Some(resource_storage) =
4641                            resource_panel.resource_storage.iter().find(|x| x.id == id)
4642                        {
4643                            [
4644                                true,
4645                                resource_storage.ignore_render_layer,
4646                                resource_storage.hidden,
4647                            ]
4648                        } else {
4649                            [false, true, true]
4650                        };
4651                        let basic_front_resource = self.get_basic_front_resource_mut(&id)?;
4652                        basic_front_resource.modify_position_size_config(new_position_size_config);
4653                        basic_front_resource.modify_clip_rect(Some(
4654                            position_size_config
4655                                .origin_size(
4656                                    position_size_config.origin_size[0]
4657                                        - resource_panel.inner_margin[2]
4658                                        - resource_panel.inner_margin[3],
4659                                    position_size_config.origin_size[1]
4660                                        - resource_panel.inner_margin[0]
4661                                        - resource_panel.inner_margin[1],
4662                                )
4663                                .origin_position(
4664                                    position_size_config.origin_position[0]
4665                                        + resource_panel.inner_margin[2],
4666                                    position_size_config.origin_position[1]
4667                                        + resource_panel.inner_margin[0],
4668                                ),
4669                        ));
4670                        basic_front_resource.modify_display_info({
4671                            let mut display_info =
4672                                basic_front_resource.display_display_info().unwrap();
4673                            display_info.ignore_render_layer =
4674                                if (resource_panel.last_frame_mouse_status.is_some()
4675                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32))
4676                                    && resource_get_focus[1]
4677                                {
4678                                    true
4679                                } else if default_storage[0] {
4680                                    default_storage[1]
4681                                } else {
4682                                    display_info.ignore_render_layer
4683                                };
4684                            display_info.hidden = if resource_panel.hidden {
4685                                true
4686                            } else if default_storage[0] {
4687                                default_storage[2]
4688                            } else {
4689                                display_info.hidden
4690                            };
4691                            display_info
4692                        });
4693                    }
4694                    for info in use_resource_list {
4695                        self.use_resource(
4696                            &RustConstructorId {
4697                                name: info[0].clone(),
4698                                discern_type: info[1].clone(),
4699                            },
4700                            ui,
4701                            ctx,
4702                        )?;
4703                    }
4704                    let mut resource_length = [None, None];
4705                    for point in resource_point_list {
4706                        resource_length = [
4707                            if resource_length[0].is_none()
4708                                || resource_length[0].is_some()
4709                                    && point.1[0] > resource_length[0].unwrap()
4710                                    && point.2[0]
4711                            {
4712                                Some(point.1[0])
4713                            } else {
4714                                resource_length[0]
4715                            },
4716                            if resource_length[1].is_none()
4717                                || resource_length[1].is_some()
4718                                    && point.1[1] > resource_length[1].unwrap()
4719                                    && point.2[1]
4720                            {
4721                                Some(point.1[1])
4722                            } else {
4723                                resource_length[1]
4724                            },
4725                        ]
4726                    }
4727                    if let Some(horizontal_scroll_length_method) =
4728                        resource_panel.scroll_length_method[0]
4729                    {
4730                        let margin = match resource_panel.overall_layout.panel_margin {
4731                            PanelMargin::Horizontal([_, _, left, right], _) => left + right,
4732                            PanelMargin::Vertical([_, _, left, right], _) => left + right,
4733                            PanelMargin::None([_, _, left, right], _) => left + right,
4734                        };
4735                        resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
4736                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4737                            ScrollLengthMethod::AutoFit(expand) => {
4738                                if let Some(max) = resource_length[0] {
4739                                    let width = max - position[0];
4740                                    if width - size[0]
4741                                        + expand
4742                                        + margin
4743                                        + resource_panel.inner_margin[3]
4744                                        + resource_panel.inner_margin[2]
4745                                        > 0_f32
4746                                    {
4747                                        width - size[0]
4748                                            + expand
4749                                            + margin
4750                                            + resource_panel.inner_margin[3]
4751                                            + resource_panel.inner_margin[2]
4752                                    } else {
4753                                        0_f32
4754                                    }
4755                                } else {
4756                                    0_f32
4757                                }
4758                            }
4759                        };
4760                        if resource_panel.scroll_progress[0] > resource_panel.scroll_length[0] {
4761                            resource_panel.scroll_progress[0] = resource_panel.scroll_length[0];
4762                        };
4763                    };
4764                    if let Some(vertical_scroll_length_method) =
4765                        resource_panel.scroll_length_method[1]
4766                    {
4767                        let margin = match resource_panel.overall_layout.panel_margin {
4768                            PanelMargin::Horizontal([top, bottom, _, _], _) => top + bottom,
4769                            PanelMargin::Vertical([top, bottom, _, _], _) => top + bottom,
4770                            PanelMargin::None([top, bottom, _, _], _) => top + bottom,
4771                        };
4772                        resource_panel.scroll_length[1] = match vertical_scroll_length_method {
4773                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4774                            ScrollLengthMethod::AutoFit(expand) => {
4775                                if let Some(max) = resource_length[1] {
4776                                    let height = max - position[1];
4777                                    if height - size[1]
4778                                        + expand
4779                                        + margin
4780                                        + resource_panel.inner_margin[1]
4781                                        + resource_panel.inner_margin[0]
4782                                        > 0_f32
4783                                    {
4784                                        height - size[1]
4785                                            + expand
4786                                            + margin
4787                                            + resource_panel.inner_margin[1]
4788                                            + resource_panel.inner_margin[0]
4789                                    } else {
4790                                        0_f32
4791                                    }
4792                                } else {
4793                                    0_f32
4794                                }
4795                            }
4796                        };
4797                        if resource_panel.scroll_progress[1] > resource_panel.scroll_length[1] {
4798                            resource_panel.scroll_progress[1] = resource_panel.scroll_length[1];
4799                        };
4800                    };
4801                    match resource_panel.scroll_bar_display_method {
4802                        ScrollBarDisplayMethod::Always(ref config, margin, width) => {
4803                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4804                                (size[0] - margin[0] * 2_f32)
4805                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4806                            } else {
4807                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4808                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4809                            };
4810                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
4811                                position[0]
4812                                    + margin[0]
4813                                    + (size[0] - margin[0] * 2_f32 - line_length)
4814                                        * (resource_panel.scroll_progress[0]
4815                                            / resource_panel.scroll_length[0])
4816                            } else {
4817                                position[0]
4818                                    + margin[0]
4819                                    + (size[0]
4820                                        - margin[0] * 2_f32
4821                                        - width
4822                                        - margin[1]
4823                                        - line_length)
4824                                        * (resource_panel.scroll_progress[0]
4825                                            / resource_panel.scroll_length[0])
4826                            };
4827                            self.replace_resource(
4828                                &format!("{}XScroll", &id.name),
4829                                background.clone().background_type(&match config.clone() {
4830                                    BackgroundType::CustomRect(config) => {
4831                                        BackgroundType::CustomRect(
4832                                            config
4833                                                .ignore_render_layer(Some(true))
4834                                                .hidden(Some(resource_panel.hidden))
4835                                                .position_size_config(Some(
4836                                                    PositionSizeConfig::default()
4837                                                        .display_method(
4838                                                            HorizontalAlign::Left,
4839                                                            VerticalAlign::Bottom,
4840                                                        )
4841                                                        .origin_position(
4842                                                            line_position,
4843                                                            position[1] + size[1] - margin[1],
4844                                                        )
4845                                                        .origin_size(line_length, width),
4846                                                )),
4847                                        )
4848                                    }
4849                                    BackgroundType::Image(config) => BackgroundType::Image(
4850                                        config
4851                                            .ignore_render_layer(Some(true))
4852                                            .hidden(Some(resource_panel.hidden))
4853                                            .position_size_config(Some(
4854                                                PositionSizeConfig::default()
4855                                                    .display_method(
4856                                                        HorizontalAlign::Left,
4857                                                        VerticalAlign::Bottom,
4858                                                    )
4859                                                    .origin_position(
4860                                                        line_position,
4861                                                        position[1] + size[1] - margin[1],
4862                                                    )
4863                                                    .origin_size(line_length, width),
4864                                            )),
4865                                    ),
4866                                }),
4867                            )?;
4868                            self.use_resource(
4869                                &RustConstructorId {
4870                                    name: format!("{}XScroll", &id.name),
4871                                    discern_type: "Background".to_string(),
4872                                },
4873                                ui,
4874                                ctx,
4875                            )?;
4876                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
4877                                (size[1] - margin[0] * 2_f32)
4878                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4879                            } else {
4880                                (size[1] - width - margin[1] - margin[0] * 2_f32)
4881                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4882                            };
4883                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
4884                                position[1]
4885                                    + margin[0]
4886                                    + (size[1] - margin[0] * 2_f32 - line_length)
4887                                        * (resource_panel.scroll_progress[1]
4888                                            / resource_panel.scroll_length[1])
4889                            } else {
4890                                position[1]
4891                                    + margin[0]
4892                                    + (size[1]
4893                                        - margin[0] * 2_f32
4894                                        - width
4895                                        - margin[1]
4896                                        - line_length)
4897                                        * (resource_panel.scroll_progress[1]
4898                                            / resource_panel.scroll_length[1])
4899                            };
4900                            self.replace_resource(
4901                                &format!("{}YScroll", &id.name),
4902                                background.background_type(&match config.clone() {
4903                                    BackgroundType::CustomRect(config) => {
4904                                        BackgroundType::CustomRect(
4905                                            config
4906                                                .ignore_render_layer(Some(true))
4907                                                .hidden(Some(resource_panel.hidden))
4908                                                .position_size_config(Some(
4909                                                    PositionSizeConfig::default()
4910                                                        .display_method(
4911                                                            HorizontalAlign::Right,
4912                                                            VerticalAlign::Top,
4913                                                        )
4914                                                        .origin_position(
4915                                                            position[0] + size[0] - margin[1],
4916                                                            line_position,
4917                                                        )
4918                                                        .origin_size(width, line_length),
4919                                                )),
4920                                        )
4921                                    }
4922                                    BackgroundType::Image(config) => BackgroundType::Image(
4923                                        config
4924                                            .ignore_render_layer(Some(true))
4925                                            .hidden(Some(resource_panel.hidden))
4926                                            .position_size_config(Some(
4927                                                PositionSizeConfig::default()
4928                                                    .display_method(
4929                                                        HorizontalAlign::Right,
4930                                                        VerticalAlign::Top,
4931                                                    )
4932                                                    .origin_position(
4933                                                        position[0] + size[0] - margin[1],
4934                                                        line_position,
4935                                                    )
4936                                                    .origin_size(width, line_length),
4937                                            )),
4938                                    ),
4939                                }),
4940                            )?;
4941                            self.use_resource(
4942                                &RustConstructorId {
4943                                    name: format!("{}YScroll", &id.name),
4944                                    discern_type: "Background".to_string(),
4945                                },
4946                                ui,
4947                                ctx,
4948                            )?;
4949                        }
4950                        ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
4951                            resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
4952                                self.reset_split_time(&format!(
4953                                    "{}ScrollBarXAlphaStart",
4954                                    &id.name
4955                                ))?;
4956                                255
4957                            } else if self.timer.now_time
4958                                - self
4959                                    .get_split_time(&format!("{}ScrollBarXAlphaStart", &id.name))?
4960                                    [0]
4961                                >= 1_f32
4962                                && self.timer.now_time
4963                                    - self
4964                                        .get_split_time(&format!("{}ScrollBarXAlpha", &id.name))?[0]
4965                                    >= self.tick_interval
4966                            {
4967                                self.reset_split_time(&format!("{}ScrollBarXAlpha", &id.name))?;
4968                                resource_panel.scroll_bar_alpha[0].saturating_sub(10)
4969                            } else {
4970                                resource_panel.scroll_bar_alpha[0]
4971                            };
4972                            resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
4973                                self.reset_split_time(&format!(
4974                                    "{}ScrollBarYAlphaStart",
4975                                    &id.name
4976                                ))?;
4977                                255
4978                            } else if self.timer.now_time
4979                                - self
4980                                    .get_split_time(&format!("{}ScrollBarYAlphaStart", &id.name))?
4981                                    [0]
4982                                >= 1_f32
4983                                && self.timer.now_time
4984                                    - self
4985                                        .get_split_time(&format!("{}ScrollBarYAlpha", &id.name))?[0]
4986                                    >= self.tick_interval
4987                            {
4988                                self.reset_split_time(&format!("{}ScrollBarYAlpha", &id.name))?;
4989                                resource_panel.scroll_bar_alpha[1].saturating_sub(10)
4990                            } else {
4991                                resource_panel.scroll_bar_alpha[1]
4992                            };
4993                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4994                                (size[0] - margin[0] * 2_f32)
4995                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4996                            } else {
4997                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4998                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4999                            };
5000                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
5001                                position[0]
5002                                    + margin[0]
5003                                    + (size[0] - margin[0] * 2_f32 - line_length)
5004                                        * (resource_panel.scroll_progress[0]
5005                                            / resource_panel.scroll_length[0])
5006                            } else {
5007                                position[0]
5008                                    + margin[0]
5009                                    + (size[0]
5010                                        - margin[0] * 2_f32
5011                                        - width
5012                                        - margin[1]
5013                                        - line_length)
5014                                        * (resource_panel.scroll_progress[0]
5015                                            / resource_panel.scroll_length[0])
5016                            };
5017                            self.replace_resource(
5018                                &format!("{}XScroll", &id.name),
5019                                background.clone().background_type(&match config.clone() {
5020                                    BackgroundType::CustomRect(config) => {
5021                                        BackgroundType::CustomRect(
5022                                            config
5023                                                .ignore_render_layer(Some(true))
5024                                                .hidden(Some(resource_panel.hidden))
5025                                                .position_size_config(Some(
5026                                                    PositionSizeConfig::default()
5027                                                        .display_method(
5028                                                            HorizontalAlign::Left,
5029                                                            VerticalAlign::Bottom,
5030                                                        )
5031                                                        .origin_position(
5032                                                            line_position,
5033                                                            position[1] + size[1] - margin[1],
5034                                                        )
5035                                                        .origin_size(line_length, width),
5036                                                ))
5037                                                .alpha(Some(resource_panel.scroll_bar_alpha[0]))
5038                                                .border_alpha(Some(
5039                                                    resource_panel.scroll_bar_alpha[0],
5040                                                )),
5041                                        )
5042                                    }
5043                                    BackgroundType::Image(config) => BackgroundType::Image(
5044                                        config
5045                                            .ignore_render_layer(Some(true))
5046                                            .hidden(Some(resource_panel.hidden))
5047                                            .position_size_config(Some(
5048                                                PositionSizeConfig::default()
5049                                                    .display_method(
5050                                                        HorizontalAlign::Left,
5051                                                        VerticalAlign::Bottom,
5052                                                    )
5053                                                    .origin_position(
5054                                                        line_position,
5055                                                        position[1] + size[1] - margin[1],
5056                                                    )
5057                                                    .origin_size(line_length, width),
5058                                            ))
5059                                            .alpha(Some(resource_panel.scroll_bar_alpha[0]))
5060                                            .background_alpha(Some(
5061                                                resource_panel.scroll_bar_alpha[0],
5062                                            ))
5063                                            .overlay_alpha(Some(
5064                                                resource_panel.scroll_bar_alpha[0],
5065                                            )),
5066                                    ),
5067                                }),
5068                            )?;
5069                            self.use_resource(
5070                                &RustConstructorId {
5071                                    name: format!("{}XScroll", &id.name),
5072                                    discern_type: "Background".to_string(),
5073                                },
5074                                ui,
5075                                ctx,
5076                            )?;
5077                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
5078                                (size[1] - margin[0] * 2_f32)
5079                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5080                            } else {
5081                                (size[1] - width - margin[1] - margin[0] * 2_f32)
5082                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5083                            };
5084                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
5085                                position[1]
5086                                    + margin[0]
5087                                    + (size[1] - margin[0] * 2_f32 - line_length)
5088                                        * (resource_panel.scroll_progress[1]
5089                                            / resource_panel.scroll_length[1])
5090                            } else {
5091                                position[1]
5092                                    + margin[0]
5093                                    + (size[1]
5094                                        - margin[0] * 2_f32
5095                                        - width
5096                                        - margin[1]
5097                                        - line_length)
5098                                        * (resource_panel.scroll_progress[1]
5099                                            / resource_panel.scroll_length[1])
5100                            };
5101                            self.replace_resource(
5102                                &format!("{}YScroll", &id.name),
5103                                background.clone().background_type(&match config.clone() {
5104                                    BackgroundType::CustomRect(config) => {
5105                                        BackgroundType::CustomRect(
5106                                            config
5107                                                .ignore_render_layer(Some(true))
5108                                                .hidden(Some(resource_panel.hidden))
5109                                                .position_size_config(Some(
5110                                                    PositionSizeConfig::default()
5111                                                        .display_method(
5112                                                            HorizontalAlign::Right,
5113                                                            VerticalAlign::Top,
5114                                                        )
5115                                                        .origin_position(
5116                                                            position[0] + size[0] - margin[1],
5117                                                            line_position,
5118                                                        )
5119                                                        .origin_size(width, line_length),
5120                                                ))
5121                                                .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5122                                                .border_alpha(Some(
5123                                                    resource_panel.scroll_bar_alpha[1],
5124                                                )),
5125                                        )
5126                                    }
5127                                    BackgroundType::Image(config) => BackgroundType::Image(
5128                                        config
5129                                            .ignore_render_layer(Some(true))
5130                                            .hidden(Some(resource_panel.hidden))
5131                                            .position_size_config(Some(
5132                                                PositionSizeConfig::default()
5133                                                    .display_method(
5134                                                        HorizontalAlign::Right,
5135                                                        VerticalAlign::Top,
5136                                                    )
5137                                                    .origin_position(
5138                                                        position[0] + size[0] - margin[1],
5139                                                        line_position,
5140                                                    )
5141                                                    .origin_size(width, line_length),
5142                                            ))
5143                                            .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5144                                            .background_alpha(Some(
5145                                                resource_panel.scroll_bar_alpha[1],
5146                                            ))
5147                                            .overlay_alpha(Some(
5148                                                resource_panel.scroll_bar_alpha[1],
5149                                            )),
5150                                    ),
5151                                }),
5152                            )?;
5153                            self.use_resource(
5154                                &RustConstructorId {
5155                                    name: format!("{}YScroll", &id.name),
5156                                    discern_type: "Background".to_string(),
5157                                },
5158                                ui,
5159                                ctx,
5160                            )?;
5161                        }
5162                        ScrollBarDisplayMethod::Hidden => {}
5163                    };
5164                    self.replace_resource(&id.name, resource_panel.clone())?;
5165                }
5166                _ => {}
5167            };
5168            Ok(())
5169        } else {
5170            Err(RustConstructorError {
5171                error_id: "ResourceNotFound".to_string(),
5172                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
5173            })
5174        }
5175    }
5176
5177    /// Switches to a different page and resets page-specific state.
5178    ///
5179    /// 切换到不同页面并重置页面特定状态。
5180    ///
5181    /// # Arguments
5182    ///
5183    /// * `name` - The name of the page to switch to
5184    ///
5185    /// # Returns
5186    ///
5187    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the page cannot be found.
5188    ///
5189    /// # 参数
5190    ///
5191    /// * `name` - 要切换到的页面名称
5192    ///
5193    /// # 返回值
5194    ///
5195    /// 成功时返回 `Ok(())`,如果页面无法找到则返回 `Err(RustConstructorError)`。
5196    pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
5197        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5198            name: name.to_string(),
5199            discern_type: "PageData".to_string(),
5200        })?;
5201        page_data.enter_page_updated = false;
5202        self.timer.start_time = self.timer.total_time;
5203        self.current_page = name.to_string();
5204        self.update_timer();
5205        Ok(())
5206    }
5207
5208    /// Try to register all fonts in the egui context.
5209    ///
5210    /// 尝试向egui上下文中注册所有字体。
5211    ///
5212    /// This method loads and registers all fonts with the egui rendering system for
5213    /// text display.
5214    ///
5215    /// 此方法加载并注册所有字体到egui渲染系统中,用于文本显示。
5216    ///
5217    /// # Arguments
5218    ///
5219    /// * `ctx` - The egui context for font registration
5220    /// * `font_info` - Font information, including font names and paths
5221    ///
5222    /// # 参数
5223    ///
5224    /// * `ctx` - 用于字体注册的egui上下文
5225    /// * `font_info` - 字体信息,包含字体名称和路径
5226    pub fn try_register_all_fonts(&mut self, ctx: &Context, font_info: Vec<[&str; 2]>) {
5227        let mut font_definitions_amount = FontDefinitions::default();
5228        let mut loaded_fonts = Vec::new();
5229        for font_info in font_info {
5230            let mut font = FontDefinitions::default();
5231            if let Ok(font_read_data) = read(font_info[1]) {
5232                let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
5233                font.font_data.insert(
5234                    font_info[0].to_owned(),
5235                    Arc::new(FontData::from_owned(
5236                        Arc::try_unwrap(font_data).ok().unwrap(),
5237                    )),
5238                );
5239                // 将字体添加到字体列表中
5240                font.families
5241                    .entry(FontFamily::Proportional)
5242                    .or_default()
5243                    .insert(0, font_info[0].to_owned());
5244
5245                font.families
5246                    .entry(FontFamily::Monospace)
5247                    .or_default()
5248                    .insert(0, font_info[0].to_owned());
5249                if let Some(font_data) = font.font_data.get(font_info[0]) {
5250                    font_definitions_amount
5251                        .font_data
5252                        .insert(font_info[0].to_string(), Arc::clone(font_data));
5253                    font_definitions_amount
5254                        .families
5255                        .entry(FontFamily::Name(font_info[0].into()))
5256                        .or_default()
5257                        .push(font_info[0].to_string());
5258                    // 将字体添加到字体列表中
5259                    font_definitions_amount
5260                        .families
5261                        .entry(FontFamily::Proportional)
5262                        .or_default()
5263                        .insert(0, font_info[0].to_owned());
5264
5265                    font_definitions_amount
5266                        .families
5267                        .entry(FontFamily::Monospace)
5268                        .or_default()
5269                        .insert(0, font_info[0].to_owned());
5270                    loaded_fonts.push(font_info);
5271                };
5272            }
5273        }
5274        self.loading_fonts = loaded_fonts
5275            .iter()
5276            .map(|x| [x[0].to_string(), x[1].to_string()])
5277            .collect();
5278        ctx.set_fonts(font_definitions_amount);
5279    }
5280
5281    /// Registers all fonts with the egui context.
5282    ///
5283    /// 向egui上下文中注册所有字体。
5284    ///
5285    /// This method loads and registers all fonts with the egui rendering system for
5286    /// text display.
5287    ///
5288    /// 此方法加载并注册所有字体到egui渲染系统中,用于文本显示。
5289    ///
5290    /// # Arguments
5291    ///
5292    /// * `ctx` - The egui context for font registration
5293    /// * `font_info` - Font information, including font names and paths
5294    ///
5295    /// # Returns
5296    ///
5297    /// If the loading is successfully completed, return `Ok(())`; otherwise,
5298    /// return `Err(RustConstructorError)`.
5299    ///
5300    /// # 参数
5301    ///
5302    /// * `ctx` - 用于字体注册的egui上下文
5303    /// * `font_info` - 字体信息,包含字体名称和路径
5304    ///
5305    /// # 返回值
5306    ///
5307    /// 如果成功完成加载返回`Ok(())`,否则返回`Err(RustConstructorError)`。
5308    pub fn register_all_fonts(
5309        &mut self,
5310        ctx: &Context,
5311        font_info: Vec<[&str; 2]>,
5312    ) -> Result<(), RustConstructorError> {
5313        let mut font_definitions_amount = FontDefinitions::default();
5314        let mut loaded_fonts = Vec::new();
5315        for font_info in font_info {
5316            let mut font = FontDefinitions::default();
5317            if let Ok(font_read_data) = read(font_info[1]) {
5318                let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
5319                font.font_data.insert(
5320                    font_info[0].to_owned(),
5321                    Arc::new(FontData::from_owned(
5322                        Arc::try_unwrap(font_data).ok().unwrap(),
5323                    )),
5324                );
5325                // 将字体添加到字体列表中
5326                font.families
5327                    .entry(FontFamily::Proportional)
5328                    .or_default()
5329                    .insert(0, font_info[0].to_owned());
5330
5331                font.families
5332                    .entry(FontFamily::Monospace)
5333                    .or_default()
5334                    .insert(0, font_info[0].to_owned());
5335                if let Some(font_data) = font.font_data.get(font_info[0]) {
5336                    font_definitions_amount
5337                        .font_data
5338                        .insert(font_info[0].to_string(), Arc::clone(font_data));
5339                    font_definitions_amount
5340                        .families
5341                        .entry(FontFamily::Name(font_info[0].into()))
5342                        .or_default()
5343                        .push(font_info[0].to_string());
5344                    // 将字体添加到字体列表中
5345                    font_definitions_amount
5346                        .families
5347                        .entry(FontFamily::Proportional)
5348                        .or_default()
5349                        .insert(0, font_info[0].to_owned());
5350
5351                    font_definitions_amount
5352                        .families
5353                        .entry(FontFamily::Monospace)
5354                        .or_default()
5355                        .insert(0, font_info[0].to_owned());
5356                    loaded_fonts.push(font_info);
5357                };
5358            } else {
5359                return Err(RustConstructorError {
5360                    error_id: "FontLoadFailed".to_string(),
5361                    description: format!("Failed to load a font from the path '{}'.", font_info[1]),
5362                });
5363            }
5364        }
5365        self.loading_fonts = loaded_fonts
5366            .iter()
5367            .map(|x| [x[0].to_string(), x[1].to_string()])
5368            .collect();
5369        ctx.set_fonts(font_definitions_amount);
5370        Ok(())
5371    }
5372
5373    /// Checks if a page has completed its initial loading phase.
5374    ///
5375    /// 检查页面是否已完成首次加载。
5376    ///
5377    /// # Arguments
5378    ///
5379    /// * `name` - The name of the page to check
5380    ///
5381    /// # Returns
5382    ///
5383    /// Returns `Ok(true)` if the page has completed loading, or `Ok(false)` if the page has not completed loading.
5384    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5385    ///
5386    /// # 参数
5387    ///
5388    /// * `name` - 要检查的页面名称
5389    ///
5390    /// # 返回值
5391    ///
5392    /// 如果页面已完成加载则返回 `Ok(true)`,如果未加载则返回 `Ok(false)`。
5393    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5394    pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5395        let page_data = self
5396            .get_resource::<PageData>(&RustConstructorId {
5397                name: name.to_string(),
5398                discern_type: "PageData".to_string(),
5399            })?
5400            .clone();
5401        if !page_data.change_page_updated {
5402            self.new_page_update(name)?;
5403        };
5404        Ok(page_data.change_page_updated)
5405    }
5406
5407    /// Checks if a page has completed its enter transition.
5408    ///
5409    /// 检查页面是否已完成进入过渡。
5410    ///
5411    /// # Arguments
5412    ///
5413    /// * `name` - The name of the page to check
5414    ///
5415    /// # Returns
5416    ///
5417    /// Returns `Ok(true)` if the page has completed entering, or `Ok(false)` if the page has not completed entering.
5418    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5419    ///
5420    /// # 参数
5421    ///
5422    /// * `name` - 要检查的页面名称
5423    ///
5424    /// # 返回值
5425    ///
5426    /// 如果页面已完成进入则返回 `Ok(true)`,如果未过渡则返回 `Ok(false)`。
5427    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5428    pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5429        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5430            name: name.to_string(),
5431            discern_type: "PageData".to_string(),
5432        })?;
5433        page_data.enter_page_updated = true;
5434        Ok(page_data.enter_page_updated)
5435    }
5436
5437    /// Updates when entering a new page.
5438    ///
5439    /// 进入新页面时的更新。
5440    ///
5441    /// This method is used to ensure the accuracy of the content based on the page, and the Rust Constructor will automatically call this method.
5442    ///
5443    /// 此方法用于确保基于页面的内容的准确性,Rust Constructor会自动调用此方法。
5444    ///
5445    /// # Arguments
5446    ///
5447    /// * `name` - The name of the page to be updated
5448    ///
5449    /// # Returns
5450    ///
5451    /// If the update is successful, return `Ok(())`; if the resource is not found, return `Err(RustConstructorError)`.
5452    ///
5453    /// # 参数
5454    ///
5455    /// * `name` - 要更新的页面名称
5456    ///
5457    /// # 返回值
5458    ///
5459    /// 如果更新成功则返回`Ok(())`,找不到资源则返回`Err(RustConstructorError)`。
5460    pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
5461        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5462            name: name.to_string(),
5463            discern_type: "PageData".to_string(),
5464        })?;
5465        page_data.change_page_updated = true;
5466        self.timer.start_time = self.timer.total_time;
5467        self.update_timer();
5468        Ok(())
5469    }
5470
5471    /// Updates frame timing statistics for performance monitoring.
5472    ///
5473    /// 更新帧数统计信息用于性能监控。
5474    ///
5475    /// This method maintains a rolling window of frame times and calculates
5476    /// performance metrics like frame rate.
5477    ///
5478    /// 此方法维护帧时间的滚动窗口并计算帧率等性能指标。
5479    pub fn update_frame_stats(&mut self) {
5480        let current_time = self.timer.total_time;
5481        if let Some(last) = self.last_frame_time {
5482            let delta = current_time - last;
5483            self.frame_times.push(delta);
5484            if self.frame_times.len() > 120 {
5485                let remove_count = self.frame_times.len() - 120;
5486                self.frame_times.drain(0..remove_count);
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            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
5512        }
5513    }
5514
5515    /// Resets the split time for a specific resource.
5516    ///
5517    /// 重置特定资源的分段计时器。
5518    ///
5519    /// # Arguments
5520    ///
5521    /// * `name` - The name of the split time resource to reset
5522    ///
5523    /// # Returns
5524    ///
5525    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5526    ///
5527    /// # 参数
5528    ///
5529    /// * `name` - 要重置的分段时间资源名称
5530    ///
5531    /// # 返回值
5532    ///
5533    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5534    pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
5535        let new_time = [self.timer.now_time, self.timer.total_time];
5536        let split_time = self.get_resource_mut::<SplitTime>(&RustConstructorId {
5537            name: name.to_string(),
5538            discern_type: "SplitTime".to_string(),
5539        })?;
5540        split_time.time = new_time;
5541        Ok(())
5542    }
5543
5544    /// Retrieves the timing information from a split time resource.
5545    ///
5546    /// 获取分段计时器资源的时间信息。
5547    ///
5548    /// # Arguments
5549    ///
5550    /// * `name` - The name of the split time resource
5551    ///
5552    /// # Returns
5553    ///
5554    /// Returns `Ok([page_runtime, total_runtime])` if found, or `Err(RustConstructorError)` if not found.
5555    ///
5556    /// # 参数
5557    ///
5558    /// * `name` - 分段计时器资源的名称
5559    ///
5560    /// # 返回值
5561    ///
5562    /// 如果找到则返回 `Ok([页面运行时间, 总运行时间])`,否则返回 `Err(RustConstructorError)`。
5563    pub fn get_split_time(&self, name: &str) -> Result<[f32; 2], RustConstructorError> {
5564        let split_time = self.get_resource::<SplitTime>(&RustConstructorId {
5565            name: name.to_string(),
5566            discern_type: "SplitTime".to_string(),
5567        })?;
5568        Ok(split_time.time)
5569    }
5570
5571    /// Updates the application timer with current timing information.
5572    ///
5573    /// 更新应用程序计时器的当前时间信息。
5574    ///
5575    /// This method updates both the total runtime and current page runtime.
5576    ///
5577    /// 此方法更新总运行时间和当前页面运行时间。
5578    pub fn update_timer(&mut self) {
5579        let elapsed = self.timer.timer.elapsed();
5580        let seconds = elapsed.as_secs();
5581        let milliseconds = elapsed.subsec_millis();
5582        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
5583        self.timer.now_time = self.timer.total_time - self.timer.start_time
5584    }
5585
5586    /// Modifies the value of a variable resource.
5587    ///
5588    /// 修改变量资源的值。
5589    ///
5590    /// # Arguments
5591    ///
5592    /// * `name` - The name of the variable resource
5593    /// * `value` - The new value to set (use `None` to clear)
5594    ///
5595    /// # Returns
5596    ///
5597    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5598    ///
5599    /// # 参数
5600    ///
5601    /// * `name` - 变量资源的名称
5602    /// * `value` - 要设置的新值(使用 `None` 来清除)
5603    ///
5604    /// # 返回值
5605    ///
5606    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5607    pub fn modify_variable<T: Debug + 'static>(
5608        &mut self,
5609        name: &str,
5610        value: Option<T>,
5611    ) -> Result<(), RustConstructorError> {
5612        let variable = self.get_resource_mut::<Variable<T>>(&RustConstructorId {
5613            name: name.to_string(),
5614            discern_type: "Variable".to_string(),
5615        })?;
5616        variable.value = value;
5617        Ok(())
5618    }
5619
5620    /// Take the variable out of the list.
5621    ///
5622    /// 从列表中取出变量。
5623    ///
5624    /// # Arguments
5625    ///
5626    /// * `name` - The name of the variable resource
5627    ///
5628    /// # Returns
5629    ///
5630    /// Returns `Ok(Option<T>)` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5631    ///
5632    /// # 参数
5633    ///
5634    /// * `name` - 变量资源的名称
5635    ///
5636    /// # 返回值
5637    ///
5638    /// 成功时返回 `Ok(Option<T>)`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5639    pub fn get_variable<T: Debug + Clone + 'static>(
5640        &self,
5641        name: &str,
5642    ) -> Result<Option<T>, RustConstructorError> {
5643        if let Ok(variable) = self.get_resource::<Variable<T>>(&RustConstructorId {
5644            name: name.to_string(),
5645            discern_type: "Variable".to_string(),
5646        }) {
5647            Ok(variable.value.clone())
5648        } else if self
5649            .check_resource_exists(&RustConstructorId {
5650                name: name.to_string(),
5651                discern_type: "Variable".to_string(),
5652            })
5653            .is_none()
5654        {
5655            Err(RustConstructorError {
5656                error_id: "ResourceNotFound".to_string(),
5657                description: format!("Resource '{name}(Variable<T>)' not found."),
5658            })
5659        } else {
5660            Err(RustConstructorError {
5661                error_id: "ResourceGenericMismatch".to_string(),
5662                description: format!(
5663                    "The generic type of the resource '{name}(Variable<T>)' is mismatched."
5664                ),
5665            })
5666        }
5667    }
5668
5669    /// Modify the enable status of the switch.
5670    ///
5671    /// 修改开关的启用状态。
5672    ///
5673    /// # Arguments
5674    ///
5675    /// * `name` - The name of the switch resource
5676    /// * `enable` - The new enable status
5677    ///
5678    /// # Returns
5679    ///
5680    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5681    ///
5682    /// # 参数
5683    ///
5684    /// * `name` - 开关资源的名称
5685    /// * `enable` - 新的启用状态
5686    ///
5687    /// # 返回值
5688    ///
5689    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5690    pub fn set_switch_enable(
5691        &mut self,
5692        name: &str,
5693        enable: bool,
5694    ) -> Result<(), RustConstructorError> {
5695        let switch = self.get_resource_mut::<Switch>(&RustConstructorId {
5696            name: name.to_string(),
5697            discern_type: "Switch".to_string(),
5698        })?;
5699        switch.enable = enable;
5700        Ok(())
5701    }
5702
5703    /// Retrieves the current state and interaction data from a switch resource.
5704    ///
5705    /// 获取开关资源的当前状态和交互数据。
5706    ///
5707    /// # Arguments
5708    ///
5709    /// * `name` - The name of the switch resource
5710    ///
5711    /// # Returns
5712    ///
5713    /// Returns `Ok(SwitchData)` containing the switch state and interaction history,
5714    /// or `Err(RustConstructorError)` if the resource cannot be found.
5715    ///
5716    /// # 参数
5717    ///
5718    /// * `name` - 开关资源的名称
5719    ///
5720    /// # 返回值
5721    ///
5722    /// 返回包含开关状态和交互历史的 `Ok(SwitchData)`,
5723    /// 如果资源无法找到则返回 `Err(RustConstructorError)`。
5724    pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
5725        let switch = self.get_resource::<Switch>(&RustConstructorId {
5726            name: name.to_string(),
5727            discern_type: "Switch".to_string(),
5728        })?;
5729        Ok(SwitchData {
5730            switched: switch.switched,
5731            last_frame_clicked: switch.last_frame_clicked,
5732            state: switch.state,
5733        })
5734    }
5735}