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