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