Skip to main content

rust_constructor/
app.rs

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