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