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                                Color32::from_rgba_unmultiplied(
1153                                    custom_rect.color[0],
1154                                    custom_rect.color[1],
1155                                    custom_rect.color[2],
1156                                    custom_rect.alpha,
1157                                ),
1158                                Stroke {
1159                                    width: custom_rect.border_width,
1160                                    color: Color32::from_rgba_unmultiplied(
1161                                        custom_rect.border_color[0],
1162                                        custom_rect.border_color[1],
1163                                        custom_rect.border_color[2],
1164                                        custom_rect.border_alpha,
1165                                    ),
1166                                },
1167                                match custom_rect.border_kind {
1168                                    BorderKind::Inside => StrokeKind::Inside,
1169                                    BorderKind::Middle => StrokeKind::Middle,
1170                                    BorderKind::Outside => StrokeKind::Outside,
1171                                },
1172                            );
1173                            if custom_rect.overlay_alpha != 0
1174                                || custom_rect.overlay_border_alpha != 0
1175                                    && custom_rect.border_width > 0_f32
1176                            {
1177                                ui.painter().rect(
1178                                    Rect::from_min_max(
1179                                        Pos2::new(custom_rect.position[0], custom_rect.position[1]),
1180                                        Pos2::new(
1181                                            custom_rect.position[0] + custom_rect.size[0],
1182                                            custom_rect.position[1] + custom_rect.size[1],
1183                                        ),
1184                                    ),
1185                                    custom_rect.rounding,
1186                                    Color32::from_rgba_unmultiplied(
1187                                        custom_rect.overlay_color[0],
1188                                        custom_rect.overlay_color[1],
1189                                        custom_rect.overlay_color[2],
1190                                        (custom_rect.overlay_alpha as f32
1191                                            * custom_rect.alpha as f32
1192                                            / 255_f32)
1193                                            as u8,
1194                                    ),
1195                                    Stroke {
1196                                        width: custom_rect.border_width,
1197                                        color: Color32::from_rgba_unmultiplied(
1198                                            custom_rect.overlay_border_color[0],
1199                                            custom_rect.overlay_border_color[1],
1200                                            custom_rect.overlay_border_color[2],
1201                                            (custom_rect.overlay_border_alpha as f32
1202                                                * custom_rect.alpha as f32
1203                                                / 255_f32)
1204                                                as u8,
1205                                        ),
1206                                    },
1207                                    match custom_rect.border_kind {
1208                                        BorderKind::Inside => StrokeKind::Inside,
1209                                        BorderKind::Middle => StrokeKind::Middle,
1210                                        BorderKind::Outside => StrokeKind::Outside,
1211                                    },
1212                                );
1213                            };
1214                            if custom_rect.basic_front_resource_config.clip_rect.is_some() {
1215                                ui.set_clip_rect(Rect::from_min_size(
1216                                    [0_f32, 0_f32].into(),
1217                                    [ctx.available_rect().width(), ctx.available_rect().height()]
1218                                        .into(),
1219                                ));
1220                            };
1221                        };
1222                        self.replace_resource(&render_resource.name, custom_rect)?;
1223                    };
1224                }
1225                _ => {
1226                    unreachable!()
1227                }
1228            }
1229            Ok(())
1230        } else {
1231            Err(RustConstructorError {
1232                error_id: "IndexOutOfRange".to_string(),
1233                description: format!(
1234                    "The maximum index of the target list is {}, but the index is {index}.",
1235                    self.render_list.len() - 1
1236                ),
1237            })
1238        }
1239    }
1240
1241    /// Generate information for Rust Constructor resources.
1242    ///
1243    /// 生成Rust Constructor资源的信息。
1244    ///
1245    /// This method returns a formatted string containing details about all resources.
1246    /// The level of detail depends on the specified method.
1247    ///
1248    /// 此方法返回一个格式化字符串,包含所有资源的详细信息。
1249    /// 详细程度取决于指定的方法。
1250    ///
1251    /// # Arguments
1252    ///
1253    /// * `method` - Determines the level of detail in the output
1254    ///
1255    /// # Returns
1256    ///
1257    /// A formatted string with resource information.
1258    ///
1259    /// # 参数
1260    ///
1261    /// * `method` - 决定输出信息的详细程度
1262    ///
1263    /// # 返回值
1264    ///
1265    /// 包含资源信息的格式化字符串。
1266    pub fn rust_constructor_resource_info(&self, method: ListInfoMethod) -> String {
1267        let mut text = String::from("Rust Constructor Resource Info:\n");
1268        for info in &self.rust_constructor_resource {
1269            if let ListInfoMethod::Detailed(format) = method {
1270                text += &if format {
1271                    format!(
1272                        "\nName: {}\nType: {}\nDetail: {:#?}\n",
1273                        info.id.name, info.id.discern_type, info.content,
1274                    )
1275                } else {
1276                    format!(
1277                        "\nName: {}\nType: {}\nDetail: {:?}\n",
1278                        info.id.name, info.id.discern_type, info.content,
1279                    )
1280                };
1281            } else {
1282                text += &format!("\nName: {}\nType: {}\n", info.id.name, info.id.discern_type);
1283            };
1284        }
1285        text
1286    }
1287
1288    /// Generates information about currently active resources.
1289    ///
1290    /// 生成当前活跃资源的信息。
1291    ///
1292    /// This method returns a formatted string containing details about all resources
1293    /// in the active list. The level of detail depends on the specified method.
1294    ///
1295    /// 此方法返回一个格式化字符串,包含活动列表中所有资源的详细信息。
1296    /// 详细程度取决于指定的方法。
1297    ///
1298    /// # Arguments
1299    ///
1300    /// * `method` - Determines the level of detail in the output
1301    ///
1302    /// # Returns
1303    ///
1304    /// A formatted string with resource information.
1305    ///
1306    /// # 参数
1307    ///
1308    /// * `method` - 决定输出信息的详细程度
1309    ///
1310    /// # 返回值
1311    ///
1312    /// 包含资源信息的格式化字符串。
1313    pub fn active_list_info(&self, method: ListInfoMethod) -> String {
1314        let mut text = String::from("Resource Active Info:\n");
1315        for info in &self.active_list {
1316            if let ListInfoMethod::Detailed(format) = method {
1317                if let Some(index) = self.check_resource_exists(info) {
1318                    text += &if format {
1319                        format!(
1320                            "\nName: {}\nType: {}\nDetail: {:#?}\n",
1321                            info.name, info.discern_type, self.rust_constructor_resource[index],
1322                        )
1323                    } else {
1324                        format!(
1325                            "\nName: {}\nType: {}\nDetail: {:?}\n",
1326                            info.name, info.discern_type, self.rust_constructor_resource[index],
1327                        )
1328                    };
1329                };
1330            } else {
1331                text += &format!("\nName: {}\nType: {}\n", info.name, info.discern_type);
1332            };
1333        }
1334        text
1335    }
1336
1337    /// Generates information about the current rendering layers.
1338    ///
1339    /// 生成当前渲染层级的信息。
1340    ///
1341    /// This method returns a formatted string containing details about the rendering
1342    /// layer stack, including resource positions and rendering behavior.
1343    ///
1344    /// 此方法返回一个格式化字符串,包含渲染层级堆栈的详细信息,
1345    /// 包括资源位置和渲染行为。
1346    ///
1347    /// # Returns
1348    ///
1349    /// A formatted string with rendering layer information.
1350    ///
1351    /// # 返回值
1352    ///
1353    /// 包含渲染层级信息的格式化字符串。
1354    pub fn render_layer_info(&self) -> String {
1355        let mut text = String::from("Render Layer Info:\n");
1356        for (
1357            RustConstructorId { name, discern_type },
1358            [min_position, max_position],
1359            ignore_render_layer,
1360        ) in &self.render_layer
1361        {
1362            text += &format!(
1363                "\nName: {}\nType: {}\nMin Position: {:?}\nMax Position: {:?}\nIgnore Render Layer: {}\n",
1364                name, discern_type, min_position, max_position, ignore_render_layer
1365            );
1366        }
1367        text
1368    }
1369
1370    /// Generates information about the current render queue.
1371    ///
1372    /// 生成当前渲染队列的信息。
1373    ///
1374    /// This method returns a formatted string listing all resources in the
1375    /// render queue with their names and types.
1376    ///
1377    /// 此方法返回一个格式化字符串,列出渲染队列中的所有资源及其名称和类型。
1378    ///
1379    /// # Returns
1380    ///
1381    /// A formatted string with render queue information.
1382    ///
1383    /// # 返回值
1384    ///
1385    /// 包含渲染队列信息的格式化字符串。
1386    pub fn render_list_info(&self) -> String {
1387        let mut text = String::from("Render List Info:\n");
1388        for RustConstructorId { name, discern_type } in &self.render_list {
1389            text += &format!("\nName: {}\nType: {}\n", name, discern_type);
1390        }
1391        text
1392    }
1393
1394    /// Updates the render queue based on active resources.
1395    ///
1396    /// 根据活跃资源更新渲染队列。
1397    ///
1398    /// This method synchronizes the render list with the active list, ensuring that
1399    /// only active basic front resources are included in the rendering queue.
1400    ///
1401    /// 此方法将渲染列表与活跃列表同步,确保只有活跃的基本前端资源包含在渲染队列中。
1402    pub fn update_render_list(&mut self) {
1403        if self.render_list.is_empty() {
1404            for info in &self.active_list {
1405                if self.basic_front_resource_list.contains(&info.discern_type) {
1406                    self.render_list.push(RustConstructorId {
1407                        name: info.name.clone(),
1408                        discern_type: info.discern_type.clone(),
1409                    });
1410                };
1411            }
1412        } else {
1413            let mut count = 0;
1414            for render_resource in &self.render_list.clone() {
1415                if !self.active_list.contains(render_resource) {
1416                    self.render_list.remove(count);
1417                } else {
1418                    count += 1;
1419                };
1420            }
1421            let mut insert_index = 0;
1422            for info in &self.active_list {
1423                if self.basic_front_resource_list.contains(&info.discern_type) {
1424                    if !self.render_list.contains(info) {
1425                        self.render_list.insert(
1426                            insert_index,
1427                            RustConstructorId {
1428                                name: info.name.clone(),
1429                                discern_type: info.discern_type.clone(),
1430                            },
1431                        );
1432                        insert_index += 1;
1433                    } else if self.render_list[insert_index].cmp(info) == Ordering::Equal {
1434                        insert_index += 1;
1435                    };
1436                };
1437            }
1438        };
1439    }
1440
1441    /// Attempts to move a resource to the front of the render queue, ignoring whether it exists.
1442    ///
1443    /// 请求在渲染队列中插队,且无视申请跳过队列的资源是否存在。
1444    ///
1445    /// This is a safe wrapper around `request_jump_render_list` that suppresses errors.
1446    /// Use when you want to attempt reordering without handling potential errors.
1447    ///
1448    /// 这是`request_jump_render_list`的安全包装器,会抑制错误。当您想要尝试重新排序而不处理潜在错误时使用。
1449    ///
1450    /// # Arguments
1451    ///
1452    /// * `requester` - The resource to move in the queue
1453    /// * `request_type` - How to move the resource (to top or up N layers)
1454    ///
1455    /// # 参数
1456    ///
1457    /// * `requester` - 要在队列中移动的资源
1458    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1459    pub fn try_request_jump_render_list(
1460        &mut self,
1461        requester: RequestMethod,
1462        request_type: RequestType,
1463    ) {
1464        #[allow(warnings)]
1465        self.request_jump_render_list(requester, request_type);
1466    }
1467
1468    /// Moves a resource to the front of the render queue with error handling.
1469    ///
1470    /// 将资源移动到渲染队列的前面(含错误处理)。
1471    ///
1472    /// This method allows changing the rendering order of resources by moving a specific
1473    /// resource to the top of the queue or up a specified number of layers.
1474    ///
1475    /// 此方法允许通过将特定资源移动到队列顶部或上移指定层数来更改资源的渲染顺序。
1476    ///
1477    /// # Arguments
1478    ///
1479    /// * `requester` - The resource to move in the queue
1480    /// * `request_type` - How to move the resource (to top or up N layers)
1481    ///
1482    /// # Returns
1483    ///
1484    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource
1485    /// cannot be found.
1486    ///
1487    /// # 参数
1488    ///
1489    /// * `requester` - 要在队列中移动的资源
1490    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1491    ///
1492    /// # 返回值
1493    ///
1494    /// 成功时返回`Ok(())`,如果资源无法找到则返回`Err(RustConstructorError)`。
1495    pub fn request_jump_render_list(
1496        &mut self,
1497        requester: RequestMethod,
1498        request_type: RequestType,
1499    ) -> Result<(), RustConstructorError> {
1500        match requester {
1501            RequestMethod::Id(id) => {
1502                if let Some(index) = self.render_list.iter().position(|x| *x == id) {
1503                    self.jump_render_list_processor(index, request_type)?;
1504                    Ok(())
1505                } else {
1506                    Err(RustConstructorError {
1507                        error_id: "RenderResourceNotFound".to_string(),
1508                        description: format!(
1509                            "Render resource '{}({})' not found.",
1510                            id.name, id.discern_type
1511                        ),
1512                    })
1513                }
1514            }
1515            RequestMethod::Citer(RustConstructorId { name, discern_type }) => {
1516                for (i, render_resource) in self.render_list.iter().enumerate() {
1517                    let tags = self.get_box_resource(render_resource)?.display_tags();
1518                    if let [Some(tag_name), Some(tag_type)] = [
1519                        self.get_tag("citer_name", &tags),
1520                        self.get_tag("citer_type", &tags),
1521                    ] && tag_name.1 == name
1522                        && tag_type.1 == discern_type
1523                    {
1524                        self.jump_render_list_processor(i, request_type)?;
1525                        return Ok(());
1526                    };
1527                }
1528                Err(RustConstructorError {
1529                    error_id: "RenderResourceNotFound".to_string(),
1530                    description: format!("Render resource '{name}({discern_type})' not found.",),
1531                })
1532            }
1533        }
1534    }
1535
1536    /// Handle the operation of skipping the rendering queue.
1537    ///
1538    /// 处理跳过渲染队列操作。
1539    ///
1540    /// # Arguments
1541    ///
1542    /// * `requester_index` - The index of the resources to be moved in the queue
1543    /// * `request_type` - How to move the resource (to top or up N layers)
1544    ///
1545    /// # Returns
1546    ///
1547    /// When successful, return `Ok(())`. If the index is out of bounds, return `Err(RustConstructorError)`.
1548    ///
1549    /// # 参数
1550    ///
1551    /// * `requester_index` - 要在队列中移动的资源的索引
1552    /// * `request_type` - 如何移动资源(到顶部或上移N层)
1553    ///
1554    /// # 返回值
1555    ///
1556    /// 成功时返回`Ok(())`,如果索引越界则返回`Err(RustConstructorError)`。
1557    pub fn jump_render_list_processor(
1558        &mut self,
1559        requester_index: usize,
1560        request_type: RequestType,
1561    ) -> Result<(), RustConstructorError> {
1562        if requester_index < self.render_list.len() {
1563            let requester = self.render_list.remove(requester_index);
1564            let new_index = match request_type {
1565                RequestType::Top => self.render_list.len(),
1566                RequestType::Up(up) => {
1567                    if requester_index + up <= self.render_list.len() {
1568                        requester_index + up
1569                    } else {
1570                        self.render_list.len()
1571                    }
1572                }
1573            };
1574            self.render_list.insert(new_index, requester);
1575            Ok(())
1576        } else {
1577            Err(RustConstructorError {
1578                error_id: "IndexOutOfRange".to_string(),
1579                description: format!(
1580                    "The maximum index of the target list is {}, but the index is {requester_index}.",
1581                    self.render_list.len() - 1
1582                ),
1583            })
1584        }
1585    }
1586
1587    /// Updates the rendering layer information for all rendering resources.
1588    ///
1589    /// 更新所有渲染资源的渲染层信息。
1590    ///
1591    /// This method recalculates the rendering layer by processing all resources
1592    /// in the render list and updating their position, size, and rendering properties.
1593    ///
1594    /// 此方法通过处理渲染列表中的所有资源并更新它们的位置、尺寸和渲染属性来重新计算渲染层级。
1595    pub fn update_render_layer(&mut self, ctx: &Context) {
1596        self.render_layer.clear();
1597        for info in &self.render_list {
1598            if let Some(index) = self.check_resource_exists(info) {
1599                let basic_front_resource: Box<dyn BasicFrontResource> = match &*info.discern_type {
1600                    "Image" => Box::new(
1601                        self.rust_constructor_resource[index]
1602                            .content
1603                            .as_any()
1604                            .downcast_ref::<Image>()
1605                            .unwrap()
1606                            .clone(),
1607                    ),
1608                    "Text" => Box::new(
1609                        self.rust_constructor_resource[index]
1610                            .content
1611                            .as_any()
1612                            .downcast_ref::<Text>()
1613                            .unwrap()
1614                            .clone(),
1615                    ),
1616                    "CustomRect" => Box::new(
1617                        self.rust_constructor_resource[index]
1618                            .content
1619                            .as_any()
1620                            .downcast_ref::<CustomRect>()
1621                            .unwrap()
1622                            .clone(),
1623                    ),
1624                    _ => {
1625                        unreachable!()
1626                    }
1627                };
1628                if let Some(display_info) = basic_front_resource.display_display_info() {
1629                    self.render_layer.push((
1630                        info.clone(),
1631                        if let Some(clip_rect) = basic_front_resource
1632                            .display_basic_front_resource_config()
1633                            .clip_rect
1634                        {
1635                            let [position, size] = self.position_size_processor(clip_rect, ctx);
1636                            let [resource_rect, clip_rect] = [
1637                                Rect::from_min_max(
1638                                    basic_front_resource.display_position().into(),
1639                                    [
1640                                        basic_front_resource.display_position()[0]
1641                                            + basic_front_resource.display_size()[0],
1642                                        basic_front_resource.display_position()[1]
1643                                            + basic_front_resource.display_size()[1],
1644                                    ]
1645                                    .into(),
1646                                ),
1647                                Rect::from_min_size(position.into(), size.into()),
1648                            ];
1649                            let min = resource_rect.min.max(clip_rect.min);
1650                            let max = resource_rect.max.min(clip_rect.max);
1651
1652                            // 检查是否有交集
1653                            if min.x < max.x && min.y < max.y {
1654                                [min.into(), max.into()]
1655                            } else {
1656                                [[0_f32, 0_f32], [0_f32, 0_f32]]
1657                            }
1658                        } else {
1659                            [
1660                                basic_front_resource.display_position(),
1661                                [
1662                                    basic_front_resource.display_position()[0]
1663                                        + basic_front_resource.display_size()[0],
1664                                    basic_front_resource.display_position()[1]
1665                                        + basic_front_resource.display_size()[1],
1666                                ],
1667                            ]
1668                        },
1669                        display_info.ignore_render_layer,
1670                    ));
1671                };
1672            };
1673        }
1674    }
1675
1676    /// Draw the rendering layer.
1677    ///
1678    /// 绘制渲染层。
1679    ///
1680    /// This method can visually inspect the rendering status of all rendering
1681    /// resources and promptly correct any issues.
1682    ///
1683    /// 此方法可以直观检查所有渲染资源的渲染情况,并及时修正问题。
1684    ///
1685    /// # Arguments
1686    ///
1687    /// * `ui` - The UI context for drawing
1688    /// * `render_config` - The config of the rendering layer area
1689    /// * `ignore_render` - The config of ignore the rendering layer area
1690    ///
1691    /// # 参数
1692    ///
1693    /// * `ui` - 用于绘制的UI上下文
1694    /// * `render_config` - 渲染层区域的配置
1695    /// * `ignore_render_config` - 无视渲染层区域的配置
1696    pub fn display_render_layer(
1697        &self,
1698        ui: &mut Ui,
1699        render_config: &RenderConfig,
1700        ignore_render_config: &RenderConfig,
1701    ) {
1702        for (_, point, ignore_render_layer) in &self.render_layer {
1703            match if *ignore_render_layer {
1704                ignore_render_config
1705            } else {
1706                render_config
1707            } {
1708                RenderConfig::Rect(
1709                    corner_radius,
1710                    fill_color,
1711                    border_color,
1712                    border_width,
1713                    border_kind,
1714                ) => {
1715                    let rect = Rect::from_min_max(point[0].into(), point[1].into());
1716                    ui.painter().rect(
1717                        rect,
1718                        CornerRadius {
1719                            nw: corner_radius[0],
1720                            ne: corner_radius[1],
1721                            sw: corner_radius[2],
1722                            se: corner_radius[3],
1723                        },
1724                        Color32::from_rgba_unmultiplied(
1725                            fill_color[0],
1726                            fill_color[1],
1727                            fill_color[2],
1728                            fill_color[3],
1729                        ),
1730                        Stroke::new(
1731                            *border_width,
1732                            Color32::from_rgba_unmultiplied(
1733                                border_color[0],
1734                                border_color[1],
1735                                border_color[2],
1736                                border_color[3],
1737                            ),
1738                        ),
1739                        match *border_kind {
1740                            BorderKind::Inside => StrokeKind::Inside,
1741                            BorderKind::Middle => StrokeKind::Middle,
1742                            BorderKind::Outside => StrokeKind::Outside,
1743                        },
1744                    );
1745                }
1746                RenderConfig::Line(width, color) => {
1747                    ui.painter().line_segment(
1748                        [point[0].into(), point[1].into()],
1749                        Stroke::new(
1750                            *width,
1751                            Color32::from_rgba_unmultiplied(color[0], color[1], color[2], color[3]),
1752                        ),
1753                    );
1754                }
1755            };
1756        }
1757    }
1758
1759    /// Search for resources in the render list by ID.
1760    ///
1761    /// 通过ID在渲染列表中查找资源。
1762    ///
1763    /// # Arguments
1764    ///
1765    /// * `id` - The ID of the resource to search for
1766    ///
1767    /// # Returns
1768    ///
1769    /// The index of the resource in the render list, or None if not found
1770    ///
1771    /// # 参数
1772    ///
1773    /// * `id` - 要查找的资源的ID
1774    ///
1775    /// # 返回值
1776    ///
1777    /// 渲染列表中的资源索引,如果没有找到则为None
1778    pub fn get_render_layer_resource(&self, id: &RustConstructorId) -> Option<usize> {
1779        self.render_layer.iter().position(|x| &x.0 == id)
1780    }
1781
1782    /// Check whether the resource has obtained the mouse focus.
1783    ///
1784    /// 检查资源是否获取鼠标焦点。
1785    ///
1786    /// Use this method to ensure that mouse operations do not trigger
1787    /// multiple components simultaneously, causing confusion.
1788    ///
1789    /// 使用此方法以保证鼠标操作不会同时触发多个组件产生混乱。
1790    ///
1791    /// # Arguments
1792    ///
1793    /// * `index` - The index value of the rendering resource
1794    /// * `mouse_pos` - The position of the mouse
1795    ///
1796    /// # Returns
1797    ///
1798    /// Return true if the resource is not blocked; otherwise, return false.
1799    ///
1800    /// # 参数
1801    ///
1802    /// * `index` - 渲染资源的索引值
1803    /// * `mouse_pos` - 鼠标的位置
1804    ///
1805    /// # 返回值
1806    ///
1807    /// 如果资源未被阻挡,返回true,否则返回false。
1808    pub fn resource_get_focus(
1809        &self,
1810        index: usize,
1811        mouse_pos: [f32; 2],
1812        need_contains_mouse: bool,
1813    ) -> bool {
1814        for i in index + 1..self.render_layer.len() {
1815            let point = self.render_layer[i].1;
1816            let target_point = self.render_layer[index].1;
1817            if mouse_pos[0] >= point[0][0]
1818                && mouse_pos[1] >= point[0][1]
1819                && mouse_pos[0] <= point[1][0]
1820                && mouse_pos[1] <= point[1][1]
1821                && !self.render_layer[i].2
1822                || need_contains_mouse
1823                    && !(mouse_pos[0] <= target_point[1][0]
1824                        && mouse_pos[0] >= target_point[0][0]
1825                        && mouse_pos[1] <= target_point[1][1]
1826                        && mouse_pos[1] >= target_point[0][1])
1827            {
1828                return false;
1829            };
1830        }
1831        true
1832    }
1833
1834    /// Mark active resources.
1835    ///
1836    /// 标记活跃资源。
1837    ///
1838    /// This method will be automatically called by the Rust Constructor without
1839    /// the need for manual control.
1840    ///
1841    /// 此方法会被Rust Constructor自动调用,无需手动控制。
1842    ///
1843    /// # Arguments
1844    ///
1845    /// * `id` - The unique identifier of the resource
1846    ///
1847    /// # Returns
1848    ///
1849    /// When a success mark is made, return `Ok(())`, and when the resource is not found,
1850    /// return `Err(RustConstructorError)`.
1851    ///
1852    /// # 参数
1853    ///
1854    /// * `id` - 资源的唯一标识符
1855    ///
1856    /// # 返回值
1857    ///
1858    /// 成功标记时返回`Ok(())`,找不到资源时返回`Err(RustConstructorError)`。
1859    pub fn add_active_resource(
1860        &mut self,
1861        id: &RustConstructorId,
1862    ) -> Result<(), RustConstructorError> {
1863        if self.check_resource_exists(id).is_some() {
1864            self.active_list.push(id.clone());
1865            Ok(())
1866        } else {
1867            Err(RustConstructorError {
1868                error_id: "ResourceNotFound".to_string(),
1869                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
1870            })
1871        }
1872    }
1873
1874    /// Adds a new resource to the application with the specified name.
1875    ///
1876    /// 添加一个新资源到应用程序中,并指定名称。
1877    ///
1878    /// This method registers a resource instance with a unique name. If the name is already in use
1879    /// or invalid, an error is returned. For certain resource types like SplitTime, it automatically
1880    /// initializes time values.
1881    ///
1882    /// 此方法使用唯一名称注册资源实例。如果名称已存在或无效,则返回错误。
1883    /// 对于某些资源类型(如 SplitTime),它会自动初始化时间值。
1884    ///
1885    /// # Arguments
1886    ///
1887    /// * `name` - A unique identifier for the resource
1888    /// * `resource` - The resource instance to add
1889    ///
1890    /// # Returns
1891    ///
1892    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be added.
1893    ///
1894    /// # 参数
1895    ///
1896    /// * `name` - 资源的唯一标识符
1897    /// * `resource` - 要添加的资源实例
1898    ///
1899    /// # 返回值
1900    ///
1901    /// 成功时返回 `Ok(())`,如果资源无法添加则返回 `Err(RustConstructorError)`。
1902    pub fn add_resource<T: RustConstructorResource + 'static>(
1903        &mut self,
1904        name: &str,
1905        mut resource: T,
1906    ) -> Result<(), RustConstructorError> {
1907        let discern_type = &*self.type_processor(&resource);
1908        if self
1909            .check_resource_exists(&RustConstructorId {
1910                name: name.to_string(),
1911                discern_type: discern_type.to_string(),
1912            })
1913            .is_some()
1914        {
1915            return Err(RustConstructorError {
1916                error_id: "ResourceNameRepetition".to_string(),
1917                description: format!("Resource '{name}({discern_type})' has already existed."),
1918            });
1919        };
1920        if name.is_empty() {
1921            return Err(RustConstructorError {
1922                error_id: "ResourceUntitled".to_string(),
1923                description: "All resources must have a valid name.".to_string(),
1924            });
1925        };
1926        match discern_type {
1927            "SplitTime" => {
1928                if let Some(split_time) = resource.as_any_mut().downcast_mut::<SplitTime>() {
1929                    split_time.time = [self.timer.now_time, self.timer.total_time];
1930                };
1931            }
1932            "Font" => {
1933                if let Some(font) = resource.as_any_mut().downcast_mut::<Font>() {
1934                    let mut fonts = FontDefinitions::default();
1935                    if let Ok(font_read_data) = read(&font.path) {
1936                        let font_data: Arc<Vec<u8>> = Arc::new(font_read_data);
1937                        fonts.font_data.insert(
1938                            name.to_owned(),
1939                            Arc::new(FontData::from_owned(
1940                                Arc::try_unwrap(font_data).ok().unwrap(),
1941                            )),
1942                        );
1943
1944                        // 将字体添加到字体列表中
1945                        fonts
1946                            .families
1947                            .entry(FontFamily::Proportional)
1948                            .or_default()
1949                            .insert(0, name.to_owned());
1950
1951                        fonts
1952                            .families
1953                            .entry(FontFamily::Monospace)
1954                            .or_default()
1955                            .insert(0, name.to_owned());
1956
1957                        font.font_definitions = WrapDefinitions {
1958                            font_definitions: fonts,
1959                        };
1960                    } else {
1961                        return Err(RustConstructorError {
1962                            error_id: "FontLoadFailed".to_string(),
1963                            description: format!(
1964                                "Failed to load a font from the path '{}'.",
1965                                font.path
1966                            ),
1967                        });
1968                    }
1969                };
1970            }
1971            "Background" => {
1972                if let Some(background) = resource.as_any_mut().downcast_mut::<Background>() {
1973                    match &background.background_type {
1974                        BackgroundType::CustomRect(config) => {
1975                            let mut custom_rect = CustomRect::default().from_config(config);
1976                            if background.use_background_tags {
1977                                custom_rect.modify_tags(&background.tags, false);
1978                            };
1979                            self.add_resource(name, custom_rect)
1980                        }
1981                        BackgroundType::Image(config) => {
1982                            let mut image = Image::default().from_config(config);
1983                            if background.use_background_tags {
1984                                image.modify_tags(&background.tags, false);
1985                            };
1986                            self.add_resource(name, image)
1987                        }
1988                    }?;
1989                };
1990            }
1991            "Switch" => {
1992                if let Some(switch) = resource.as_any_mut().downcast_mut::<Switch>() {
1993                    let count = 1 + switch.enable_animation.iter().filter(|x| **x).count();
1994                    if switch.appearance.len() != count * switch.state_amount as usize {
1995                        return Err(RustConstructorError {
1996                            error_id: "SwitchAppearanceConfigMismatch".to_string(),
1997                            description: format!(
1998                                "Expected {} elements, found {}.",
1999                                count * switch.state_amount as usize,
2000                                switch.appearance.len()
2001                            ),
2002                        });
2003                    };
2004                    self.add_resource(
2005                        &format!("{name}Background"),
2006                        Background::default()
2007                            .background_type(&switch.background_type)
2008                            .auto_update(true)
2009                            .use_background_tags(true)
2010                            .tags(
2011                                if switch.use_switch_tags {
2012                                    &switch.tags
2013                                } else {
2014                                    &[]
2015                                },
2016                                false,
2017                            )
2018                            .tags(
2019                                &[
2020                                    ["citer_name".to_string(), name.to_string()],
2021                                    ["citer_type".to_string(), discern_type.to_string()],
2022                                ],
2023                                false,
2024                            ),
2025                    )?;
2026                    self.add_resource(
2027                        &format!("{name}Text"),
2028                        Text::default()
2029                            .from_config(&switch.text_config)
2030                            .tags(
2031                                if switch.use_switch_tags {
2032                                    &switch.tags
2033                                } else {
2034                                    &[]
2035                                },
2036                                false,
2037                            )
2038                            .tags(
2039                                &[
2040                                    ["citer_name".to_string(), name.to_string()],
2041                                    ["citer_type".to_string(), discern_type.to_string()],
2042                                ],
2043                                false,
2044                            ),
2045                    )?;
2046                    self.add_resource(
2047                        &format!("{name}HintText"),
2048                        Text::default()
2049                            .from_config(&switch.hint_text_config)
2050                            .ignore_render_layer(true)
2051                            .hidden(true)
2052                            .alpha(0)
2053                            .tags(
2054                                &[
2055                                    ["citer_name".to_string(), name.to_string()],
2056                                    ["citer_type".to_string(), discern_type.to_string()],
2057                                    ["disable_x_scrolling".to_string(), "".to_string()],
2058                                    ["disable_y_scrolling".to_string(), "".to_string()],
2059                                ],
2060                                false,
2061                            ),
2062                    )?;
2063                    self.add_resource(
2064                        &format!("{name}StartHoverTime"),
2065                        SplitTime::default().tags(
2066                            &[
2067                                ["citer_name".to_string(), name.to_string()],
2068                                ["citer_type".to_string(), discern_type.to_string()],
2069                            ],
2070                            false,
2071                        ),
2072                    )?;
2073                    self.add_resource(
2074                        &format!("{name}HintFadeAnimation"),
2075                        SplitTime::default().tags(
2076                            &[
2077                                ["citer_name".to_string(), name.to_string()],
2078                                ["citer_type".to_string(), discern_type.to_string()],
2079                            ],
2080                            false,
2081                        ),
2082                    )?;
2083                };
2084            }
2085            "ResourcePanel" => {
2086                if let Some(resource_panel) = resource.as_any_mut().downcast_mut::<ResourcePanel>()
2087                {
2088                    self.add_resource(
2089                        &format!("{name}Background"),
2090                        Background::default()
2091                            .background_type(&resource_panel.background)
2092                            .auto_update(true)
2093                            .use_background_tags(true)
2094                            .tags(
2095                                &[
2096                                    ["citer_name".to_string(), name.to_string()],
2097                                    ["citer_type".to_string(), discern_type.to_string()],
2098                                ],
2099                                false,
2100                            ),
2101                    )?;
2102                    if let ScrollBarDisplayMethod::Always(_, _, _) =
2103                        &resource_panel.scroll_bar_display_method
2104                    {
2105                        self.add_resource(
2106                            &format!("{name}XScroll"),
2107                            Background::default()
2108                                .auto_update(true)
2109                                .use_background_tags(true)
2110                                .tags(
2111                                    &[
2112                                        ["citer_name".to_string(), name.to_string()],
2113                                        ["citer_type".to_string(), discern_type.to_string()],
2114                                    ],
2115                                    false,
2116                                ),
2117                        )?;
2118                        self.add_resource(
2119                            &format!("{name}YScroll"),
2120                            Background::default()
2121                                .auto_update(true)
2122                                .use_background_tags(true)
2123                                .tags(
2124                                    &[
2125                                        ["citer_name".to_string(), name.to_string()],
2126                                        ["citer_type".to_string(), discern_type.to_string()],
2127                                    ],
2128                                    false,
2129                                ),
2130                        )?;
2131                    };
2132                    if let ScrollBarDisplayMethod::OnlyScroll(_, _, _) =
2133                        &resource_panel.scroll_bar_display_method
2134                    {
2135                        self.add_resource(
2136                            &format!("{name}XScroll"),
2137                            Background::default()
2138                                .auto_update(true)
2139                                .use_background_tags(true)
2140                                .tags(
2141                                    &[
2142                                        ["citer_name".to_string(), name.to_string()],
2143                                        ["citer_type".to_string(), discern_type.to_string()],
2144                                    ],
2145                                    false,
2146                                ),
2147                        )?;
2148                        self.add_resource(
2149                            &format!("{name}YScroll"),
2150                            Background::default()
2151                                .auto_update(true)
2152                                .use_background_tags(true)
2153                                .tags(
2154                                    &[
2155                                        ["citer_name".to_string(), name.to_string()],
2156                                        ["citer_type".to_string(), discern_type.to_string()],
2157                                    ],
2158                                    false,
2159                                ),
2160                        )?;
2161                        self.add_resource(
2162                            &format!("{name}ScrollBarXAlpha"),
2163                            SplitTime::default().tags(
2164                                &[
2165                                    ["citer_name".to_string(), name.to_string()],
2166                                    ["citer_type".to_string(), discern_type.to_string()],
2167                                ],
2168                                false,
2169                            ),
2170                        )?;
2171                        self.add_resource(
2172                            &format!("{name}ScrollBarXAlphaStart"),
2173                            SplitTime::default().tags(
2174                                &[
2175                                    ["citer_name".to_string(), name.to_string()],
2176                                    ["citer_type".to_string(), discern_type.to_string()],
2177                                ],
2178                                false,
2179                            ),
2180                        )?;
2181                        self.add_resource(
2182                            &format!("{name}ScrollBarYAlpha"),
2183                            SplitTime::default().tags(
2184                                &[
2185                                    ["citer_name".to_string(), name.to_string()],
2186                                    ["citer_type".to_string(), discern_type.to_string()],
2187                                ],
2188                                false,
2189                            ),
2190                        )?;
2191                        self.add_resource(
2192                            &format!("{name}ScrollBarYAlphaStart"),
2193                            SplitTime::default().tags(
2194                                &[
2195                                    ["citer_name".to_string(), name.to_string()],
2196                                    ["citer_type".to_string(), discern_type.to_string()],
2197                                ],
2198                                false,
2199                            ),
2200                        )?;
2201                    };
2202                };
2203            }
2204            _ => {}
2205        };
2206        self.rust_constructor_resource
2207            .push(RustConstructorResourceBox::new(
2208                name,
2209                discern_type,
2210                Box::new(resource),
2211            ));
2212        Ok(())
2213    }
2214
2215    /// Removes a resource from the application. This method is very dangerous! Ensure the resource is no longer in use before deletion.
2216    ///
2217    /// 移除资源。此方法非常危险!务必确保资源一定不再使用后删除。
2218    ///
2219    /// # Arguments
2220    ///
2221    /// * `id` - The unique identifier of the resource
2222    ///
2223    /// # Returns
2224    ///
2225    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
2226    ///
2227    /// # 参数
2228    ///
2229    /// * `id` - 资源的唯一标识符
2230    ///
2231    /// # 返回值
2232    ///
2233    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
2234    pub fn drop_resource(&mut self, id: &RustConstructorId) -> Result<(), RustConstructorError> {
2235        if let Some(index) = self.check_resource_exists(id) {
2236            self.rust_constructor_resource.remove(index);
2237            if let Some(index) = self.active_list.iter().position(|x| x == id) {
2238                self.active_list.remove(index);
2239            };
2240            if let Some(index) = self
2241                .render_layer
2242                .iter()
2243                .position(|x| x.0.name == id.name && x.0.discern_type == id.discern_type)
2244            {
2245                self.render_layer.remove(index);
2246            };
2247            Ok(())
2248        } else {
2249            Err(RustConstructorError {
2250                error_id: "ResourceNotFound".to_string(),
2251                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2252            })
2253        }
2254    }
2255
2256    /// Replaces an existing resource with a new one in the application.
2257    ///
2258    /// 用应用程序中的新资源替换现有资源。
2259    ///
2260    /// # Arguments
2261    ///
2262    /// * `name` - The name of the resource to replace
2263    /// * `resource` - The new resource instance
2264    ///
2265    /// # Returns
2266    ///
2267    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found or replaced.
2268    ///
2269    /// # 参数
2270    ///
2271    /// * `name` - 要替换的资源名称
2272    /// * `resource` - 新的资源实例
2273    ///
2274    /// # 返回值
2275    ///
2276    /// 成功时返回 `Ok(())`,如果资源无法找到或替换则返回 `Err(RustConstructorError)`。
2277    pub fn replace_resource<T>(
2278        &mut self,
2279        name: &str,
2280        resource: T,
2281    ) -> Result<(), RustConstructorError>
2282    where
2283        T: RustConstructorResource + 'static,
2284    {
2285        let discern_type = &*self.type_processor(&resource);
2286        if let Some(index) = self.check_resource_exists(&RustConstructorId {
2287            name: name.to_string(),
2288            discern_type: discern_type.to_string(),
2289        }) {
2290            self.rust_constructor_resource[index] =
2291                RustConstructorResourceBox::new(name, discern_type, Box::new(resource));
2292            Ok(())
2293        } else {
2294            Err(RustConstructorError {
2295                error_id: "ResourceNotFound".to_string(),
2296                description: format!("Resource '{name}({discern_type})' not found."),
2297            })
2298        }
2299    }
2300
2301    /// Obtain the boxed immutable resources from the list.
2302    ///
2303    /// 从列表中获取封装的不可变资源。
2304    ///
2305    /// If you need to use a resource without knowing its type, please use this method to retrieve the resource.
2306    ///
2307    /// 如果需要在不知道类型的情况下使用资源,请使用此方法取出资源。
2308    ///
2309    /// # Arguments
2310    ///
2311    /// * `id` - The unique identifier of the resource
2312    ///
2313    /// # Returns
2314    ///
2315    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2316    ///
2317    /// # 参数
2318    ///
2319    /// * `id` - 资源的唯一标识符
2320    ///
2321    /// # 返回值
2322    ///
2323    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2324    pub fn get_box_resource(
2325        &self,
2326        id: &RustConstructorId,
2327    ) -> Result<&dyn RustConstructorResource, RustConstructorError> {
2328        if let Some(index) = self.check_resource_exists(id) {
2329            Ok(&*self.rust_constructor_resource[index].content)
2330        } else {
2331            Err(RustConstructorError {
2332                error_id: "ResourceNotFound".to_string(),
2333                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2334            })
2335        }
2336    }
2337
2338    /// Obtain the boxed mutable resources from the list.
2339    ///
2340    /// 从列表中获取封装的可变资源。
2341    ///
2342    /// If you need to use a resource without knowing its type, please use this method to retrieve the resource.
2343    ///
2344    /// 如果需要在不知道类型的情况下使用资源,请使用此方法取出资源。
2345    ///
2346    /// # Arguments
2347    ///
2348    /// * `id` - The unique identifier of the resource
2349    ///
2350    /// # Returns
2351    ///
2352    /// If the resource is found, return the mutable reference of the resource; otherwise, return `Err(RustConstructorError)`.
2353    ///
2354    /// # 参数
2355    ///
2356    /// * `id` - 资源的唯一标识符
2357    ///
2358    /// # 返回值
2359    ///
2360    /// 如果找到资源,返回资源的可变引用,否则返回`Err(RustConstructorError)`。
2361    pub fn get_box_resource_mut(
2362        &mut self,
2363        id: &RustConstructorId,
2364    ) -> Result<&mut dyn RustConstructorResource, RustConstructorError> {
2365        if let Some(index) = self.check_resource_exists(id) {
2366            Ok(&mut *self.rust_constructor_resource[index].content)
2367        } else {
2368            Err(RustConstructorError {
2369                error_id: "ResourceNotFound".to_string(),
2370                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
2371            })
2372        }
2373    }
2374
2375    /// Obtain the immutable resources from the list.
2376    ///
2377    /// 从列表中获取不可变资源。
2378    ///
2379    /// # Arguments
2380    ///
2381    /// * `id` - The unique identifier of the resource
2382    ///
2383    /// # Returns
2384    ///
2385    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2386    ///
2387    /// # 参数
2388    ///
2389    /// * `id` - 资源的唯一标识符
2390    ///
2391    /// # 返回值
2392    ///
2393    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2394    pub fn get_resource<T>(&self, id: &RustConstructorId) -> Result<&T, RustConstructorError>
2395    where
2396        T: RustConstructorResource + 'static,
2397    {
2398        if let Some(resource) = self.get_box_resource(id)?.as_any().downcast_ref::<T>() {
2399            Ok(resource)
2400        } else {
2401            Err(RustConstructorError {
2402                error_id: "ResourceGenericMismatch".to_string(),
2403                description: format!(
2404                    "The generic type of the resource '{}({})' is mismatched.",
2405                    id.name, id.discern_type
2406                ),
2407            })
2408        }
2409    }
2410
2411    /// Obtain the mutable resources from the list.
2412    ///
2413    /// 从列表中获取可变资源。
2414    ///
2415    /// # Arguments
2416    ///
2417    /// * `id` - The unique identifier of the resource
2418    ///
2419    /// # Returns
2420    ///
2421    /// If the resource is found, return the reference of the resource; otherwise, return `Err(RustConstructorError)`.
2422    ///
2423    /// # 参数
2424    ///
2425    /// * `id` - 资源的唯一标识符
2426    ///
2427    /// # 返回值
2428    ///
2429    /// 如果找到资源,返回资源的引用,否则返回`Err(RustConstructorError)`。
2430    pub fn get_resource_mut<T>(
2431        &mut self,
2432        id: &RustConstructorId,
2433    ) -> Result<&mut T, RustConstructorError>
2434    where
2435        T: RustConstructorResource + 'static,
2436    {
2437        if let Some(resource) = self
2438            .get_box_resource_mut(id)?
2439            .as_any_mut()
2440            .downcast_mut::<T>()
2441        {
2442            Ok(resource)
2443        } else {
2444            Err(RustConstructorError {
2445                error_id: "ResourceGenericMismatch".to_string(),
2446                description: format!(
2447                    "The generic type of the resource '{}({})' is mismatched.",
2448                    id.name, id.discern_type
2449                ),
2450            })
2451        }
2452    }
2453
2454    /// Checks if a specific resource exists in the application.
2455    ///
2456    /// 检查应用程序中是否存在特定资源。
2457    ///
2458    /// # Arguments
2459    ///
2460    /// * `id` - The unique identifier of the resource
2461    ///
2462    /// # Returns
2463    ///
2464    /// Returns `Some(index)` if the resource exists, or `None` if not found.
2465    ///
2466    /// # 参数
2467    ///
2468    /// * `id` - 资源的唯一标识符
2469    ///
2470    /// # 返回值
2471    ///
2472    /// 如果资源存在则返回 `Some(索引)`,否则返回 `None`。
2473    pub fn check_resource_exists(&self, id: &RustConstructorId) -> Option<usize> {
2474        self.rust_constructor_resource
2475            .iter()
2476            .position(|x| &x.id == id)
2477    }
2478
2479    /// Quickly adds and uses a resource in one operation.
2480    ///
2481    /// 快速添加并使用资源。
2482    ///
2483    /// This method combines adding a resource to the application and immediately using it.
2484    ///
2485    /// 此方法将资源添加到应用程序并立即使用它。
2486    ///
2487    /// # Arguments
2488    ///
2489    /// * `name` - The name for the resource
2490    /// * `resource` - The resource instance to add and draw
2491    /// * `ui` - The UI context for drawing
2492    /// * `ctx` - The rendering context
2493    ///
2494    /// # Returns
2495    ///
2496    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be added or drawn.
2497    ///
2498    /// # 参数
2499    ///
2500    /// * `name` - 资源的名称
2501    /// * `resource` - 要添加和绘制的资源实例
2502    /// * `ui` - 用于绘制的UI上下文
2503    /// * `ctx` - 渲染上下文
2504    ///
2505    /// # 返回值
2506    ///
2507    /// 成功时返回 `Ok(())`,如果资源无法添加或绘制则返回 `Err(RustConstructorError)`。
2508    pub fn quick_place<T: RustConstructorResource + 'static>(
2509        &mut self,
2510        name: &str,
2511        resource: T,
2512        ui: &mut Ui,
2513        ctx: &Context,
2514    ) -> Result<(), RustConstructorError> {
2515        let discern_type = &*self.type_processor(&resource);
2516        if self
2517            .check_resource_exists(&RustConstructorId {
2518                name: name.to_string(),
2519                discern_type: discern_type.to_string(),
2520            })
2521            .is_none()
2522        {
2523            self.add_resource(name, resource)
2524        } else {
2525            self.use_resource(
2526                &RustConstructorId {
2527                    name: name.to_string(),
2528                    discern_type: discern_type.to_string(),
2529                },
2530                ui,
2531                ctx,
2532            )
2533        }
2534    }
2535
2536    /// Use the existing resources.
2537    ///
2538    /// 使用已存在的资源。
2539    ///
2540    /// This method invokes existing resources and performs operations.
2541    ///
2542    /// 此方法调用存在的资源并进行操作。
2543    ///
2544    /// # Arguments
2545    ///
2546    /// * `id` - The unique identifier of the resource
2547    /// * `ui` - The UI context for drawing
2548    /// * `ctx` - The rendering context
2549    ///
2550    /// # Returns
2551    ///
2552    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be handled.
2553    ///
2554    /// # 参数
2555    ///
2556    /// * `id` - 资源的唯一标识符
2557    /// * `ui` - 用于绘制的UI上下文
2558    /// * `ctx` - 渲染上下文
2559    ///
2560    /// # 返回值
2561    ///
2562    /// 成功时返回 `Ok(())`,如果资源无法处理则返回 `Err(RustConstructorError)`。
2563    pub fn use_resource(
2564        &mut self,
2565        id: &RustConstructorId,
2566        ui: &mut Ui,
2567        ctx: &Context,
2568    ) -> Result<(), RustConstructorError> {
2569        if self.check_resource_exists(id).is_some() {
2570            match &*id.discern_type {
2571                "CustomRect" | "Text" | "Image" => {
2572                    self.add_active_resource(id)?;
2573                }
2574                "PageData" => {
2575                    // 更新帧数
2576                    self.update_frame_stats();
2577                    // 更新渲染队列。
2578                    self.update_render_list();
2579                    // 绘制渲染队列中的资源。
2580                    for i in 0..self.render_list.len() {
2581                        self.draw_resource_by_index(ui, ctx, i)?;
2582                    }
2583                    // 更新渲染列表。
2584                    self.update_render_layer(ctx);
2585                    // 更新资源活跃状态。
2586                    self.active_list.clear();
2587                    // 更新资源启用状态。
2588                    for rcr in &mut self.rust_constructor_resource {
2589                        if let Some(display_info) = &mut rcr.content.display_display_info() {
2590                            rcr.content.modify_display_info(DisplayInfo {
2591                                enable: true,
2592                                hidden: display_info.hidden,
2593                                ignore_render_layer: display_info.ignore_render_layer,
2594                            });
2595                        };
2596                    }
2597                    // 更新计时器
2598                    self.update_timer();
2599                    let page_data = self.get_resource::<PageData>(&RustConstructorId {
2600                        name: self.current_page.clone(),
2601                        discern_type: "PageData".to_string(),
2602                    })?;
2603                    if page_data.forced_update {
2604                        ctx.request_repaint();
2605                    };
2606                }
2607                "Background" => {
2608                    let background = self.get_resource::<Background>(id)?.clone();
2609                    if background.auto_update {
2610                        match &background.background_type {
2611                            BackgroundType::CustomRect(config) => {
2612                                let mut custom_rect = self
2613                                    .get_resource::<CustomRect>(&RustConstructorId {
2614                                        name: id.name.clone(),
2615                                        discern_type: "CustomRect".to_string(),
2616                                    })?
2617                                    .clone()
2618                                    .from_config(config);
2619                                if background.use_background_tags {
2620                                    custom_rect.modify_tags(&background.tags, false);
2621                                };
2622                                self.replace_resource(&id.name, custom_rect)?;
2623                            }
2624                            BackgroundType::Image(config) => {
2625                                let mut image = self
2626                                    .get_resource::<Image>(&RustConstructorId {
2627                                        name: id.name.clone(),
2628                                        discern_type: "Image".to_string(),
2629                                    })?
2630                                    .clone()
2631                                    .from_config(config);
2632                                if background.use_background_tags {
2633                                    image.modify_tags(&background.tags, false);
2634                                };
2635                                self.replace_resource(&id.name, image)?;
2636                            }
2637                        };
2638                    };
2639                    match background.background_type {
2640                        BackgroundType::CustomRect(_) => self.use_resource(
2641                            &RustConstructorId {
2642                                name: id.name.clone(),
2643                                discern_type: "CustomRect".to_string(),
2644                            },
2645                            ui,
2646                            ctx,
2647                        ),
2648                        BackgroundType::Image(_) => self.use_resource(
2649                            &RustConstructorId {
2650                                name: id.name.clone(),
2651                                discern_type: "Image".to_string(),
2652                            },
2653                            ui,
2654                            ctx,
2655                        ),
2656                    }?;
2657                }
2658                "Switch" => {
2659                    let mut switch = self.get_resource::<Switch>(id)?.clone();
2660                    let mut background = self
2661                        .get_resource::<Background>(&RustConstructorId {
2662                            name: format!("{}Background", &id.name),
2663                            discern_type: "Background".to_string(),
2664                        })?
2665                        .clone();
2666                    let background_resource_type = match switch.background_type {
2667                        BackgroundType::CustomRect(_) => "CustomRect",
2668                        BackgroundType::Image(_) => "Image",
2669                    };
2670                    let background_resource: Box<dyn BasicFrontResource> =
2671                        match background_resource_type {
2672                            "CustomRect" => Box::new(
2673                                self.get_resource::<CustomRect>(&RustConstructorId {
2674                                    name: format!("{}Background", &id.name),
2675                                    discern_type: background_resource_type.to_string(),
2676                                })?
2677                                .clone(),
2678                            ),
2679                            "Image" => Box::new(
2680                                self.get_resource::<Image>(&RustConstructorId {
2681                                    name: format!("{}Background", &id.name),
2682                                    discern_type: background_resource_type.to_string(),
2683                                })?
2684                                .clone(),
2685                            ),
2686                            _ => {
2687                                unreachable!()
2688                            }
2689                        };
2690                    let mut text = self
2691                        .get_resource::<Text>(&RustConstructorId {
2692                            name: format!("{}Text", &id.name),
2693                            discern_type: "Text".to_string(),
2694                        })?
2695                        .clone();
2696                    let mut hint_text = self
2697                        .get_resource::<Text>(&RustConstructorId {
2698                            name: format!("{}HintText", &id.name),
2699                            discern_type: "Text".to_string(),
2700                        })?
2701                        .clone();
2702                    switch.switched = false;
2703                    let animation_count =
2704                        1 + switch.enable_animation.iter().filter(|x| **x).count();
2705                    let mut clicked = None;
2706                    let mut hovered = false;
2707                    let mut appearance_count = 0;
2708                    // 处理点击事件
2709                    if let Some(index) = self.get_render_layer_resource(&RustConstructorId {
2710                        name: format!("{}Background", &id.name),
2711                        discern_type: background_resource_type.to_string(),
2712                    }) && switch.enable
2713                        && let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
2714                        && self.resource_get_focus(index, mouse_pos.into(), true)
2715                        && let Some(display_info) = background_resource.display_display_info()
2716                        && !display_info.hidden
2717                    {
2718                        if !switch.last_frame_hovered {
2719                            self.reset_split_time(&format!("{}StartHoverTime", &id.name))?;
2720                        } else if self.timer.total_time
2721                            - self.get_split_time(&format!("{}StartHoverTime", &id.name))?[1]
2722                            >= 2_f32
2723                            || hint_text.alpha != 0
2724                        {
2725                            hint_text.alpha = 255;
2726                            hint_text
2727                                .basic_front_resource_config
2728                                .position_size_config
2729                                .origin_position = [mouse_pos.x, mouse_pos.y];
2730                        };
2731                        hint_text
2732                            .basic_front_resource_config
2733                            .position_size_config
2734                            .display_method
2735                            .0 = if mouse_pos.x + hint_text.actual_size[0]
2736                            <= ctx.available_rect().width()
2737                        {
2738                            HorizontalAlign::Left
2739                        } else {
2740                            HorizontalAlign::Right
2741                        };
2742                        hint_text
2743                            .basic_front_resource_config
2744                            .position_size_config
2745                            .display_method
2746                            .1 = if mouse_pos.y + hint_text.actual_size[1]
2747                            <= ctx.available_rect().height()
2748                        {
2749                            VerticalAlign::Top
2750                        } else {
2751                            VerticalAlign::Bottom
2752                        };
2753                        hovered = true;
2754                        for (count, click_method) in switch.click_method.iter().enumerate() {
2755                            if ui.input(|i| {
2756                                switch.last_frame_clicked.is_none()
2757                                    && i.pointer.button_pressed(click_method.click_method)
2758                                    || switch.last_frame_clicked.is_some()
2759                                        && i.pointer.button_down(click_method.click_method)
2760                            }) {
2761                                clicked = Some(count);
2762                                break;
2763                            };
2764                        }
2765                        if let Some(clicked_index) = switch.last_frame_clicked
2766                            && clicked.is_none()
2767                        {
2768                            switch.switched = true;
2769                            if switch.click_method[clicked_index].action {
2770                                if switch.state
2771                                    < (switch.appearance.len() / animation_count - 1) as u32
2772                                {
2773                                    switch.state += 1;
2774                                } else {
2775                                    switch.state = 0;
2776                                };
2777                            };
2778                        };
2779                        appearance_count = if clicked.is_some() {
2780                            match switch.enable_animation {
2781                                [true, true] => 2,
2782                                [true, false] | [false, true] => 1,
2783                                [false, false] => 0,
2784                            }
2785                        } else if switch.enable_animation[0] {
2786                            1
2787                        } else {
2788                            0
2789                        };
2790                    };
2791
2792                    // 若鼠标未悬挂在开关上,逐渐隐藏提示文本
2793                    if !hovered {
2794                        if switch.last_frame_hovered {
2795                            self.reset_split_time(&format!("{}HintFadeAnimation", &id.name))?;
2796                        };
2797                        if self.timer.total_time
2798                            - self.get_split_time(&format!("{}HintFadeAnimation", &id.name))?[1]
2799                            >= self.tick_interval
2800                        {
2801                            self.reset_split_time(&format!("{}HintFadeAnimation", &id.name))?;
2802                            hint_text.alpha = hint_text.alpha.saturating_sub(10);
2803                        };
2804                    };
2805
2806                    hint_text.display_info.hidden = hint_text.alpha == 0;
2807
2808                    // 更新Background样式。
2809                    background.background_type = switch.appearance
2810                        [(switch.state * animation_count as u32 + appearance_count) as usize]
2811                        .background_config
2812                        .clone();
2813
2814                    background.modify_tags(
2815                        if switch.use_switch_tags {
2816                            &switch.tags
2817                        } else {
2818                            &[]
2819                        },
2820                        false,
2821                    );
2822
2823                    // 刷新提示Text。
2824                    let alpha = hint_text.alpha;
2825                    hint_text = hint_text
2826                        .from_config(
2827                            &switch.appearance[(switch.state * animation_count as u32
2828                                + appearance_count)
2829                                as usize]
2830                                .hint_text_config,
2831                        )
2832                        .ignore_render_layer(true);
2833                    hint_text.background_alpha = alpha;
2834                    hint_text.alpha = alpha;
2835                    hint_text.display_info.hidden = if let Some(display_info) =
2836                        background_resource.display_display_info()
2837                        && display_info.hidden
2838                    {
2839                        true
2840                    } else {
2841                        hint_text.display_info.hidden
2842                    };
2843
2844                    // 更新Text样式。
2845                    text = text
2846                        .tags(
2847                            if switch.use_switch_tags {
2848                                &switch.tags
2849                            } else {
2850                                &[]
2851                            },
2852                            false,
2853                        )
2854                        .from_config(
2855                            &switch.appearance[(switch.state * animation_count as u32
2856                                + appearance_count)
2857                                as usize]
2858                                .text_config,
2859                        );
2860
2861                    switch.last_frame_hovered = hovered;
2862                    switch.last_frame_clicked = clicked;
2863
2864                    self.replace_resource(&format!("{}Text", &id.name), text)?;
2865                    self.replace_resource(&format!("{}HintText", &id.name), hint_text)?;
2866                    self.replace_resource(&id.name, switch)?;
2867                    self.replace_resource(&format!("{}Background", &id.name), background)?;
2868
2869                    self.use_resource(
2870                        &RustConstructorId {
2871                            name: format!("{}Background", &id.name),
2872                            discern_type: "Background".to_string(),
2873                        },
2874                        ui,
2875                        ctx,
2876                    )?;
2877                    self.use_resource(
2878                        &RustConstructorId {
2879                            name: format!("{}Text", &id.name),
2880                            discern_type: "Text".to_string(),
2881                        },
2882                        ui,
2883                        ctx,
2884                    )?;
2885                    if alpha != 0 {
2886                        if let [Some(hint_text_index), Some(switch_background_index)] = [
2887                            self.get_render_layer_resource(&RustConstructorId {
2888                                name: format!("{}HintText", &id.name),
2889                                discern_type: "Text".to_string(),
2890                            }),
2891                            self.get_render_layer_resource(&RustConstructorId {
2892                                name: format!("{}Background", &id.name),
2893                                discern_type: background_resource_type.to_string(),
2894                            }),
2895                        ] && hint_text_index < switch_background_index
2896                        {
2897                            self.try_request_jump_render_list(
2898                                RequestMethod::Id(RustConstructorId {
2899                                    name: format!("{}HintText", &id.name),
2900                                    discern_type: "Text".to_string(),
2901                                }),
2902                                RequestType::Up(switch_background_index - hint_text_index),
2903                            );
2904                        };
2905                        self.use_resource(
2906                            &RustConstructorId {
2907                                name: format!("{}HintText", &id.name),
2908                                discern_type: "Text".to_string(),
2909                            },
2910                            ui,
2911                            ctx,
2912                        )?;
2913                    };
2914                }
2915                "ResourcePanel" => {
2916                    let mut resource_panel = self
2917                        .get_resource::<ResourcePanel>(&RustConstructorId {
2918                            name: id.name.clone(),
2919                            discern_type: "ResourcePanel".to_string(),
2920                        })?
2921                        .clone();
2922                    let background = self
2923                        .get_resource::<Background>(&RustConstructorId {
2924                            name: format!("{}Background", &id.name),
2925                            discern_type: "Background".to_string(),
2926                        })?
2927                        .clone();
2928                    let background_resource: Box<dyn BasicFrontResource> =
2929                        match background.background_type.clone() {
2930                            BackgroundType::CustomRect(_) => Box::new(
2931                                self.get_resource::<CustomRect>(&RustConstructorId {
2932                                    name: format!("{}Background", &id.name),
2933                                    discern_type: "CustomRect".to_string(),
2934                                })?
2935                                .clone(),
2936                            ),
2937                            BackgroundType::Image(_) => Box::new(
2938                                self.get_resource::<Image>(&RustConstructorId {
2939                                    name: format!("{}Background", &id.name),
2940                                    discern_type: "Image".to_string(),
2941                                })?
2942                                .clone(),
2943                            ),
2944                        };
2945                    let (mut position_size_config, mut position, mut size) = (
2946                        background_resource
2947                            .display_basic_front_resource_config()
2948                            .position_size_config,
2949                        background_resource.display_position(),
2950                        background_resource.display_size(),
2951                    );
2952                    let rect = Rect::from_min_size(position.into(), size.into());
2953                    resource_panel.scrolled = [false, false];
2954                    if resource_panel.resizable.contains(&true)
2955                        || resource_panel.movable.contains(&true)
2956                    {
2957                        position_size_config.x_location_grid = [0_f32, 0_f32];
2958                        position_size_config.y_location_grid = [0_f32, 0_f32];
2959                        position_size_config.x_size_grid = [0_f32, 0_f32];
2960                        position_size_config.y_size_grid = [0_f32, 0_f32];
2961                        position_size_config.display_method =
2962                            (HorizontalAlign::Left, VerticalAlign::Top);
2963                    };
2964                    if resource_panel.min_size[0] < 10_f32 {
2965                        resource_panel.min_size[0] = 10_f32;
2966                    };
2967                    if resource_panel.min_size[1] < 10_f32 {
2968                        resource_panel.min_size[1] = 10_f32;
2969                    };
2970                    if position_size_config.origin_size[0] < resource_panel.min_size[0] {
2971                        position_size_config.origin_size[0] = resource_panel.min_size[0];
2972                    };
2973                    if position_size_config.origin_size[1] < resource_panel.min_size[1] {
2974                        position_size_config.origin_size[1] = resource_panel.min_size[1];
2975                    };
2976                    [position, size] = self.position_size_processor(position_size_config, ctx);
2977                    let scroll_delta: [f32; 2] = if resource_panel.use_smooth_scroll_delta {
2978                        ui.input(|i| i.smooth_scroll_delta).into()
2979                    } else {
2980                        ui.input(|i| i.raw_scroll_delta).into()
2981                    };
2982                    let [x_scroll_delta, y_scroll_delta] =
2983                        if scroll_delta[0].abs() >= scroll_delta[1].abs() {
2984                            [
2985                                if resource_panel.reverse_scroll_direction[0] {
2986                                    -scroll_delta[0]
2987                                } else {
2988                                    scroll_delta[0]
2989                                },
2990                                0_f32,
2991                            ]
2992                        } else {
2993                            [
2994                                0_f32,
2995                                if resource_panel.reverse_scroll_direction[1] {
2996                                    -scroll_delta[1]
2997                                } else {
2998                                    scroll_delta[1]
2999                                },
3000                            ]
3001                        };
3002                    if let Some(mouse_pos) = ui.input(|i| i.pointer.hover_pos())
3003                        && !resource_panel.hidden
3004                    {
3005                        if let Some(index) = self.get_render_layer_resource(&RustConstructorId {
3006                            name: format!("{}Background", &id.name),
3007                            discern_type: match background.background_type {
3008                                BackgroundType::CustomRect(_) => "CustomRect",
3009                                BackgroundType::Image(_) => "Image",
3010                            }
3011                            .to_string(),
3012                        }) && self.resource_get_focus(index, mouse_pos.into(), false)
3013                        {
3014                            if ui.input(|i| i.pointer.primary_pressed())
3015                                && Rect::from_min_size(position.into(), size.into())
3016                                    .contains(mouse_pos)
3017                            {
3018                                self.request_jump_render_list(
3019                                    RequestMethod::Id(RustConstructorId {
3020                                        name: format!("{}Background", &id.name),
3021                                        discern_type: match background.background_type {
3022                                            BackgroundType::CustomRect(_) => "CustomRect",
3023                                            BackgroundType::Image(_) => "Image",
3024                                        }
3025                                        .to_string(),
3026                                    }),
3027                                    RequestType::Top,
3028                                )
3029                                .unwrap();
3030                                let mut update_list = Vec::new();
3031                                for rcr in &self.rust_constructor_resource {
3032                                    if self
3033                                        .basic_front_resource_list
3034                                        .contains(&rcr.id.discern_type)
3035                                        && let Some(panel_name) =
3036                                            self.get_tag("panel_name", &rcr.content.display_tags())
3037                                        && panel_name.1 == id.name
3038                                    {
3039                                        update_list.push(rcr.id.clone());
3040                                    };
3041                                }
3042                                for id in update_list {
3043                                    self.try_request_jump_render_list(
3044                                        RequestMethod::Id(id),
3045                                        RequestType::Top,
3046                                    );
3047                                }
3048                                if let ScrollBarDisplayMethod::Always(ref background_type, _, _) =
3049                                    resource_panel.scroll_bar_display_method
3050                                {
3051                                    self.try_request_jump_render_list(
3052                                        RequestMethod::Id(RustConstructorId {
3053                                            name: format!("{}XScroll", &id.name),
3054                                            discern_type: match background_type {
3055                                                BackgroundType::CustomRect(_) => "CustomRect",
3056                                                BackgroundType::Image(_) => "Image",
3057                                            }
3058                                            .to_string(),
3059                                        }),
3060                                        RequestType::Top,
3061                                    );
3062                                    self.try_request_jump_render_list(
3063                                        RequestMethod::Id(RustConstructorId {
3064                                            name: format!("{}YScroll", &id.name),
3065                                            discern_type: match background_type {
3066                                                BackgroundType::CustomRect(_) => "CustomRect",
3067                                                BackgroundType::Image(_) => "Image",
3068                                            }
3069                                            .to_string(),
3070                                        }),
3071                                        RequestType::Top,
3072                                    );
3073                                };
3074                                if let ScrollBarDisplayMethod::OnlyScroll(
3075                                    ref background_type,
3076                                    _,
3077                                    _,
3078                                ) = resource_panel.scroll_bar_display_method
3079                                {
3080                                    self.try_request_jump_render_list(
3081                                        RequestMethod::Id(RustConstructorId {
3082                                            name: format!("{}XScroll", &id.name),
3083                                            discern_type: match background_type {
3084                                                BackgroundType::CustomRect(_) => "CustomRect",
3085                                                BackgroundType::Image(_) => "Image",
3086                                            }
3087                                            .to_string(),
3088                                        }),
3089                                        RequestType::Top,
3090                                    );
3091                                    self.try_request_jump_render_list(
3092                                        RequestMethod::Id(RustConstructorId {
3093                                            name: format!("{}YScroll", &id.name),
3094                                            discern_type: match background_type {
3095                                                BackgroundType::CustomRect(_) => "CustomRect",
3096                                                BackgroundType::Image(_) => "Image",
3097                                            }
3098                                            .to_string(),
3099                                        }),
3100                                        RequestType::Top,
3101                                    );
3102                                };
3103                            };
3104                            let top_rect = Rect::from_min_size(
3105                                [position[0], position[1]].into(),
3106                                [size[0], 3_f32].into(),
3107                            );
3108                            let bottom_rect = Rect::from_min_size(
3109                                [position[0], position[1] + size[1] - 3_f32].into(),
3110                                [size[0], 3_f32].into(),
3111                            );
3112                            let left_rect = Rect::from_min_size(
3113                                [position[0], position[1]].into(),
3114                                [3_f32, size[1]].into(),
3115                            );
3116                            let right_rect = Rect::from_min_size(
3117                                [position[0] + size[0] - 3_f32, position[1]].into(),
3118                                [3_f32, size[1]].into(),
3119                            );
3120                            match [
3121                                top_rect.contains(mouse_pos),
3122                                bottom_rect.contains(mouse_pos),
3123                                left_rect.contains(mouse_pos),
3124                                right_rect.contains(mouse_pos),
3125                            ] {
3126                                [true, false, false, false] => {
3127                                    if resource_panel.resizable[0] {
3128                                        if resource_panel.last_frame_mouse_status.is_none()
3129                                            && ui.input(|i| i.pointer.primary_pressed())
3130                                        {
3131                                            resource_panel.last_frame_mouse_status = Some((
3132                                                mouse_pos.into(),
3133                                                ClickAim::TopResize,
3134                                                [
3135                                                    mouse_pos.x - position[0],
3136                                                    mouse_pos.y - position[1],
3137                                                ],
3138                                            ))
3139                                        };
3140                                        if size[1] > resource_panel.min_size[1]
3141                                            && (resource_panel.max_size.is_none()
3142                                                || size[1] < resource_panel.max_size.unwrap()[1])
3143                                        {
3144                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3145                                        } else if resource_panel.max_size.is_some()
3146                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3147                                        {
3148                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3149                                        } else {
3150                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3151                                        };
3152                                    };
3153                                }
3154                                [false, true, false, false] => {
3155                                    if resource_panel.resizable[1] {
3156                                        if resource_panel.last_frame_mouse_status.is_none()
3157                                            && ui.input(|i| i.pointer.primary_pressed())
3158                                        {
3159                                            resource_panel.last_frame_mouse_status = Some((
3160                                                mouse_pos.into(),
3161                                                ClickAim::BottomResize,
3162                                                [
3163                                                    mouse_pos.x - position[0],
3164                                                    mouse_pos.y - position[1],
3165                                                ],
3166                                            ))
3167                                        };
3168                                        if size[1] > resource_panel.min_size[1]
3169                                            && (resource_panel.max_size.is_none()
3170                                                || size[1] < resource_panel.max_size.unwrap()[1])
3171                                        {
3172                                            ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3173                                        } else if resource_panel.max_size.is_some()
3174                                            && size[1] >= resource_panel.max_size.unwrap()[1]
3175                                        {
3176                                            ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3177                                        } else {
3178                                            ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3179                                        };
3180                                    };
3181                                }
3182                                [false, false, true, false] => {
3183                                    if resource_panel.resizable[2] {
3184                                        if resource_panel.last_frame_mouse_status.is_none()
3185                                            && ui.input(|i| i.pointer.primary_pressed())
3186                                        {
3187                                            resource_panel.last_frame_mouse_status = Some((
3188                                                mouse_pos.into(),
3189                                                ClickAim::LeftResize,
3190                                                [
3191                                                    mouse_pos.x - position[0],
3192                                                    mouse_pos.y - position[1],
3193                                                ],
3194                                            ))
3195                                        };
3196                                        if size[0] > resource_panel.min_size[0]
3197                                            && (resource_panel.max_size.is_none()
3198                                                || size[0] < resource_panel.max_size.unwrap()[0])
3199                                        {
3200                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3201                                        } else if resource_panel.max_size.is_some()
3202                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3203                                        {
3204                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3205                                        } else {
3206                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3207                                        };
3208                                    };
3209                                }
3210                                [false, false, false, true] => {
3211                                    if resource_panel.resizable[3] {
3212                                        if resource_panel.last_frame_mouse_status.is_none()
3213                                            && ui.input(|i| i.pointer.primary_pressed())
3214                                        {
3215                                            resource_panel.last_frame_mouse_status = Some((
3216                                                mouse_pos.into(),
3217                                                ClickAim::RightResize,
3218                                                [
3219                                                    mouse_pos.x - position[0],
3220                                                    mouse_pos.y - position[1],
3221                                                ],
3222                                            ))
3223                                        };
3224                                        if size[0] > resource_panel.min_size[0]
3225                                            && (resource_panel.max_size.is_none()
3226                                                || size[0] < resource_panel.max_size.unwrap()[0])
3227                                        {
3228                                            ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3229                                        } else if resource_panel.max_size.is_some()
3230                                            && size[0] >= resource_panel.max_size.unwrap()[0]
3231                                        {
3232                                            ctx.set_cursor_icon(CursorIcon::ResizeWest);
3233                                        } else {
3234                                            ctx.set_cursor_icon(CursorIcon::ResizeEast);
3235                                        };
3236                                    };
3237                                }
3238                                [true, false, true, false] => {
3239                                    match [resource_panel.resizable[0], resource_panel.resizable[2]]
3240                                    {
3241                                        [true, true] => {
3242                                            if resource_panel.last_frame_mouse_status.is_none()
3243                                                && ui.input(|i| i.pointer.primary_pressed())
3244                                            {
3245                                                resource_panel.last_frame_mouse_status = Some((
3246                                                    mouse_pos.into(),
3247                                                    ClickAim::LeftTopResize,
3248                                                    [
3249                                                        mouse_pos.x - position[0],
3250                                                        mouse_pos.y - position[1],
3251                                                    ],
3252                                                ))
3253                                            };
3254                                            if size[0] > resource_panel.min_size[0]
3255                                                && (resource_panel.max_size.is_none()
3256                                                    || size[0]
3257                                                        < resource_panel.max_size.unwrap()[0])
3258                                                || size[1] > resource_panel.min_size[1]
3259                                                    && (resource_panel.max_size.is_none()
3260                                                        || size[1]
3261                                                            < resource_panel.max_size.unwrap()[1])
3262                                            {
3263                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3264                                            } else if resource_panel.max_size.is_some()
3265                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3266                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3267                                            {
3268                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3269                                            } else {
3270                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3271                                            };
3272                                        }
3273                                        [false, true] => {
3274                                            if resource_panel.last_frame_mouse_status.is_none()
3275                                                && ui.input(|i| i.pointer.primary_pressed())
3276                                            {
3277                                                resource_panel.last_frame_mouse_status = Some((
3278                                                    mouse_pos.into(),
3279                                                    ClickAim::LeftResize,
3280                                                    [
3281                                                        mouse_pos.x - position[0],
3282                                                        mouse_pos.y - position[1],
3283                                                    ],
3284                                                ))
3285                                            };
3286                                            if size[0] > resource_panel.min_size[0]
3287                                                && (resource_panel.max_size.is_none()
3288                                                    || size[0]
3289                                                        < resource_panel.max_size.unwrap()[0])
3290                                            {
3291                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3292                                            } else if resource_panel.max_size.is_some()
3293                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3294                                            {
3295                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3296                                            } else {
3297                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3298                                            };
3299                                        }
3300                                        [true, false] => {
3301                                            if resource_panel.last_frame_mouse_status.is_none()
3302                                                && ui.input(|i| i.pointer.primary_pressed())
3303                                            {
3304                                                resource_panel.last_frame_mouse_status = Some((
3305                                                    mouse_pos.into(),
3306                                                    ClickAim::TopResize,
3307                                                    [
3308                                                        mouse_pos.x - position[0],
3309                                                        mouse_pos.y - position[1],
3310                                                    ],
3311                                                ))
3312                                            };
3313                                            if size[1] > resource_panel.min_size[1]
3314                                                && (resource_panel.max_size.is_none()
3315                                                    || size[1]
3316                                                        < resource_panel.max_size.unwrap()[1])
3317                                            {
3318                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3319                                            } else if resource_panel.max_size.is_some()
3320                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3321                                            {
3322                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3323                                            } else {
3324                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3325                                            };
3326                                        }
3327                                        [false, false] => {}
3328                                    }
3329                                }
3330                                [false, true, false, true] => {
3331                                    match [resource_panel.resizable[1], resource_panel.resizable[3]]
3332                                    {
3333                                        [true, true] => {
3334                                            if resource_panel.last_frame_mouse_status.is_none()
3335                                                && ui.input(|i| i.pointer.primary_pressed())
3336                                            {
3337                                                resource_panel.last_frame_mouse_status = Some((
3338                                                    mouse_pos.into(),
3339                                                    ClickAim::RightBottomResize,
3340                                                    [
3341                                                        mouse_pos.x - position[0],
3342                                                        mouse_pos.y - position[1],
3343                                                    ],
3344                                                ))
3345                                            };
3346                                            if size[0] > resource_panel.min_size[0]
3347                                                && (resource_panel.max_size.is_none()
3348                                                    || size[0]
3349                                                        < resource_panel.max_size.unwrap()[0])
3350                                                || size[1] > resource_panel.min_size[1]
3351                                                    && (resource_panel.max_size.is_none()
3352                                                        || size[1]
3353                                                            < resource_panel.max_size.unwrap()[1])
3354                                            {
3355                                                ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3356                                            } else if resource_panel.max_size.is_some()
3357                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3358                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3359                                            {
3360                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3361                                            } else {
3362                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3363                                            };
3364                                        }
3365                                        [false, true] => {
3366                                            if resource_panel.last_frame_mouse_status.is_none()
3367                                                && ui.input(|i| i.pointer.primary_pressed())
3368                                            {
3369                                                resource_panel.last_frame_mouse_status = Some((
3370                                                    mouse_pos.into(),
3371                                                    ClickAim::RightResize,
3372                                                    [
3373                                                        mouse_pos.x - position[0],
3374                                                        mouse_pos.y - position[1],
3375                                                    ],
3376                                                ))
3377                                            };
3378                                            if size[0] > resource_panel.min_size[0]
3379                                                && (resource_panel.max_size.is_none()
3380                                                    || size[0]
3381                                                        < resource_panel.max_size.unwrap()[0])
3382                                            {
3383                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3384                                            } else if resource_panel.max_size.is_some()
3385                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3386                                            {
3387                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3388                                            } else {
3389                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3390                                            };
3391                                        }
3392                                        [true, false] => {
3393                                            if resource_panel.last_frame_mouse_status.is_none()
3394                                                && ui.input(|i| i.pointer.primary_pressed())
3395                                            {
3396                                                resource_panel.last_frame_mouse_status = Some((
3397                                                    mouse_pos.into(),
3398                                                    ClickAim::BottomResize,
3399                                                    [
3400                                                        mouse_pos.x - position[0],
3401                                                        mouse_pos.y - position[1],
3402                                                    ],
3403                                                ))
3404                                            };
3405                                            if size[1] > resource_panel.min_size[1]
3406                                                && (resource_panel.max_size.is_none()
3407                                                    || size[1]
3408                                                        < resource_panel.max_size.unwrap()[1])
3409                                            {
3410                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3411                                            } else if resource_panel.max_size.is_some()
3412                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3413                                            {
3414                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3415                                            } else {
3416                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3417                                            };
3418                                        }
3419                                        [false, false] => {}
3420                                    }
3421                                }
3422                                [true, false, false, true] => {
3423                                    match [resource_panel.resizable[0], resource_panel.resizable[3]]
3424                                    {
3425                                        [true, true] => {
3426                                            if resource_panel.last_frame_mouse_status.is_none()
3427                                                && ui.input(|i| i.pointer.primary_pressed())
3428                                            {
3429                                                resource_panel.last_frame_mouse_status = Some((
3430                                                    mouse_pos.into(),
3431                                                    ClickAim::RightTopResize,
3432                                                    [
3433                                                        mouse_pos.x - position[0],
3434                                                        mouse_pos.y - position[1],
3435                                                    ],
3436                                                ))
3437                                            };
3438                                            if size[0] > resource_panel.min_size[0]
3439                                                && (resource_panel.max_size.is_none()
3440                                                    || size[0]
3441                                                        < resource_panel.max_size.unwrap()[0])
3442                                                || size[1] > resource_panel.min_size[1]
3443                                                    && (resource_panel.max_size.is_none()
3444                                                        || size[1]
3445                                                            < resource_panel.max_size.unwrap()[1])
3446                                            {
3447                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3448                                            } else if resource_panel.max_size.is_some()
3449                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3450                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3451                                            {
3452                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3453                                            } else {
3454                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3455                                            };
3456                                        }
3457                                        [false, true] => {
3458                                            if resource_panel.last_frame_mouse_status.is_none()
3459                                                && ui.input(|i| i.pointer.primary_pressed())
3460                                            {
3461                                                resource_panel.last_frame_mouse_status = Some((
3462                                                    mouse_pos.into(),
3463                                                    ClickAim::RightResize,
3464                                                    [
3465                                                        mouse_pos.x - position[0],
3466                                                        mouse_pos.y - position[1],
3467                                                    ],
3468                                                ))
3469                                            };
3470                                            if size[0] > resource_panel.min_size[0]
3471                                                && (resource_panel.max_size.is_none()
3472                                                    || size[0]
3473                                                        < resource_panel.max_size.unwrap()[0])
3474                                            {
3475                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3476                                            } else if resource_panel.max_size.is_some()
3477                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3478                                            {
3479                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3480                                            } else {
3481                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3482                                            };
3483                                        }
3484                                        [true, false] => {
3485                                            if resource_panel.last_frame_mouse_status.is_none()
3486                                                && ui.input(|i| i.pointer.primary_pressed())
3487                                            {
3488                                                resource_panel.last_frame_mouse_status = Some((
3489                                                    mouse_pos.into(),
3490                                                    ClickAim::TopResize,
3491                                                    [
3492                                                        mouse_pos.x - position[0],
3493                                                        mouse_pos.y - position[1],
3494                                                    ],
3495                                                ))
3496                                            };
3497                                            if size[1] > resource_panel.min_size[1]
3498                                                && (resource_panel.max_size.is_none()
3499                                                    || size[1]
3500                                                        < resource_panel.max_size.unwrap()[1])
3501                                            {
3502                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3503                                            } else if resource_panel.max_size.is_some()
3504                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3505                                            {
3506                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3507                                            } else {
3508                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3509                                            };
3510                                        }
3511                                        [false, false] => {}
3512                                    }
3513                                }
3514                                [false, true, true, false] => {
3515                                    match [resource_panel.resizable[1], resource_panel.resizable[2]]
3516                                    {
3517                                        [true, true] => {
3518                                            if resource_panel.last_frame_mouse_status.is_none()
3519                                                && ui.input(|i| i.pointer.primary_pressed())
3520                                            {
3521                                                resource_panel.last_frame_mouse_status = Some((
3522                                                    mouse_pos.into(),
3523                                                    ClickAim::LeftBottomResize,
3524                                                    [
3525                                                        mouse_pos.x - position[0],
3526                                                        mouse_pos.y - position[1],
3527                                                    ],
3528                                                ))
3529                                            };
3530                                            if size[0] > resource_panel.min_size[0]
3531                                                && (resource_panel.max_size.is_none()
3532                                                    || size[0]
3533                                                        < resource_panel.max_size.unwrap()[0])
3534                                                || size[1] > resource_panel.min_size[1]
3535                                                    && (resource_panel.max_size.is_none()
3536                                                        || size[1]
3537                                                            < resource_panel.max_size.unwrap()[1])
3538                                            {
3539                                                ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3540                                            } else if resource_panel.max_size.is_some()
3541                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3542                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3543                                            {
3544                                                ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
3545                                            } else {
3546                                                ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
3547                                            };
3548                                        }
3549                                        [false, true] => {
3550                                            if resource_panel.last_frame_mouse_status.is_none()
3551                                                && ui.input(|i| i.pointer.primary_pressed())
3552                                            {
3553                                                resource_panel.last_frame_mouse_status = Some((
3554                                                    mouse_pos.into(),
3555                                                    ClickAim::LeftResize,
3556                                                    [
3557                                                        mouse_pos.x - position[0],
3558                                                        mouse_pos.y - position[1],
3559                                                    ],
3560                                                ))
3561                                            };
3562                                            if size[0] > resource_panel.min_size[0]
3563                                                && (resource_panel.max_size.is_none()
3564                                                    || size[0]
3565                                                        < resource_panel.max_size.unwrap()[0])
3566                                            {
3567                                                ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3568                                            } else if resource_panel.max_size.is_some()
3569                                                && size[0] >= resource_panel.max_size.unwrap()[0]
3570                                            {
3571                                                ctx.set_cursor_icon(CursorIcon::ResizeEast);
3572                                            } else {
3573                                                ctx.set_cursor_icon(CursorIcon::ResizeWest);
3574                                            };
3575                                        }
3576                                        [true, false] => {
3577                                            if resource_panel.last_frame_mouse_status.is_none()
3578                                                && ui.input(|i| i.pointer.primary_pressed())
3579                                            {
3580                                                resource_panel.last_frame_mouse_status = Some((
3581                                                    mouse_pos.into(),
3582                                                    ClickAim::BottomResize,
3583                                                    [
3584                                                        mouse_pos.x - position[0],
3585                                                        mouse_pos.y - position[1],
3586                                                    ],
3587                                                ))
3588                                            };
3589                                            if size[1] > resource_panel.min_size[1]
3590                                                && (resource_panel.max_size.is_none()
3591                                                    || size[1]
3592                                                        < resource_panel.max_size.unwrap()[1])
3593                                            {
3594                                                ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3595                                            } else if resource_panel.max_size.is_some()
3596                                                && size[1] >= resource_panel.max_size.unwrap()[1]
3597                                            {
3598                                                ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3599                                            } else {
3600                                                ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3601                                            };
3602                                        }
3603                                        [false, false] => {}
3604                                    }
3605                                }
3606                                _ => {}
3607                            };
3608                            resource_panel.last_frame_mouse_status =
3609                                if resource_panel.last_frame_mouse_status.is_none()
3610                                    && rect.contains(mouse_pos)
3611                                    && ui.input(|i| i.pointer.primary_pressed())
3612                                {
3613                                    Some((
3614                                        [mouse_pos.x, mouse_pos.y],
3615                                        ClickAim::Move,
3616                                        [mouse_pos.x - position[0], mouse_pos.y - position[1]],
3617                                    ))
3618                                } else if resource_panel.last_frame_mouse_status.is_some()
3619                                    && !ui.input(|i| i.pointer.primary_released())
3620                                {
3621                                    Some((
3622                                        [mouse_pos.x, mouse_pos.y],
3623                                        resource_panel.last_frame_mouse_status.unwrap().1,
3624                                        resource_panel.last_frame_mouse_status.unwrap().2,
3625                                    ))
3626                                } else {
3627                                    None
3628                                };
3629                            if resource_panel.scroll_length_method[0].is_some()
3630                                && x_scroll_delta != 0_f32
3631                                && rect.contains(mouse_pos)
3632                            {
3633                                resource_panel.scrolled[0] = true;
3634                                resource_panel.scroll_progress[0] = if resource_panel
3635                                    .scroll_progress[0]
3636                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3637                                    > resource_panel.scroll_length[0]
3638                                {
3639                                    resource_panel.scroll_length[0]
3640                                } else if resource_panel.scroll_progress[0]
3641                                    + -x_scroll_delta * resource_panel.scroll_sensitivity
3642                                    > 0_f32
3643                                {
3644                                    resource_panel.scroll_progress[0]
3645                                        + -x_scroll_delta * resource_panel.scroll_sensitivity
3646                                } else {
3647                                    0_f32
3648                                };
3649                            };
3650                            if resource_panel.scroll_length_method[1].is_some()
3651                                && y_scroll_delta != 0_f32
3652                                && rect.contains(mouse_pos)
3653                            {
3654                                resource_panel.scrolled[1] = true;
3655                                resource_panel.scroll_progress[1] = if resource_panel
3656                                    .scroll_progress[1]
3657                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3658                                    > resource_panel.scroll_length[1]
3659                                {
3660                                    resource_panel.scroll_length[1]
3661                                } else if resource_panel.scroll_progress[1]
3662                                    + -y_scroll_delta * resource_panel.scroll_sensitivity
3663                                    > 0_f32
3664                                {
3665                                    resource_panel.scroll_progress[1]
3666                                        + -y_scroll_delta * resource_panel.scroll_sensitivity
3667                                } else {
3668                                    0_f32
3669                                };
3670                            };
3671                        } else if ui.input(|i| i.pointer.primary_released()) {
3672                            resource_panel.last_frame_mouse_status = None;
3673                        };
3674                    };
3675                    if let Some((mouse_pos, click_aim, offset)) =
3676                        resource_panel.last_frame_mouse_status
3677                    {
3678                        match click_aim {
3679                            ClickAim::LeftTopResize => {
3680                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3681                                    && (resource_panel.max_size.is_none()
3682                                        || position[0] - mouse_pos[0] + size[0]
3683                                            < resource_panel.max_size.unwrap()[0])
3684                                {
3685                                    position_size_config.origin_size[0] +=
3686                                        position[0] - mouse_pos[0];
3687                                    position_size_config.origin_position[0] = mouse_pos[0];
3688                                } else if resource_panel.max_size.is_some()
3689                                    && position[0] - mouse_pos[0] + size[0]
3690                                        >= resource_panel.max_size.unwrap()[0]
3691                                {
3692                                    position_size_config.origin_position[0] -=
3693                                        resource_panel.max_size.unwrap()[0]
3694                                            - position_size_config.origin_size[0];
3695                                    position_size_config.origin_size[0] =
3696                                        resource_panel.max_size.unwrap()[0];
3697                                } else {
3698                                    position_size_config.origin_position[0] += position_size_config
3699                                        .origin_size[0]
3700                                        - resource_panel.min_size[0];
3701                                    position_size_config.origin_size[0] =
3702                                        resource_panel.min_size[0];
3703                                };
3704                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3705                                    && (resource_panel.max_size.is_none()
3706                                        || position[1] - mouse_pos[1] + size[1]
3707                                            < resource_panel.max_size.unwrap()[1])
3708                                {
3709                                    position_size_config.origin_size[1] +=
3710                                        position[1] - mouse_pos[1];
3711                                    position_size_config.origin_position[1] = mouse_pos[1];
3712                                } else if resource_panel.max_size.is_some()
3713                                    && position[1] - mouse_pos[1] + size[1]
3714                                        >= resource_panel.max_size.unwrap()[1]
3715                                {
3716                                    position_size_config.origin_position[1] -=
3717                                        resource_panel.max_size.unwrap()[1]
3718                                            - position_size_config.origin_size[1];
3719                                    position_size_config.origin_size[1] =
3720                                        resource_panel.max_size.unwrap()[1];
3721                                } else {
3722                                    position_size_config.origin_position[1] += position_size_config
3723                                        .origin_size[1]
3724                                        - resource_panel.min_size[1];
3725                                    position_size_config.origin_size[1] =
3726                                        resource_panel.min_size[1];
3727                                };
3728                                if size[0] > resource_panel.min_size[0]
3729                                    && (resource_panel.max_size.is_none()
3730                                        || size[0] < resource_panel.max_size.unwrap()[0])
3731                                    || size[1] > resource_panel.min_size[1]
3732                                        && (resource_panel.max_size.is_none()
3733                                            || size[1] < resource_panel.max_size.unwrap()[1])
3734                                {
3735                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3736                                } else if resource_panel.max_size.is_some()
3737                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3738                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3739                                {
3740                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast);
3741                                } else {
3742                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest)
3743                                };
3744                            }
3745                            ClickAim::RightBottomResize => {
3746                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3747                                    && (resource_panel.max_size.is_none()
3748                                        || mouse_pos[0] - position[0]
3749                                            < resource_panel.max_size.unwrap()[0])
3750                                {
3751                                    position_size_config.origin_size[0] =
3752                                        mouse_pos[0] - position[0];
3753                                } else if resource_panel.max_size.is_some()
3754                                    && mouse_pos[0] - position[0]
3755                                        >= resource_panel.max_size.unwrap()[0]
3756                                {
3757                                    position_size_config.origin_size[0] =
3758                                        resource_panel.max_size.unwrap()[0];
3759                                } else {
3760                                    position_size_config.origin_size[0] =
3761                                        resource_panel.min_size[0];
3762                                };
3763                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3764                                    && (resource_panel.max_size.is_none()
3765                                        || mouse_pos[1] - position[1]
3766                                            < resource_panel.max_size.unwrap()[1])
3767                                {
3768                                    position_size_config.origin_size[1] =
3769                                        mouse_pos[1] - position[1];
3770                                } else if resource_panel.max_size.is_some()
3771                                    && mouse_pos[1] - position[1]
3772                                        >= resource_panel.max_size.unwrap()[1]
3773                                {
3774                                    position_size_config.origin_size[1] =
3775                                        resource_panel.max_size.unwrap()[1];
3776                                } else {
3777                                    position_size_config.origin_size[1] =
3778                                        resource_panel.min_size[1];
3779                                };
3780                                if size[0] > resource_panel.min_size[0]
3781                                    && (resource_panel.max_size.is_none()
3782                                        || size[0] < resource_panel.max_size.unwrap()[0])
3783                                    || size[1] > resource_panel.min_size[1]
3784                                        && (resource_panel.max_size.is_none()
3785                                            || size[1] < resource_panel.max_size.unwrap()[1])
3786                                {
3787                                    ctx.set_cursor_icon(CursorIcon::ResizeNwSe);
3788                                } else if resource_panel.max_size.is_some()
3789                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3790                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3791                                {
3792                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthWest);
3793                                } else {
3794                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthEast)
3795                                };
3796                            }
3797                            ClickAim::RightTopResize => {
3798                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3799                                    && (resource_panel.max_size.is_none()
3800                                        || mouse_pos[0] - position[0]
3801                                            < resource_panel.max_size.unwrap()[0])
3802                                {
3803                                    position_size_config.origin_size[0] =
3804                                        mouse_pos[0] - position[0];
3805                                } else if resource_panel.max_size.is_some()
3806                                    && mouse_pos[0] - position[0]
3807                                        >= resource_panel.max_size.unwrap()[0]
3808                                {
3809                                    position_size_config.origin_size[0] =
3810                                        resource_panel.max_size.unwrap()[0];
3811                                } else {
3812                                    position_size_config.origin_size[0] =
3813                                        resource_panel.min_size[0];
3814                                };
3815                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3816                                    && (resource_panel.max_size.is_none()
3817                                        || position[1] - mouse_pos[1] + size[1]
3818                                            < resource_panel.max_size.unwrap()[1])
3819                                {
3820                                    position_size_config.origin_size[1] +=
3821                                        position[1] - mouse_pos[1];
3822                                    position_size_config.origin_position[1] = mouse_pos[1];
3823                                } else if resource_panel.max_size.is_some()
3824                                    && position[1] - mouse_pos[1] + size[1]
3825                                        >= resource_panel.max_size.unwrap()[1]
3826                                {
3827                                    position_size_config.origin_position[1] -=
3828                                        resource_panel.max_size.unwrap()[1]
3829                                            - position_size_config.origin_size[1];
3830                                    position_size_config.origin_size[1] =
3831                                        resource_panel.max_size.unwrap()[1];
3832                                } else {
3833                                    position_size_config.origin_position[1] += position_size_config
3834                                        .origin_size[1]
3835                                        - resource_panel.min_size[1];
3836                                    position_size_config.origin_size[1] =
3837                                        resource_panel.min_size[1];
3838                                };
3839                                if size[0] > resource_panel.min_size[0]
3840                                    && (resource_panel.max_size.is_none()
3841                                        || size[0] < resource_panel.max_size.unwrap()[0])
3842                                    || size[1] > resource_panel.min_size[1]
3843                                        && (resource_panel.max_size.is_none()
3844                                            || size[1] < resource_panel.max_size.unwrap()[1])
3845                                {
3846                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3847                                } else if resource_panel.max_size.is_some()
3848                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3849                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3850                                {
3851                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest);
3852                                } else {
3853                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast)
3854                                };
3855                            }
3856                            ClickAim::LeftBottomResize => {
3857                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3858                                    && (resource_panel.max_size.is_none()
3859                                        || position[0] - mouse_pos[0] + size[0]
3860                                            < resource_panel.max_size.unwrap()[0])
3861                                {
3862                                    position_size_config.origin_size[0] +=
3863                                        position[0] - mouse_pos[0];
3864                                    position_size_config.origin_position[0] = mouse_pos[0];
3865                                } else if resource_panel.max_size.is_some()
3866                                    && position[0] - mouse_pos[0] + size[0]
3867                                        >= resource_panel.max_size.unwrap()[0]
3868                                {
3869                                    position_size_config.origin_position[0] -=
3870                                        resource_panel.max_size.unwrap()[0]
3871                                            - position_size_config.origin_size[0];
3872                                    position_size_config.origin_size[0] =
3873                                        resource_panel.max_size.unwrap()[0];
3874                                } else {
3875                                    position_size_config.origin_position[0] += position_size_config
3876                                        .origin_size[0]
3877                                        - resource_panel.min_size[0];
3878                                    position_size_config.origin_size[0] =
3879                                        resource_panel.min_size[0];
3880                                };
3881                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3882                                    && (resource_panel.max_size.is_none()
3883                                        || mouse_pos[1] - position[1]
3884                                            < resource_panel.max_size.unwrap()[1])
3885                                {
3886                                    position_size_config.origin_size[1] =
3887                                        mouse_pos[1] - position[1];
3888                                } else if resource_panel.max_size.is_some()
3889                                    && mouse_pos[1] - position[1]
3890                                        >= resource_panel.max_size.unwrap()[1]
3891                                {
3892                                    position_size_config.origin_size[1] =
3893                                        resource_panel.max_size.unwrap()[1];
3894                                } else {
3895                                    position_size_config.origin_size[1] =
3896                                        resource_panel.min_size[1];
3897                                };
3898                                if size[0] > resource_panel.min_size[0]
3899                                    && (resource_panel.max_size.is_none()
3900                                        || size[0] < resource_panel.max_size.unwrap()[0])
3901                                    || size[1] > resource_panel.min_size[1]
3902                                        && (resource_panel.max_size.is_none()
3903                                            || size[1] < resource_panel.max_size.unwrap()[1])
3904                                {
3905                                    ctx.set_cursor_icon(CursorIcon::ResizeNeSw);
3906                                } else if resource_panel.max_size.is_some()
3907                                    && size[0] >= resource_panel.max_size.unwrap()[0]
3908                                    && size[1] >= resource_panel.max_size.unwrap()[1]
3909                                {
3910                                    ctx.set_cursor_icon(CursorIcon::ResizeNorthEast);
3911                                } else {
3912                                    ctx.set_cursor_icon(CursorIcon::ResizeSouthWest)
3913                                };
3914                            }
3915                            ClickAim::TopResize => {
3916                                if position[1] - mouse_pos[1] + size[1] > resource_panel.min_size[1]
3917                                    && (resource_panel.max_size.is_none()
3918                                        || position[1] - mouse_pos[1] + size[1]
3919                                            < resource_panel.max_size.unwrap()[1])
3920                                {
3921                                    position_size_config.origin_size[1] +=
3922                                        position[1] - mouse_pos[1];
3923                                    position_size_config.origin_position[1] = mouse_pos[1];
3924                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3925                                } else if resource_panel.max_size.is_some()
3926                                    && position[1] - mouse_pos[1] + size[1]
3927                                        >= resource_panel.max_size.unwrap()[1]
3928                                {
3929                                    position_size_config.origin_position[1] -=
3930                                        resource_panel.max_size.unwrap()[1]
3931                                            - position_size_config.origin_size[1];
3932                                    position_size_config.origin_size[1] =
3933                                        resource_panel.max_size.unwrap()[1];
3934                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3935                                } else {
3936                                    position_size_config.origin_position[1] += position_size_config
3937                                        .origin_size[1]
3938                                        - resource_panel.min_size[1];
3939                                    position_size_config.origin_size[1] =
3940                                        resource_panel.min_size[1];
3941                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3942                                };
3943                            }
3944                            ClickAim::BottomResize => {
3945                                if mouse_pos[1] - position[1] > resource_panel.min_size[1]
3946                                    && (resource_panel.max_size.is_none()
3947                                        || mouse_pos[1] - position[1]
3948                                            < resource_panel.max_size.unwrap()[1])
3949                                {
3950                                    position_size_config.origin_size[1] =
3951                                        mouse_pos[1] - position[1];
3952                                    ctx.set_cursor_icon(CursorIcon::ResizeVertical);
3953                                } else if resource_panel.max_size.is_some()
3954                                    && mouse_pos[1] - position[1]
3955                                        >= resource_panel.max_size.unwrap()[1]
3956                                {
3957                                    position_size_config.origin_size[1] =
3958                                        resource_panel.max_size.unwrap()[1];
3959                                    ctx.set_cursor_icon(CursorIcon::ResizeNorth);
3960                                } else {
3961                                    position_size_config.origin_size[1] =
3962                                        resource_panel.min_size[1];
3963                                    ctx.set_cursor_icon(CursorIcon::ResizeSouth);
3964                                };
3965                            }
3966                            ClickAim::LeftResize => {
3967                                if position[0] - mouse_pos[0] + size[0] > resource_panel.min_size[0]
3968                                    && (resource_panel.max_size.is_none()
3969                                        || position[0] - mouse_pos[0] + size[0]
3970                                            < resource_panel.max_size.unwrap()[0])
3971                                {
3972                                    position_size_config.origin_size[0] +=
3973                                        position[0] - mouse_pos[0];
3974                                    position_size_config.origin_position[0] = mouse_pos[0];
3975                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
3976                                } else if resource_panel.max_size.is_some()
3977                                    && position[0] - mouse_pos[0] + size[0]
3978                                        >= resource_panel.max_size.unwrap()[0]
3979                                {
3980                                    position_size_config.origin_position[0] -=
3981                                        resource_panel.max_size.unwrap()[0]
3982                                            - position_size_config.origin_size[0];
3983                                    position_size_config.origin_size[0] =
3984                                        resource_panel.max_size.unwrap()[0];
3985                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
3986                                } else {
3987                                    position_size_config.origin_position[0] += position_size_config
3988                                        .origin_size[0]
3989                                        - resource_panel.min_size[0];
3990                                    position_size_config.origin_size[0] =
3991                                        resource_panel.min_size[0];
3992                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
3993                                };
3994                            }
3995                            ClickAim::RightResize => {
3996                                if mouse_pos[0] - position[0] > resource_panel.min_size[0]
3997                                    && (resource_panel.max_size.is_none()
3998                                        || mouse_pos[0] - position[0]
3999                                            < resource_panel.max_size.unwrap()[0])
4000                                {
4001                                    position_size_config.origin_size[0] =
4002                                        mouse_pos[0] - position[0];
4003                                    ctx.set_cursor_icon(CursorIcon::ResizeHorizontal);
4004                                } else if resource_panel.max_size.is_some()
4005                                    && mouse_pos[0] - position[0]
4006                                        >= resource_panel.max_size.unwrap()[0]
4007                                {
4008                                    position_size_config.origin_size[0] =
4009                                        resource_panel.max_size.unwrap()[0];
4010                                    ctx.set_cursor_icon(CursorIcon::ResizeWest);
4011                                } else {
4012                                    position_size_config.origin_size[0] =
4013                                        resource_panel.min_size[0];
4014                                    ctx.set_cursor_icon(CursorIcon::ResizeEast);
4015                                };
4016                            }
4017                            ClickAim::Move => {
4018                                if resource_panel.movable[0] {
4019                                    position_size_config.origin_position[0] =
4020                                        mouse_pos[0] - offset[0];
4021                                };
4022                                if resource_panel.movable[1] {
4023                                    position_size_config.origin_position[1] =
4024                                        mouse_pos[1] - offset[1];
4025                                };
4026                            }
4027                        };
4028                    };
4029                    [position, size] = self.position_size_processor(position_size_config, ctx);
4030                    let background_type = match background.background_type.clone() {
4031                        BackgroundType::CustomRect(config) => BackgroundType::CustomRect(
4032                            config
4033                                .position_size_config(Some(position_size_config))
4034                                .hidden(Some(resource_panel.hidden)),
4035                        ),
4036                        BackgroundType::Image(config) => BackgroundType::Image(
4037                            config
4038                                .position_size_config(Some(position_size_config))
4039                                .hidden(Some(resource_panel.hidden)),
4040                        ),
4041                    };
4042                    self.replace_resource(
4043                        &format!("{}Background", &id.name),
4044                        background.clone().background_type(&background_type).clone(),
4045                    )?;
4046                    self.use_resource(
4047                        &RustConstructorId {
4048                            name: format!("{}Background", &id.name),
4049                            discern_type: "Background".to_string(),
4050                        },
4051                        ui,
4052                        ctx,
4053                    )?;
4054                    let mut resource_point_list: Vec<([f32; 2], [f32; 2], [bool; 2])> = Vec::new();
4055                    let mut use_resource_list = Vec::new();
4056                    let mut replace_resource_list = Vec::new();
4057                    for rcr in &self.rust_constructor_resource {
4058                        if self
4059                            .basic_front_resource_list
4060                            .contains(&rcr.id.discern_type)
4061                            && let Some(panel_name) =
4062                                self.get_tag("panel_name", &rcr.content.display_tags())
4063                            && panel_name.1 == id.name
4064                        {
4065                            if let [Some(citer_name), Some(citer_type)] = [
4066                                self.get_tag("citer_name", &rcr.content.display_tags()),
4067                                self.get_tag("citer_type", &rcr.content.display_tags()),
4068                            ] {
4069                                if !use_resource_list
4070                                    .iter()
4071                                    .any(|x| x == &[citer_name.1.clone(), citer_type.1.clone()])
4072                                {
4073                                    use_resource_list.push([citer_name.1, citer_type.1]);
4074                                };
4075                            } else if !use_resource_list
4076                                .iter()
4077                                .any(|x| x == &[rcr.id.name.clone(), rcr.id.discern_type.clone()])
4078                            {
4079                                use_resource_list
4080                                    .push([rcr.id.name.clone(), rcr.id.discern_type.clone()]);
4081                            };
4082                            let mut basic_front_resource: Box<dyn BasicFrontResource> = match &*rcr
4083                                .id
4084                                .discern_type
4085                            {
4086                                "Image" => Box::new(
4087                                    rcr.content
4088                                        .as_any()
4089                                        .downcast_ref::<Image>()
4090                                        .unwrap()
4091                                        .clone(),
4092                                ),
4093                                "Text" => Box::new(
4094                                    rcr.content.as_any().downcast_ref::<Text>().unwrap().clone(),
4095                                ),
4096                                "CustomRect" => Box::new(
4097                                    rcr.content
4098                                        .as_any()
4099                                        .downcast_ref::<CustomRect>()
4100                                        .unwrap()
4101                                        .clone(),
4102                                ),
4103                                _ => {
4104                                    unreachable!()
4105                                }
4106                            };
4107                            if !resource_panel
4108                                .resource_storage
4109                                .iter()
4110                                .any(|x| x.id == rcr.id)
4111                            {
4112                                resource_panel.resource_storage.push(PanelStorage {
4113                                    id: rcr.id.clone(),
4114                                    ignore_render_layer: if let Some(display_info) =
4115                                        basic_front_resource.display_display_info()
4116                                    {
4117                                        display_info.ignore_render_layer
4118                                    } else {
4119                                        false
4120                                    },
4121                                    hidden: if let Some(display_info) =
4122                                        basic_front_resource.display_display_info()
4123                                    {
4124                                        display_info.hidden
4125                                    } else {
4126                                        false
4127                                    },
4128                                });
4129                            };
4130                            let enable_scrolling = [
4131                                self.get_tag("disable_x_scrolling", &rcr.content.display_tags())
4132                                    .is_none(),
4133                                self.get_tag("disable_y_scrolling", &rcr.content.display_tags())
4134                                    .is_none(),
4135                            ];
4136                            let offset = basic_front_resource.display_position_size_config().offset;
4137                            basic_front_resource.modify_position_size_config(
4138                                basic_front_resource
4139                                    .display_position_size_config()
4140                                    .x_location_grid(0_f32, 0_f32)
4141                                    .y_location_grid(0_f32, 0_f32)
4142                                    .x_size_grid(0_f32, 0_f32)
4143                                    .y_size_grid(0_f32, 0_f32)
4144                                    .offset(
4145                                        if enable_scrolling[0] {
4146                                            -resource_panel.scroll_progress[0]
4147                                        } else {
4148                                            offset[0]
4149                                        },
4150                                        if enable_scrolling[1] {
4151                                            -resource_panel.scroll_progress[1]
4152                                        } else {
4153                                            offset[1]
4154                                        },
4155                                    ),
4156                            );
4157                            let mut layout = resource_panel.overall_layout;
4158                            for custom_layout in &resource_panel.custom_layout {
4159                                match custom_layout {
4160                                    CustomPanelLayout::Id(layout_id, panel_layout) => {
4161                                        if rcr.id.cmp(layout_id) == Ordering::Equal {
4162                                            layout = *panel_layout;
4163                                            break;
4164                                        };
4165                                    }
4166                                    CustomPanelLayout::Type(layout_type, panel_layout) => {
4167                                        if *layout_type == rcr.id.discern_type {
4168                                            layout = *panel_layout;
4169                                        }
4170                                    }
4171                                };
4172                            }
4173                            match layout.panel_margin {
4174                                PanelMargin::Vertical(
4175                                    [top, bottom, left, right],
4176                                    move_to_bottom,
4177                                ) => {
4178                                    let mut modify_y = 0_f32;
4179                                    let [default_x_position, default_y_position] =
4180                                        match layout.panel_location {
4181                                            PanelLocation::Absolute([x, y]) => {
4182                                                [position[0] + x, position[1] + y]
4183                                            }
4184                                            PanelLocation::Relative([x, y]) => [
4185                                                position[0]
4186                                                    + if x[1] != 0_f32 {
4187                                                        size[0] / x[1] * x[0]
4188                                                    } else {
4189                                                        0_f32
4190                                                    },
4191                                                position[1]
4192                                                    + if y[1] != 0_f32 {
4193                                                        size[1] / y[1] * y[0]
4194                                                    } else {
4195                                                        0_f32
4196                                                    },
4197                                            ],
4198                                        };
4199                                    let default_x_position = match basic_front_resource
4200                                        .display_position_size_config()
4201                                        .display_method
4202                                        .0
4203                                    {
4204                                        HorizontalAlign::Left => default_x_position,
4205                                        HorizontalAlign::Center => {
4206                                            default_x_position
4207                                                - basic_front_resource.display_size()[0] / 2.0
4208                                        }
4209                                        HorizontalAlign::Right => {
4210                                            default_x_position
4211                                                - basic_front_resource.display_size()[0]
4212                                        }
4213                                    };
4214                                    let default_y_position = match basic_front_resource
4215                                        .display_position_size_config()
4216                                        .display_method
4217                                        .1
4218                                    {
4219                                        VerticalAlign::Top => default_y_position,
4220                                        VerticalAlign::Center => {
4221                                            default_y_position
4222                                                - basic_front_resource.display_size()[1] / 2.0
4223                                        }
4224                                        VerticalAlign::Bottom => {
4225                                            default_y_position
4226                                                - basic_front_resource.display_size()[1]
4227                                        }
4228                                    };
4229                                    for point in &resource_point_list {
4230                                        if default_x_position - left < point.1[0]
4231                                            && default_y_position - top + modify_y < point.1[1]
4232                                            && default_x_position
4233                                                + basic_front_resource.display_size()[0]
4234                                                + right
4235                                                > point.0[0]
4236                                            && default_y_position
4237                                                + basic_front_resource.display_size()[1]
4238                                                + bottom
4239                                                + modify_y
4240                                                > point.0[1]
4241                                        {
4242                                            if move_to_bottom
4243                                                && point.1[1] - default_y_position + top > modify_y
4244                                            {
4245                                                modify_y = point.1[1] - default_y_position + top;
4246                                            } else if !move_to_bottom
4247                                                && point.0[1]
4248                                                    - default_y_position
4249                                                    - basic_front_resource.display_size()[1]
4250                                                    - bottom
4251                                                    < modify_y
4252                                            {
4253                                                modify_y = point.0[1]
4254                                                    - default_y_position
4255                                                    - basic_front_resource.display_size()[1]
4256                                                    - bottom;
4257                                            };
4258                                        };
4259                                    }
4260                                    let real_x_position = match basic_front_resource
4261                                        .display_position_size_config()
4262                                        .display_method
4263                                        .0
4264                                    {
4265                                        HorizontalAlign::Left => default_x_position,
4266                                        HorizontalAlign::Center => {
4267                                            default_x_position
4268                                                + basic_front_resource.display_size()[0] / 2.0
4269                                        }
4270                                        HorizontalAlign::Right => {
4271                                            default_x_position
4272                                                + basic_front_resource.display_size()[0]
4273                                        }
4274                                    };
4275                                    let real_y_position = match basic_front_resource
4276                                        .display_position_size_config()
4277                                        .display_method
4278                                        .1
4279                                    {
4280                                        VerticalAlign::Top => default_y_position + modify_y,
4281                                        VerticalAlign::Center => {
4282                                            default_y_position
4283                                                + modify_y
4284                                                + basic_front_resource.display_size()[1] / 2.0
4285                                        }
4286                                        VerticalAlign::Bottom => {
4287                                            default_y_position
4288                                                + modify_y
4289                                                + basic_front_resource.display_size()[1]
4290                                        }
4291                                    };
4292                                    basic_front_resource.modify_position_size_config(
4293                                        basic_front_resource
4294                                            .display_position_size_config()
4295                                            .origin_position(
4296                                                real_x_position
4297                                                    + left
4298                                                    + resource_panel.inner_margin[2],
4299                                                real_y_position
4300                                                    + top
4301                                                    + resource_panel.inner_margin[0],
4302                                            ),
4303                                    );
4304                                    replace_resource_list.push((
4305                                        basic_front_resource.display_position_size_config(),
4306                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4307                                    ));
4308                                    resource_point_list.push((
4309                                        [real_x_position - left, real_y_position - top],
4310                                        [
4311                                            real_x_position
4312                                                + basic_front_resource.display_size()[0]
4313                                                + right,
4314                                            real_y_position
4315                                                + basic_front_resource.display_size()[1]
4316                                                + bottom,
4317                                        ],
4318                                        enable_scrolling,
4319                                    ));
4320                                }
4321                                PanelMargin::Horizontal(
4322                                    [top, bottom, left, right],
4323                                    move_to_right,
4324                                ) => {
4325                                    let mut modify_x = 0_f32;
4326                                    let [default_x_position, default_y_position] =
4327                                        match layout.panel_location {
4328                                            PanelLocation::Absolute([x, y]) => {
4329                                                [position[0] + x, position[1] + y]
4330                                            }
4331                                            PanelLocation::Relative([x, y]) => [
4332                                                position[0]
4333                                                    + if x[1] != 0_f32 {
4334                                                        size[0] / x[1] * x[0]
4335                                                    } else {
4336                                                        0_f32
4337                                                    },
4338                                                position[1]
4339                                                    + if y[1] != 0_f32 {
4340                                                        size[1] / y[1] * y[0]
4341                                                    } else {
4342                                                        0_f32
4343                                                    },
4344                                            ],
4345                                        };
4346                                    let default_x_position = match basic_front_resource
4347                                        .display_position_size_config()
4348                                        .display_method
4349                                        .0
4350                                    {
4351                                        HorizontalAlign::Left => default_x_position,
4352                                        HorizontalAlign::Center => {
4353                                            default_x_position
4354                                                - basic_front_resource.display_size()[0] / 2.0
4355                                        }
4356                                        HorizontalAlign::Right => {
4357                                            default_x_position
4358                                                - basic_front_resource.display_size()[0]
4359                                        }
4360                                    };
4361                                    let default_y_position = match basic_front_resource
4362                                        .display_position_size_config()
4363                                        .display_method
4364                                        .1
4365                                    {
4366                                        VerticalAlign::Top => default_y_position,
4367                                        VerticalAlign::Center => {
4368                                            default_y_position
4369                                                - basic_front_resource.display_size()[1] / 2.0
4370                                        }
4371                                        VerticalAlign::Bottom => {
4372                                            default_y_position
4373                                                - basic_front_resource.display_size()[1]
4374                                        }
4375                                    };
4376                                    for point in &resource_point_list {
4377                                        if default_x_position - left + modify_x < point.1[0]
4378                                            && default_y_position - top < point.1[1]
4379                                            && default_x_position
4380                                                + basic_front_resource.display_size()[0]
4381                                                + right
4382                                                + modify_x
4383                                                > point.0[0]
4384                                            && default_y_position
4385                                                + basic_front_resource.display_size()[1]
4386                                                + bottom
4387                                                > point.0[1]
4388                                        {
4389                                            if move_to_right
4390                                                && point.1[0] - default_x_position + left > modify_x
4391                                            {
4392                                                modify_x = point.1[0] - default_x_position + left;
4393                                            } else if !move_to_right
4394                                                && point.0[0]
4395                                                    - default_x_position
4396                                                    - basic_front_resource.display_size()[0]
4397                                                    - right
4398                                                    < modify_x
4399                                            {
4400                                                modify_x = point.0[0]
4401                                                    - default_x_position
4402                                                    - basic_front_resource.display_size()[0]
4403                                                    - right;
4404                                            };
4405                                        };
4406                                    }
4407                                    let real_x_position = match basic_front_resource
4408                                        .display_position_size_config()
4409                                        .display_method
4410                                        .0
4411                                    {
4412                                        HorizontalAlign::Left => default_x_position + modify_x,
4413                                        HorizontalAlign::Center => {
4414                                            default_x_position
4415                                                + modify_x
4416                                                + basic_front_resource.display_size()[0] / 2.0
4417                                        }
4418                                        HorizontalAlign::Right => {
4419                                            default_x_position
4420                                                + modify_x
4421                                                + basic_front_resource.display_size()[0]
4422                                        }
4423                                    };
4424                                    let real_y_position = match basic_front_resource
4425                                        .display_position_size_config()
4426                                        .display_method
4427                                        .1
4428                                    {
4429                                        VerticalAlign::Top => default_y_position,
4430                                        VerticalAlign::Center => {
4431                                            default_y_position
4432                                                + basic_front_resource.display_size()[1] / 2.0
4433                                        }
4434                                        VerticalAlign::Bottom => {
4435                                            default_y_position
4436                                                + basic_front_resource.display_size()[1]
4437                                        }
4438                                    };
4439                                    basic_front_resource.modify_position_size_config(
4440                                        basic_front_resource
4441                                            .display_position_size_config()
4442                                            .origin_position(
4443                                                real_x_position
4444                                                    + left
4445                                                    + resource_panel.inner_margin[2],
4446                                                real_y_position
4447                                                    + top
4448                                                    + resource_panel.inner_margin[0],
4449                                            ),
4450                                    );
4451                                    replace_resource_list.push((
4452                                        basic_front_resource.display_position_size_config(),
4453                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4454                                    ));
4455                                    resource_point_list.push((
4456                                        [real_x_position - left, real_y_position - top],
4457                                        [
4458                                            real_x_position
4459                                                + basic_front_resource.display_size()[0]
4460                                                + right,
4461                                            real_y_position
4462                                                + basic_front_resource.display_size()[1]
4463                                                + bottom,
4464                                        ],
4465                                        enable_scrolling,
4466                                    ));
4467                                }
4468                                PanelMargin::None([top, bottom, left, right], influence_layout) => {
4469                                    let [default_x_position, default_y_position] =
4470                                        match layout.panel_location {
4471                                            PanelLocation::Absolute([x, y]) => {
4472                                                [position[0] + x, position[1] + y]
4473                                            }
4474                                            PanelLocation::Relative([x, y]) => [
4475                                                position[0]
4476                                                    + if x[1] != 0_f32 {
4477                                                        size[0] / x[1] * x[0]
4478                                                    } else {
4479                                                        0_f32
4480                                                    },
4481                                                position[1]
4482                                                    + if y[1] != 0_f32 {
4483                                                        size[1] / y[1] * y[0]
4484                                                    } else {
4485                                                        0_f32
4486                                                    },
4487                                            ],
4488                                        };
4489                                    basic_front_resource.modify_position_size_config(
4490                                        basic_front_resource
4491                                            .display_position_size_config()
4492                                            .origin_position(
4493                                                default_x_position
4494                                                    + left
4495                                                    + resource_panel.inner_margin[2],
4496                                                default_y_position
4497                                                    + top
4498                                                    + resource_panel.inner_margin[0],
4499                                            ),
4500                                    );
4501                                    replace_resource_list.push((
4502                                        basic_front_resource.display_position_size_config(),
4503                                        [rcr.id.name.clone(), rcr.id.discern_type.clone()],
4504                                    ));
4505                                    if influence_layout {
4506                                        resource_point_list.push((
4507                                            [default_x_position - left, default_y_position - top],
4508                                            [
4509                                                default_x_position
4510                                                    + basic_front_resource.display_size()[0]
4511                                                    + right,
4512                                                default_y_position
4513                                                    + basic_front_resource.display_size()[1]
4514                                                    + bottom,
4515                                            ],
4516                                            enable_scrolling,
4517                                        ));
4518                                    };
4519                                }
4520                            };
4521                        };
4522                    }
4523                    for (new_position_size_config, [name, discern_type]) in replace_resource_list {
4524                        let id = RustConstructorId {
4525                            name: name.clone(),
4526                            discern_type: discern_type.clone(),
4527                        };
4528                        let default_storage = if let Some(resource_storage) =
4529                            resource_panel.resource_storage.iter().find(|x| x.id == id)
4530                        {
4531                            [
4532                                true,
4533                                resource_storage.ignore_render_layer,
4534                                resource_storage.hidden,
4535                            ]
4536                        } else {
4537                            [false, true, true]
4538                        };
4539                        match &*discern_type {
4540                            "CustomRect" => {
4541                                let mut custom_rect = self.get_resource::<CustomRect>(&id)?.clone();
4542                                custom_rect.basic_front_resource_config.position_size_config =
4543                                    new_position_size_config;
4544                                custom_rect.display_info.ignore_render_layer = if resource_panel
4545                                    .last_frame_mouse_status
4546                                    .is_some()
4547                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
4548                                {
4549                                    true
4550                                } else if default_storage[0] {
4551                                    default_storage[1]
4552                                } else {
4553                                    custom_rect.display_info.ignore_render_layer
4554                                };
4555                                custom_rect.basic_front_resource_config.clip_rect = Some(
4556                                    position_size_config
4557                                        .origin_size(
4558                                            position_size_config.origin_size[0]
4559                                                - resource_panel.inner_margin[2]
4560                                                - resource_panel.inner_margin[3],
4561                                            position_size_config.origin_size[1]
4562                                                - resource_panel.inner_margin[0]
4563                                                - resource_panel.inner_margin[1],
4564                                        )
4565                                        .origin_position(
4566                                            position_size_config.origin_position[0]
4567                                                + resource_panel.inner_margin[2],
4568                                            position_size_config.origin_position[1]
4569                                                + resource_panel.inner_margin[0],
4570                                        ),
4571                                );
4572                                custom_rect.display_info.hidden = if resource_panel.hidden {
4573                                    true
4574                                } else if default_storage[0] {
4575                                    default_storage[2]
4576                                } else {
4577                                    custom_rect.display_info.hidden
4578                                };
4579                                self.replace_resource(&name, custom_rect)?;
4580                            }
4581                            "Image" => {
4582                                let mut image = self.get_resource::<Image>(&id)?.clone();
4583                                image.basic_front_resource_config.position_size_config =
4584                                    new_position_size_config;
4585                                image.display_info.ignore_render_layer = if resource_panel
4586                                    .last_frame_mouse_status
4587                                    .is_some()
4588                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
4589                                {
4590                                    true
4591                                } else if default_storage[0] {
4592                                    default_storage[1]
4593                                } else {
4594                                    image.display_info.ignore_render_layer
4595                                };
4596                                image.basic_front_resource_config.clip_rect = Some(
4597                                    position_size_config
4598                                        .origin_size(
4599                                            position_size_config.origin_size[0]
4600                                                - resource_panel.inner_margin[2]
4601                                                - resource_panel.inner_margin[3],
4602                                            position_size_config.origin_size[1]
4603                                                - resource_panel.inner_margin[0]
4604                                                - resource_panel.inner_margin[1],
4605                                        )
4606                                        .origin_position(
4607                                            position_size_config.origin_position[0]
4608                                                + resource_panel.inner_margin[2],
4609                                            position_size_config.origin_position[1]
4610                                                + resource_panel.inner_margin[0],
4611                                        ),
4612                                );
4613                                image.display_info.hidden = resource_panel.hidden;
4614                                self.replace_resource(&name, image)?;
4615                            }
4616                            "Text" => {
4617                                let mut text = self.get_resource::<Text>(&id)?.clone();
4618                                text.basic_front_resource_config.position_size_config =
4619                                    new_position_size_config;
4620                                text.display_info.ignore_render_layer = if resource_panel
4621                                    .last_frame_mouse_status
4622                                    .is_some()
4623                                    || [x_scroll_delta, y_scroll_delta].iter().any(|x| *x != 0_f32)
4624                                {
4625                                    true
4626                                } else if default_storage[0] {
4627                                    default_storage[1]
4628                                } else {
4629                                    text.display_info.ignore_render_layer
4630                                };
4631                                text.auto_fit = [false, false];
4632                                text.basic_front_resource_config.clip_rect = Some(
4633                                    position_size_config
4634                                        .origin_size(
4635                                            position_size_config.origin_size[0]
4636                                                - resource_panel.inner_margin[2]
4637                                                - resource_panel.inner_margin[3],
4638                                            position_size_config.origin_size[1]
4639                                                - resource_panel.inner_margin[0]
4640                                                - resource_panel.inner_margin[1],
4641                                        )
4642                                        .origin_position(
4643                                            position_size_config.origin_position[0]
4644                                                + resource_panel.inner_margin[2],
4645                                            position_size_config.origin_position[1]
4646                                                + resource_panel.inner_margin[0],
4647                                        ),
4648                                );
4649                                text.display_info.hidden = resource_panel.hidden;
4650                                self.replace_resource(&name, text)?;
4651                            }
4652                            _ => unreachable!(),
4653                        }
4654                    }
4655                    for info in use_resource_list {
4656                        self.use_resource(
4657                            &RustConstructorId {
4658                                name: info[0].clone(),
4659                                discern_type: info[1].clone(),
4660                            },
4661                            ui,
4662                            ctx,
4663                        )?;
4664                    }
4665                    let mut resource_length = [None, None];
4666                    for point in resource_point_list {
4667                        resource_length = [
4668                            if resource_length[0].is_none()
4669                                || resource_length[0].is_some()
4670                                    && point.1[0] > resource_length[0].unwrap()
4671                                    && point.2[0]
4672                            {
4673                                Some(point.1[0])
4674                            } else {
4675                                resource_length[0]
4676                            },
4677                            if resource_length[1].is_none()
4678                                || resource_length[1].is_some()
4679                                    && point.1[1] > resource_length[1].unwrap()
4680                                    && point.2[1]
4681                            {
4682                                Some(point.1[1])
4683                            } else {
4684                                resource_length[1]
4685                            },
4686                        ]
4687                    }
4688                    if let Some(horizontal_scroll_length_method) =
4689                        resource_panel.scroll_length_method[0]
4690                    {
4691                        let margin = match resource_panel.overall_layout.panel_margin {
4692                            PanelMargin::Horizontal([_, _, left, right], _) => left + right,
4693                            PanelMargin::Vertical([_, _, left, right], _) => left + right,
4694                            PanelMargin::None([_, _, left, right], _) => left + right,
4695                        };
4696                        resource_panel.scroll_length[0] = match horizontal_scroll_length_method {
4697                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4698                            ScrollLengthMethod::AutoFit(expand) => {
4699                                if let Some(max) = resource_length[0] {
4700                                    let width = max - position[0];
4701                                    if width - size[0]
4702                                        + expand
4703                                        + margin
4704                                        + resource_panel.inner_margin[3]
4705                                        + resource_panel.inner_margin[2]
4706                                        > 0_f32
4707                                    {
4708                                        width - size[0]
4709                                            + expand
4710                                            + margin
4711                                            + resource_panel.inner_margin[3]
4712                                            + resource_panel.inner_margin[2]
4713                                    } else {
4714                                        0_f32
4715                                    }
4716                                } else {
4717                                    0_f32
4718                                }
4719                            }
4720                        };
4721                        if resource_panel.scroll_progress[0] > resource_panel.scroll_length[0] {
4722                            resource_panel.scroll_progress[0] = resource_panel.scroll_length[0];
4723                        };
4724                    };
4725                    if let Some(vertical_scroll_length_method) =
4726                        resource_panel.scroll_length_method[1]
4727                    {
4728                        let margin = match resource_panel.overall_layout.panel_margin {
4729                            PanelMargin::Horizontal([top, bottom, _, _], _) => top + bottom,
4730                            PanelMargin::Vertical([top, bottom, _, _], _) => top + bottom,
4731                            PanelMargin::None([top, bottom, _, _], _) => top + bottom,
4732                        };
4733                        resource_panel.scroll_length[1] = match vertical_scroll_length_method {
4734                            ScrollLengthMethod::Fixed(fixed_length) => fixed_length,
4735                            ScrollLengthMethod::AutoFit(expand) => {
4736                                if let Some(max) = resource_length[1] {
4737                                    let height = max - position[1];
4738                                    if height - size[1]
4739                                        + expand
4740                                        + margin
4741                                        + resource_panel.inner_margin[1]
4742                                        + resource_panel.inner_margin[0]
4743                                        > 0_f32
4744                                    {
4745                                        height - size[1]
4746                                            + expand
4747                                            + margin
4748                                            + resource_panel.inner_margin[1]
4749                                            + resource_panel.inner_margin[0]
4750                                    } else {
4751                                        0_f32
4752                                    }
4753                                } else {
4754                                    0_f32
4755                                }
4756                            }
4757                        };
4758                        if resource_panel.scroll_progress[1] > resource_panel.scroll_length[1] {
4759                            resource_panel.scroll_progress[1] = resource_panel.scroll_length[1];
4760                        };
4761                    };
4762                    match resource_panel.scroll_bar_display_method {
4763                        ScrollBarDisplayMethod::Always(ref config, margin, width) => {
4764                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4765                                (size[0] - margin[0] * 2_f32)
4766                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4767                            } else {
4768                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4769                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4770                            };
4771                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
4772                                position[0]
4773                                    + margin[0]
4774                                    + (size[0] - margin[0] * 2_f32 - line_length)
4775                                        * (resource_panel.scroll_progress[0]
4776                                            / resource_panel.scroll_length[0])
4777                            } else {
4778                                position[0]
4779                                    + margin[0]
4780                                    + (size[0]
4781                                        - margin[0] * 2_f32
4782                                        - width
4783                                        - margin[1]
4784                                        - line_length)
4785                                        * (resource_panel.scroll_progress[0]
4786                                            / resource_panel.scroll_length[0])
4787                            };
4788                            self.replace_resource(
4789                                &format!("{}XScroll", &id.name),
4790                                background.clone().background_type(&match config.clone() {
4791                                    BackgroundType::CustomRect(config) => {
4792                                        BackgroundType::CustomRect(
4793                                            config
4794                                                .ignore_render_layer(Some(true))
4795                                                .hidden(Some(resource_panel.hidden))
4796                                                .position_size_config(Some(
4797                                                    PositionSizeConfig::default()
4798                                                        .display_method(
4799                                                            HorizontalAlign::Left,
4800                                                            VerticalAlign::Bottom,
4801                                                        )
4802                                                        .origin_position(
4803                                                            line_position,
4804                                                            position[1] + size[1] - margin[1],
4805                                                        )
4806                                                        .origin_size(line_length, width),
4807                                                )),
4808                                        )
4809                                    }
4810                                    BackgroundType::Image(config) => BackgroundType::Image(
4811                                        config
4812                                            .ignore_render_layer(Some(true))
4813                                            .hidden(Some(resource_panel.hidden))
4814                                            .position_size_config(Some(
4815                                                PositionSizeConfig::default()
4816                                                    .display_method(
4817                                                        HorizontalAlign::Left,
4818                                                        VerticalAlign::Bottom,
4819                                                    )
4820                                                    .origin_position(
4821                                                        line_position,
4822                                                        position[1] + size[1] - margin[1],
4823                                                    )
4824                                                    .origin_size(line_length, width),
4825                                            )),
4826                                    ),
4827                                }),
4828                            )?;
4829                            self.use_resource(
4830                                &RustConstructorId {
4831                                    name: format!("{}XScroll", &id.name),
4832                                    discern_type: "Background".to_string(),
4833                                },
4834                                ui,
4835                                ctx,
4836                            )?;
4837                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
4838                                (size[1] - margin[0] * 2_f32)
4839                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4840                            } else {
4841                                (size[1] - width - margin[1] - margin[0] * 2_f32)
4842                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
4843                            };
4844                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
4845                                position[1]
4846                                    + margin[0]
4847                                    + (size[1] - margin[0] * 2_f32 - line_length)
4848                                        * (resource_panel.scroll_progress[1]
4849                                            / resource_panel.scroll_length[1])
4850                            } else {
4851                                position[1]
4852                                    + margin[0]
4853                                    + (size[1]
4854                                        - margin[0] * 2_f32
4855                                        - width
4856                                        - margin[1]
4857                                        - line_length)
4858                                        * (resource_panel.scroll_progress[1]
4859                                            / resource_panel.scroll_length[1])
4860                            };
4861                            self.replace_resource(
4862                                &format!("{}YScroll", &id.name),
4863                                background.background_type(&match config.clone() {
4864                                    BackgroundType::CustomRect(config) => {
4865                                        BackgroundType::CustomRect(
4866                                            config
4867                                                .ignore_render_layer(Some(true))
4868                                                .hidden(Some(resource_panel.hidden))
4869                                                .position_size_config(Some(
4870                                                    PositionSizeConfig::default()
4871                                                        .display_method(
4872                                                            HorizontalAlign::Right,
4873                                                            VerticalAlign::Top,
4874                                                        )
4875                                                        .origin_position(
4876                                                            position[0] + size[0] - margin[1],
4877                                                            line_position,
4878                                                        )
4879                                                        .origin_size(width, line_length),
4880                                                )),
4881                                        )
4882                                    }
4883                                    BackgroundType::Image(config) => BackgroundType::Image(
4884                                        config
4885                                            .ignore_render_layer(Some(true))
4886                                            .hidden(Some(resource_panel.hidden))
4887                                            .position_size_config(Some(
4888                                                PositionSizeConfig::default()
4889                                                    .display_method(
4890                                                        HorizontalAlign::Right,
4891                                                        VerticalAlign::Top,
4892                                                    )
4893                                                    .origin_position(
4894                                                        position[0] + size[0] - margin[1],
4895                                                        line_position,
4896                                                    )
4897                                                    .origin_size(width, line_length),
4898                                            )),
4899                                    ),
4900                                }),
4901                            )?;
4902                            self.use_resource(
4903                                &RustConstructorId {
4904                                    name: format!("{}YScroll", &id.name),
4905                                    discern_type: "Background".to_string(),
4906                                },
4907                                ui,
4908                                ctx,
4909                            )?;
4910                        }
4911                        ScrollBarDisplayMethod::OnlyScroll(ref config, margin, width) => {
4912                            resource_panel.scroll_bar_alpha[0] = if resource_panel.scrolled[0] {
4913                                self.reset_split_time(&format!(
4914                                    "{}ScrollBarXAlphaStart",
4915                                    &id.name
4916                                ))?;
4917                                255
4918                            } else if self.timer.now_time
4919                                - self
4920                                    .get_split_time(&format!("{}ScrollBarXAlphaStart", &id.name))?
4921                                    [0]
4922                                >= 1_f32
4923                                && self.timer.now_time
4924                                    - self
4925                                        .get_split_time(&format!("{}ScrollBarXAlpha", &id.name))?[0]
4926                                    >= self.tick_interval
4927                            {
4928                                self.reset_split_time(&format!("{}ScrollBarXAlpha", &id.name))?;
4929                                resource_panel.scroll_bar_alpha[0].saturating_sub(10)
4930                            } else {
4931                                resource_panel.scroll_bar_alpha[0]
4932                            };
4933                            resource_panel.scroll_bar_alpha[1] = if resource_panel.scrolled[1] {
4934                                self.reset_split_time(&format!(
4935                                    "{}ScrollBarYAlphaStart",
4936                                    &id.name
4937                                ))?;
4938                                255
4939                            } else if self.timer.now_time
4940                                - self
4941                                    .get_split_time(&format!("{}ScrollBarYAlphaStart", &id.name))?
4942                                    [0]
4943                                >= 1_f32
4944                                && self.timer.now_time
4945                                    - self
4946                                        .get_split_time(&format!("{}ScrollBarYAlpha", &id.name))?[0]
4947                                    >= self.tick_interval
4948                            {
4949                                self.reset_split_time(&format!("{}ScrollBarYAlpha", &id.name))?;
4950                                resource_panel.scroll_bar_alpha[1].saturating_sub(10)
4951                            } else {
4952                                resource_panel.scroll_bar_alpha[1]
4953                            };
4954                            let line_length = if resource_panel.scroll_length[1] == 0_f32 {
4955                                (size[0] - margin[0] * 2_f32)
4956                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4957                            } else {
4958                                (size[0] - width - margin[1] - margin[0] * 2_f32)
4959                                    * (size[0] / (resource_panel.scroll_length[0] + size[0]))
4960                            };
4961                            let line_position = if resource_panel.scroll_length[1] == 0_f32 {
4962                                position[0]
4963                                    + margin[0]
4964                                    + (size[0] - margin[0] * 2_f32 - line_length)
4965                                        * (resource_panel.scroll_progress[0]
4966                                            / resource_panel.scroll_length[0])
4967                            } else {
4968                                position[0]
4969                                    + margin[0]
4970                                    + (size[0]
4971                                        - margin[0] * 2_f32
4972                                        - width
4973                                        - margin[1]
4974                                        - line_length)
4975                                        * (resource_panel.scroll_progress[0]
4976                                            / resource_panel.scroll_length[0])
4977                            };
4978                            self.replace_resource(
4979                                &format!("{}XScroll", &id.name),
4980                                background.clone().background_type(&match config.clone() {
4981                                    BackgroundType::CustomRect(config) => {
4982                                        BackgroundType::CustomRect(
4983                                            config
4984                                                .ignore_render_layer(Some(true))
4985                                                .hidden(Some(resource_panel.hidden))
4986                                                .position_size_config(Some(
4987                                                    PositionSizeConfig::default()
4988                                                        .display_method(
4989                                                            HorizontalAlign::Left,
4990                                                            VerticalAlign::Bottom,
4991                                                        )
4992                                                        .origin_position(
4993                                                            line_position,
4994                                                            position[1] + size[1] - margin[1],
4995                                                        )
4996                                                        .origin_size(line_length, width),
4997                                                ))
4998                                                .alpha(Some(resource_panel.scroll_bar_alpha[0]))
4999                                                .border_alpha(Some(
5000                                                    resource_panel.scroll_bar_alpha[0],
5001                                                )),
5002                                        )
5003                                    }
5004                                    BackgroundType::Image(config) => BackgroundType::Image(
5005                                        config
5006                                            .ignore_render_layer(Some(true))
5007                                            .hidden(Some(resource_panel.hidden))
5008                                            .position_size_config(Some(
5009                                                PositionSizeConfig::default()
5010                                                    .display_method(
5011                                                        HorizontalAlign::Left,
5012                                                        VerticalAlign::Bottom,
5013                                                    )
5014                                                    .origin_position(
5015                                                        line_position,
5016                                                        position[1] + size[1] - margin[1],
5017                                                    )
5018                                                    .origin_size(line_length, width),
5019                                            ))
5020                                            .alpha(Some(resource_panel.scroll_bar_alpha[0]))
5021                                            .background_alpha(Some(
5022                                                resource_panel.scroll_bar_alpha[0],
5023                                            ))
5024                                            .overlay_alpha(Some(
5025                                                resource_panel.scroll_bar_alpha[0],
5026                                            )),
5027                                    ),
5028                                }),
5029                            )?;
5030                            self.use_resource(
5031                                &RustConstructorId {
5032                                    name: format!("{}XScroll", &id.name),
5033                                    discern_type: "Background".to_string(),
5034                                },
5035                                ui,
5036                                ctx,
5037                            )?;
5038                            let line_length = if resource_panel.scroll_length[0] == 0_f32 {
5039                                (size[1] - margin[0] * 2_f32)
5040                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5041                            } else {
5042                                (size[1] - width - margin[1] - margin[0] * 2_f32)
5043                                    * (size[1] / (resource_panel.scroll_length[1] + size[1]))
5044                            };
5045                            let line_position = if resource_panel.scroll_length[0] == 0_f32 {
5046                                position[1]
5047                                    + margin[0]
5048                                    + (size[1] - margin[0] * 2_f32 - line_length)
5049                                        * (resource_panel.scroll_progress[1]
5050                                            / resource_panel.scroll_length[1])
5051                            } else {
5052                                position[1]
5053                                    + margin[0]
5054                                    + (size[1]
5055                                        - margin[0] * 2_f32
5056                                        - width
5057                                        - margin[1]
5058                                        - line_length)
5059                                        * (resource_panel.scroll_progress[1]
5060                                            / resource_panel.scroll_length[1])
5061                            };
5062                            self.replace_resource(
5063                                &format!("{}YScroll", &id.name),
5064                                background.clone().background_type(&match config.clone() {
5065                                    BackgroundType::CustomRect(config) => {
5066                                        BackgroundType::CustomRect(
5067                                            config
5068                                                .ignore_render_layer(Some(true))
5069                                                .hidden(Some(resource_panel.hidden))
5070                                                .position_size_config(Some(
5071                                                    PositionSizeConfig::default()
5072                                                        .display_method(
5073                                                            HorizontalAlign::Right,
5074                                                            VerticalAlign::Top,
5075                                                        )
5076                                                        .origin_position(
5077                                                            position[0] + size[0] - margin[1],
5078                                                            line_position,
5079                                                        )
5080                                                        .origin_size(width, line_length),
5081                                                ))
5082                                                .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5083                                                .border_alpha(Some(
5084                                                    resource_panel.scroll_bar_alpha[1],
5085                                                )),
5086                                        )
5087                                    }
5088                                    BackgroundType::Image(config) => BackgroundType::Image(
5089                                        config
5090                                            .ignore_render_layer(Some(true))
5091                                            .hidden(Some(resource_panel.hidden))
5092                                            .position_size_config(Some(
5093                                                PositionSizeConfig::default()
5094                                                    .display_method(
5095                                                        HorizontalAlign::Right,
5096                                                        VerticalAlign::Top,
5097                                                    )
5098                                                    .origin_position(
5099                                                        position[0] + size[0] - margin[1],
5100                                                        line_position,
5101                                                    )
5102                                                    .origin_size(width, line_length),
5103                                            ))
5104                                            .alpha(Some(resource_panel.scroll_bar_alpha[1]))
5105                                            .background_alpha(Some(
5106                                                resource_panel.scroll_bar_alpha[1],
5107                                            ))
5108                                            .overlay_alpha(Some(
5109                                                resource_panel.scroll_bar_alpha[1],
5110                                            )),
5111                                    ),
5112                                }),
5113                            )?;
5114                            self.use_resource(
5115                                &RustConstructorId {
5116                                    name: format!("{}YScroll", &id.name),
5117                                    discern_type: "Background".to_string(),
5118                                },
5119                                ui,
5120                                ctx,
5121                            )?;
5122                        }
5123                        ScrollBarDisplayMethod::Hidden => {}
5124                    };
5125                    self.replace_resource(&id.name, resource_panel.clone())?;
5126                }
5127                _ => {}
5128            };
5129            Ok(())
5130        } else {
5131            Err(RustConstructorError {
5132                error_id: "ResourceNotFound".to_string(),
5133                description: format!("Resource '{}({})' not found.", id.name, id.discern_type),
5134            })
5135        }
5136    }
5137
5138    /// Switches to a different page and resets page-specific state.
5139    ///
5140    /// 切换到不同页面并重置页面特定状态。
5141    ///
5142    /// # Arguments
5143    ///
5144    /// * `name` - The name of the page to switch to
5145    ///
5146    /// # Returns
5147    ///
5148    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the page cannot be found.
5149    ///
5150    /// # 参数
5151    ///
5152    /// * `name` - 要切换到的页面名称
5153    ///
5154    /// # 返回值
5155    ///
5156    /// 成功时返回 `Ok(())`,如果页面无法找到则返回 `Err(RustConstructorError)`。
5157    pub fn switch_page(&mut self, name: &str) -> Result<(), RustConstructorError> {
5158        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5159            name: name.to_string(),
5160            discern_type: "PageData".to_string(),
5161        })?;
5162        page_data.enter_page_updated = false;
5163        self.timer.start_time = self.timer.total_time;
5164        self.current_page = name.to_string();
5165        self.update_timer();
5166        Ok(())
5167    }
5168
5169    /// Retrieves font definitions for a font resource.
5170    ///
5171    /// 获取字体资源的字体定义。
5172    ///
5173    /// # Arguments
5174    ///
5175    /// * `name` - The name of the font resource
5176    ///
5177    /// # Returns
5178    ///
5179    /// Returns `Ok(FontDefinitions)` if the font exists, or `Err(RustConstructorError)` if not found.
5180    ///
5181    /// # 参数
5182    ///
5183    /// * `name` - 字体资源的名称
5184    ///
5185    /// # 返回值
5186    ///
5187    /// 如果字体存在则返回 `Ok(FontDefinitions)`,否则返回 `Err(RustConstructorError)`。
5188    pub fn get_font(&self, name: &str) -> Result<WrapDefinitions, RustConstructorError> {
5189        let font = self.get_resource::<Font>(&RustConstructorId {
5190            name: name.to_string(),
5191            discern_type: "Font".to_string(),
5192        })?;
5193        Ok(font.font_definitions.clone())
5194    }
5195
5196    /// Registers all font resources with the egui context.
5197    ///
5198    /// 向egui上下文中注册所有字体资源。
5199    ///
5200    /// This method loads and registers all fonts that have been added to the application
5201    /// with the egui rendering system for text display.
5202    ///
5203    /// 此方法加载并注册应用程序中已添加的所有字体到egui渲染系统中,用于文本显示。
5204    ///
5205    /// # Arguments
5206    ///
5207    /// * `ctx` - The egui context for font registration
5208    ///
5209    /// # 参数
5210    ///
5211    /// * `ctx` - 用于字体注册的egui上下文
5212    pub fn register_all_fonts(&self, ctx: &Context) {
5213        let mut font_definitions_amount = FontDefinitions::default();
5214        let mut fonts = Vec::new();
5215        for i in 0..self.rust_constructor_resource.len() {
5216            if let Some(font) = self.rust_constructor_resource[i]
5217                .content
5218                .as_any()
5219                .downcast_ref::<Font>()
5220            {
5221                fonts.push((
5222                    self.rust_constructor_resource[i].id.name.clone(),
5223                    font.font_definitions.clone(),
5224                ));
5225            };
5226        }
5227        for i in &fonts {
5228            // 从 font_def 中提取对应字体的 Arc<FontData>
5229            if let Some(font_data) = i.1.font_definitions.font_data.get(&i.0) {
5230                font_definitions_amount
5231                    .font_data
5232                    .insert(i.0.clone(), Arc::clone(font_data));
5233                font_definitions_amount
5234                    .families
5235                    .entry(FontFamily::Name(i.0.clone().into()))
5236                    .or_default()
5237                    .push(i.0.clone());
5238            };
5239
5240            // 将字体添加到字体列表中
5241            font_definitions_amount
5242                .families
5243                .entry(FontFamily::Proportional)
5244                .or_default()
5245                .insert(0, i.0.to_owned());
5246
5247            font_definitions_amount
5248                .families
5249                .entry(FontFamily::Monospace)
5250                .or_default()
5251                .insert(0, i.0.to_owned());
5252        }
5253        ctx.set_fonts(font_definitions_amount);
5254    }
5255
5256    /// Processes position and size calculations for resources.
5257    ///
5258    /// 处理资源的最基本位置和尺寸计算。
5259    ///
5260    /// This method handles the complex positioning logic including grid-based layout,
5261    /// alignment, and offset calculations for UI resources.
5262    ///
5263    /// 此方法处理复杂的定位逻辑,包括基于网格的布局、对齐方式和UI资源的偏移计算。
5264    ///
5265    /// # Arguments
5266    ///
5267    /// * `position_size_config` - The configuration for position and size
5268    /// * `ctx` - The egui context for available space calculations
5269    ///
5270    /// # Returns
5271    ///
5272    /// Returns `[position, size]` as computed from the configuration
5273    ///
5274    /// # 参数
5275    ///
5276    /// * `position_size_config` - 位置和尺寸的配置
5277    /// * `ctx` - 用于可用空间计算的egui上下文
5278    ///
5279    /// # 返回值
5280    ///
5281    /// 返回根据配置计算出的 `[位置, 尺寸]`
5282    pub fn position_size_processor(
5283        &self,
5284        position_size_config: PositionSizeConfig,
5285        ctx: &Context,
5286    ) -> [[f32; 2]; 2] {
5287        let mut position = [0_f32, 0_f32];
5288        let mut size = [0_f32, 0_f32];
5289        size[0] = match position_size_config.x_size_grid[0] {
5290            0_f32 => position_size_config.origin_size[0],
5291            _ => {
5292                (ctx.available_rect().width() / position_size_config.x_size_grid[1]
5293                    * position_size_config.x_size_grid[0])
5294                    + position_size_config.origin_size[0]
5295            }
5296        };
5297        size[1] = match position_size_config.y_size_grid[0] {
5298            0_f32 => position_size_config.origin_size[1],
5299            _ => {
5300                (ctx.available_rect().height() / position_size_config.y_size_grid[1]
5301                    * position_size_config.y_size_grid[0])
5302                    + position_size_config.origin_size[1]
5303            }
5304        };
5305        position[0] = match position_size_config.x_location_grid[1] {
5306            0_f32 => position_size_config.origin_position[0],
5307            _ => {
5308                (ctx.available_rect().width() / position_size_config.x_location_grid[1]
5309                    * position_size_config.x_location_grid[0])
5310                    + position_size_config.origin_position[0]
5311            }
5312        };
5313        position[1] = match position_size_config.y_location_grid[1] {
5314            0_f32 => position_size_config.origin_position[1],
5315            _ => {
5316                (ctx.available_rect().height() / position_size_config.y_location_grid[1]
5317                    * position_size_config.y_location_grid[0])
5318                    + position_size_config.origin_position[1]
5319            }
5320        };
5321        match position_size_config.display_method.0 {
5322            HorizontalAlign::Left => {}
5323            HorizontalAlign::Center => position[0] -= size[0] / 2.0,
5324            HorizontalAlign::Right => position[0] -= size[0],
5325        };
5326        match position_size_config.display_method.1 {
5327            VerticalAlign::Top => {}
5328            VerticalAlign::Center => position[1] -= size[1] / 2.0,
5329            VerticalAlign::Bottom => position[1] -= size[1],
5330        };
5331        position[0] += position_size_config.offset[0];
5332        position[1] += position_size_config.offset[1];
5333        [position, size]
5334    }
5335
5336    /// Checks if a page has completed its initial loading phase.
5337    ///
5338    /// 检查页面是否已完成首次加载。
5339    ///
5340    /// # Arguments
5341    ///
5342    /// * `name` - The name of the page to check
5343    ///
5344    /// # Returns
5345    ///
5346    /// Returns `Ok(true)` if the page has completed loading, or `Ok(false)` if the page has not completed loading.
5347    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5348    ///
5349    /// # 参数
5350    ///
5351    /// * `name` - 要检查的页面名称
5352    ///
5353    /// # 返回值
5354    ///
5355    /// 如果页面已完成加载则返回 `Ok(true)`,如果未加载则返回 `Ok(false)`。
5356    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5357    pub fn check_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5358        let page_data = self
5359            .get_resource::<PageData>(&RustConstructorId {
5360                name: name.to_string(),
5361                discern_type: "PageData".to_string(),
5362            })?
5363            .clone();
5364        if !page_data.change_page_updated {
5365            self.new_page_update(name)?;
5366        };
5367        Ok(page_data.change_page_updated)
5368    }
5369
5370    /// Checks if a page has completed its enter transition.
5371    ///
5372    /// 检查页面是否已完成进入过渡。
5373    ///
5374    /// # Arguments
5375    ///
5376    /// * `name` - The name of the page to check
5377    ///
5378    /// # Returns
5379    ///
5380    /// Returns `Ok(true)` if the page has completed entering, or `Ok(false)` if the page has not completed entering.
5381    /// Returns `Err(RustConstructorError)` if the page cannot be found.
5382    ///
5383    /// # 参数
5384    ///
5385    /// * `name` - 要检查的页面名称
5386    ///
5387    /// # 返回值
5388    ///
5389    /// 如果页面已完成进入则返回 `Ok(true)`,如果未过渡则返回 `Ok(false)`。
5390    /// 如果页面无法找到则返回 `Err(RustConstructorError)`。
5391    pub fn check_enter_updated(&mut self, name: &str) -> Result<bool, RustConstructorError> {
5392        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5393            name: name.to_string(),
5394            discern_type: "PageData".to_string(),
5395        })?;
5396        page_data.enter_page_updated = true;
5397        Ok(page_data.enter_page_updated)
5398    }
5399
5400    /// Updates when entering a new page.
5401    ///
5402    /// 进入新页面时的更新。
5403    ///
5404    /// This method is used to ensure the accuracy of the content based on the page, and the Rust Constructor will automatically call this method.
5405    ///
5406    /// 此方法用于确保基于页面的内容的准确性,Rust Constructor会自动调用此方法。
5407    ///
5408    /// # Arguments
5409    ///
5410    /// * `name` - The name of the page to be updated
5411    ///
5412    /// # Returns
5413    ///
5414    /// If the update is successful, return `Ok(())`; if the resource is not found, return `Err(RustConstructorError)`.
5415    ///
5416    /// # 参数
5417    ///
5418    /// * `name` - 要更新的页面名称
5419    ///
5420    /// # 返回值
5421    ///
5422    /// 如果更新成功则返回`Ok(())`,找不到资源则返回`Err(RustConstructorError)`。
5423    pub fn new_page_update(&mut self, name: &str) -> Result<(), RustConstructorError> {
5424        let page_data = self.get_resource_mut::<PageData>(&RustConstructorId {
5425            name: name.to_string(),
5426            discern_type: "PageData".to_string(),
5427        })?;
5428        page_data.change_page_updated = true;
5429        self.timer.start_time = self.timer.total_time;
5430        self.update_timer();
5431        Ok(())
5432    }
5433
5434    /// Updates frame timing statistics for performance monitoring.
5435    ///
5436    /// 更新帧数统计信息用于性能监控。
5437    ///
5438    /// This method maintains a rolling window of frame times and calculates
5439    /// performance metrics like frame rate.
5440    ///
5441    /// 此方法维护帧时间的滚动窗口并计算帧率等性能指标。
5442    pub fn update_frame_stats(&mut self) {
5443        let current_time = self.timer.total_time;
5444        if let Some(last) = self.last_frame_time {
5445            let delta = current_time - last;
5446            self.frame_times.push(delta);
5447            const MAX_SAMPLES: usize = 120;
5448            if self.frame_times.len() > MAX_SAMPLES {
5449                let remove_count = self.frame_times.len() - MAX_SAMPLES;
5450                self.frame_times.drain(0..remove_count);
5451            }
5452        }
5453        self.last_frame_time = Some(current_time);
5454    }
5455
5456    /// Update the frame rate.
5457    ///
5458    /// 更新帧数。
5459    ///
5460    /// This method is used to obtain the number of program frames and conduct analysis.
5461    ///
5462    /// 此方法用于获取程序帧数并进行分析。
5463    ///
5464    /// # Returns
5465    ///
5466    /// Return the number of frames.
5467    ///
5468    /// # 返回值
5469    ///
5470    /// 返回帧数。
5471    pub fn current_fps(&self) -> f32 {
5472        if self.frame_times.is_empty() {
5473            0.0
5474        } else {
5475            1.0 / (self.frame_times.iter().sum::<f32>() / self.frame_times.len() as f32)
5476        }
5477    }
5478
5479    /// Resets the split time for a specific resource.
5480    ///
5481    /// 重置特定资源的分段计时器。
5482    ///
5483    /// # Arguments
5484    ///
5485    /// * `name` - The name of the split time resource to reset
5486    ///
5487    /// # Returns
5488    ///
5489    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5490    ///
5491    /// # 参数
5492    ///
5493    /// * `name` - 要重置的分段时间资源名称
5494    ///
5495    /// # 返回值
5496    ///
5497    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5498    pub fn reset_split_time(&mut self, name: &str) -> Result<(), RustConstructorError> {
5499        let new_time = [self.timer.now_time, self.timer.total_time];
5500        let split_time = self.get_resource_mut::<SplitTime>(&RustConstructorId {
5501            name: name.to_string(),
5502            discern_type: "SplitTime".to_string(),
5503        })?;
5504        split_time.time = new_time;
5505        Ok(())
5506    }
5507
5508    /// Retrieves the timing information from a split time resource.
5509    ///
5510    /// 获取分段计时器资源的时间信息。
5511    ///
5512    /// # Arguments
5513    ///
5514    /// * `name` - The name of the split time resource
5515    ///
5516    /// # Returns
5517    ///
5518    /// Returns `Ok([page_runtime, total_runtime])` if found, or `Err(RustConstructorError)` if not found.
5519    ///
5520    /// # 参数
5521    ///
5522    /// * `name` - 分段计时器资源的名称
5523    ///
5524    /// # 返回值
5525    ///
5526    /// 如果找到则返回 `Ok([页面运行时间, 总运行时间])`,否则返回 `Err(RustConstructorError)`。
5527    pub fn get_split_time(&self, name: &str) -> Result<[f32; 2], RustConstructorError> {
5528        let split_time = self.get_resource::<SplitTime>(&RustConstructorId {
5529            name: name.to_string(),
5530            discern_type: "SplitTime".to_string(),
5531        })?;
5532        Ok(split_time.time)
5533    }
5534
5535    /// Updates the application timer with current timing information.
5536    ///
5537    /// 更新应用程序计时器的当前时间信息。
5538    ///
5539    /// This method updates both the total runtime and current page runtime.
5540    ///
5541    /// 此方法更新总运行时间和当前页面运行时间。
5542    pub fn update_timer(&mut self) {
5543        let elapsed = self.timer.timer.elapsed();
5544        let seconds = elapsed.as_secs();
5545        let milliseconds = elapsed.subsec_millis();
5546        self.timer.total_time = seconds as f32 + milliseconds as f32 / 1000.0;
5547        self.timer.now_time = self.timer.total_time - self.timer.start_time
5548    }
5549
5550    /// Modifies the value of a variable resource.
5551    ///
5552    /// 修改变量资源的值。
5553    ///
5554    /// # Arguments
5555    ///
5556    /// * `name` - The name of the variable resource
5557    /// * `value` - The new value to set (use `None` to clear)
5558    ///
5559    /// # Returns
5560    ///
5561    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5562    ///
5563    /// # 参数
5564    ///
5565    /// * `name` - 变量资源的名称
5566    /// * `value` - 要设置的新值(使用 `None` 来清除)
5567    ///
5568    /// # 返回值
5569    ///
5570    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5571    pub fn modify_variable<T: Debug + 'static>(
5572        &mut self,
5573        name: &str,
5574        value: Option<T>,
5575    ) -> Result<(), RustConstructorError> {
5576        let variable = self.get_resource_mut::<Variable<T>>(&RustConstructorId {
5577            name: name.to_string(),
5578            discern_type: "Variable".to_string(),
5579        })?;
5580        variable.value = value;
5581        Ok(())
5582    }
5583
5584    /// Take the variable out of the list.
5585    ///
5586    /// 从列表中取出变量。
5587    ///
5588    /// # Arguments
5589    ///
5590    /// * `name` - The name of the variable resource
5591    ///
5592    /// # Returns
5593    ///
5594    /// Returns `Ok(Option<T>)` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5595    ///
5596    /// # 参数
5597    ///
5598    /// * `name` - 变量资源的名称
5599    ///
5600    /// # 返回值
5601    ///
5602    /// 成功时返回 `Ok(Option<T>)`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5603    pub fn get_variable<T: Debug + Clone + 'static>(
5604        &self,
5605        name: &str,
5606    ) -> Result<Option<T>, RustConstructorError> {
5607        if let Ok(variable) = self.get_resource::<Variable<T>>(&RustConstructorId {
5608            name: name.to_string(),
5609            discern_type: "Variable".to_string(),
5610        }) {
5611            Ok(variable.value.clone())
5612        } else if self
5613            .check_resource_exists(&RustConstructorId {
5614                name: name.to_string(),
5615                discern_type: "Variable".to_string(),
5616            })
5617            .is_none()
5618        {
5619            Err(RustConstructorError {
5620                error_id: "ResourceNotFound".to_string(),
5621                description: format!("Resource '{name}(Variable<T>)' not found."),
5622            })
5623        } else {
5624            Err(RustConstructorError {
5625                error_id: "ResourceGenericMismatch".to_string(),
5626                description: format!(
5627                    "The generic type of the resource '{name}(Variable<T>)' is mismatched."
5628                ),
5629            })
5630        }
5631    }
5632
5633    /// Modify the enable status of the switch.
5634    ///
5635    /// 修改开关的启用状态。
5636    ///
5637    /// # Arguments
5638    ///
5639    /// * `name` - The name of the switch resource
5640    /// * `enable` - The new enable status
5641    ///
5642    /// # Returns
5643    ///
5644    /// Returns `Ok(())` on success, or `Err(RustConstructorError)` if the resource cannot be found.
5645    ///
5646    /// # 参数
5647    ///
5648    /// * `name` - 开关资源的名称
5649    /// * `enable` - 新的启用状态
5650    ///
5651    /// # 返回值
5652    ///
5653    /// 成功时返回 `Ok(())`,如果资源无法找到则返回 `Err(RustConstructorError)`。
5654    pub fn set_switch_enable(
5655        &mut self,
5656        name: &str,
5657        enable: bool,
5658    ) -> Result<(), RustConstructorError> {
5659        let switch = self.get_resource_mut::<Switch>(&RustConstructorId {
5660            name: name.to_string(),
5661            discern_type: "Switch".to_string(),
5662        })?;
5663        switch.enable = enable;
5664        Ok(())
5665    }
5666
5667    /// Retrieves the current state and interaction data from a switch resource.
5668    ///
5669    /// 获取开关资源的当前状态和交互数据。
5670    ///
5671    /// # Arguments
5672    ///
5673    /// * `name` - The name of the switch resource
5674    ///
5675    /// # Returns
5676    ///
5677    /// Returns `Ok(SwitchData)` containing the switch state and interaction history,
5678    /// or `Err(RustConstructorError)` if the resource cannot be found.
5679    ///
5680    /// # 参数
5681    ///
5682    /// * `name` - 开关资源的名称
5683    ///
5684    /// # 返回值
5685    ///
5686    /// 返回包含开关状态和交互历史的 `Ok(SwitchData)`,
5687    /// 如果资源无法找到则返回 `Err(RustConstructorError)`。
5688    pub fn check_switch_data(&self, name: &str) -> Result<SwitchData, RustConstructorError> {
5689        let switch = self.get_resource::<Switch>(&RustConstructorId {
5690            name: name.to_string(),
5691            discern_type: "Switch".to_string(),
5692        })?;
5693        Ok(SwitchData {
5694            switched: switch.switched,
5695            last_frame_clicked: switch.last_frame_clicked,
5696            state: switch.state,
5697        })
5698    }
5699}