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