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