xref: /StarryEngine/starry_applications/src/asset_manager/code/mod.rs (revision 731cae0674923fcc85c6e683a2eee596eb642796)
1 use self::asset_item_grid::AssetItemGrid;
2 use self::asset_item_list::AssetItemList;
3 use crate::starry_toolkit::traits::focus::Focus;
4 use starry_client::base::color::Color;
5 use starry_server::base::image::Image as ImageResource;
6 use starry_server::core::{SCREEN_HEIGHT, SCREEN_WIDTH};
7 use starry_toolkit::layout::list::{List, ListArrangeType};
8 use starry_toolkit::{
9     base::{panel::Panel, rect::Rect},
10     layout::grid::{Grid, GridArrangeType},
11     traits::enter::Enter,
12     widgets::image::Image,
13 };
14 use std::{collections::BTreeMap, fs, sync::Arc};
15 pub mod asset_item_grid;
16 pub mod asset_item_list;
17 
18 const DESKTOP_BG_PATH: &[u8] = include_bytes!("../resource/desktop_bg.png");
19 const LOADING_IMG_PATH: &[u8] = include_bytes!("../resource/loading.png");
20 
21 pub struct AssetManager {
22     cur_path: String,
23     asset_grid: Arc<Grid>,
24     asset_list: Arc<List>,
25     items: BTreeMap<(usize, usize), Arc<AssetItemGrid>>,
26     panel: Arc<Panel>,
27     // 原则上一个应用程序对应一个Panel和Window
28     // 这里额外创建一个Panel用于Loading图标优先显示
29     // 后续通过Server来显示Loading或不显示Loading
30     loading_panel: Arc<Panel>,
31     init_show: bool,
32 }
33 
34 impl AssetManager {
new() -> Self35     pub fn new() -> Self {
36         AssetManager {
37             cur_path: String::from("/"),
38             asset_grid: Grid::new(),
39             asset_list: List::new(),
40             items: BTreeMap::new(),
41             panel: Panel::new(
42                 Rect::new(0, 0, SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32),
43                 "Title",
44                 Color::rgb(0, 0, 0),
45             ),
46             loading_panel: Panel::new(
47                 Rect::new(SCREEN_WIDTH as i32 - 64, SCREEN_HEIGHT as i32 - 64, 64, 64),
48                 "Loading",
49                 Color::rgb(255, 255, 255),
50             ),
51             init_show: true,
52         }
53     }
54 
init_grid(&mut self)55     pub fn init_grid(&mut self) {
56         self.init_loading_panel();
57 
58         let grid = self.asset_grid.clone();
59         grid.set_upper_limit(8);
60         grid.set_space(20, 20);
61         grid.set_arrange_type(GridArrangeType::Horizontal);
62 
63         // 处理输入回调
64         let self_ptr = self as *mut AssetManager;
65         grid.set_enter_callback(move |grid, char, redraw| {
66             let asset_manager: &mut AssetManager = unsafe { &mut *self_ptr };
67 
68             if char == '\n' {
69                 if let Some(item) = asset_manager.items.get(&grid.focused_id.get().unwrap()) {
70                     // 判断是否是文件夹
71                     if item.is_dir.get() == false {
72                         return;
73                     }
74 
75                     // 返回上级目录
76                     if item.file_path.borrow().eq(&"..".to_string()) {
77                         if asset_manager.cur_path.len() == 1 {
78                             return;
79                         } else {
80                             let split_path =
81                                 &asset_manager.cur_path[..asset_manager.cur_path.len() - 1];
82                             let slash_pos = split_path.rfind('/').unwrap();
83                             let _ = asset_manager.cur_path.split_off(slash_pos + 1);
84                         }
85                     } else {
86                         // 打开文件夹
87                         asset_manager.cur_path.push_str(&item.file_path.borrow());
88                         asset_manager.cur_path.push_str(&"/");
89                     }
90                     asset_manager.refresh_grid();
91                 }
92 
93                 return;
94             }
95 
96             let row_offset: i32 = match char {
97                 'a' => 0,
98                 'A' => 0,
99                 'd' => 0,
100                 'D' => 0,
101                 'w' => -1,
102                 'W' => -1,
103                 's' => 1,
104                 'S' => 1,
105                 _ => 0,
106             };
107 
108             let col_offset: i32 = match char {
109                 'a' => -1,
110                 'A' => -1,
111                 'd' => 1,
112                 'D' => 1,
113                 'w' => 0,
114                 'W' => 0,
115                 's' => 0,
116                 'S' => 0,
117                 _ => 0,
118             };
119 
120             if row_offset == 0 && col_offset == 0 {
121                 return;
122             }
123             let mut nxt_row = grid.focused_id.get().unwrap().0 as i32 + row_offset;
124             let mut nxt_col = grid.focused_id.get().unwrap().1 as i32 + col_offset;
125             loop {
126                 if nxt_row < 0
127                     || nxt_row >= grid.max_row.get() as i32
128                     || nxt_col < 0
129                     || nxt_col >= grid.max_column.get() as i32
130                 {
131                     return;
132                 }
133 
134                 if grid
135                     .elements
136                     .borrow()
137                     .contains_key(&(nxt_row as usize, nxt_col as usize))
138                 {
139                     break;
140                 }
141 
142                 nxt_row += row_offset;
143                 nxt_col += col_offset;
144             }
145 
146             grid.focus(
147                 grid.elements
148                     .borrow()
149                     .get(&(nxt_row as usize, nxt_col as usize))
150                     .unwrap(),
151             );
152 
153             asset_manager.loading_panel.draw();
154             redraw.set(true);
155         });
156 
157         self.panel.add_child(&Image::new_from_image(
158             ImageResource::from_path(DESKTOP_BG_PATH).unwrap(),
159         ));
160 
161         self.panel.add_child(&(self.asset_grid));
162         // self.panel.set_renderer_mode(PanelRendererMode::WithWireframe);
163     }
164 
init_list(&mut self)165     pub fn init_list(&mut self) {
166         self.init_loading_panel();
167 
168         let list = self.asset_list.clone();
169         list.set_arrange_type(ListArrangeType::Vertical);
170         list.set_space(3);
171 
172         self.panel.add_child(&Image::new_from_image(
173             ImageResource::from_path(DESKTOP_BG_PATH).unwrap(),
174         ));
175 
176         self.panel.add_child(&(self.asset_list));
177         // self.panel.set_renderer_mode(PanelRendererMode::WithWireframe);
178     }
179 
init_loading_panel(&mut self)180     fn init_loading_panel(&mut self) {
181         self.loading_panel.add_child(&Image::new_from_image(
182             ImageResource::from_path(LOADING_IMG_PATH).unwrap(),
183         ));
184     }
185 
refresh_grid(&mut self)186     pub fn refresh_grid(&mut self) {
187         self.items.clear();
188         self.asset_grid.clear();
189 
190         // 父目录
191         let parent_asset_item = AssetItemGrid::new("..", true);
192         let (row, col) = self.asset_grid.add_element(&parent_asset_item);
193         self.items.insert((row, col), parent_asset_item.clone());
194 
195         // 读取目录中的文件列表
196         if let Ok(entries) = fs::read_dir(&self.cur_path) {
197             for entry in entries {
198                 if let Ok(item) = entry {
199                     let is_dir = if let Ok(metadata) = item.metadata() {
200                         metadata.is_dir()
201                     } else {
202                         false
203                     };
204 
205                     let asset_item = AssetItemGrid::new(item.file_name().to_str().unwrap(), is_dir);
206                     let (row, col) = self.asset_grid.add_element(&asset_item);
207                     self.items.insert((row, col), asset_item.clone());
208                 }
209             }
210         } else {
211             println!(
212                 "[Error] AssetManager failed to read dir {:?}",
213                 self.cur_path
214             );
215         }
216 
217         let grid = self.asset_grid.clone();
218         if let Some(widget) = grid.elements.borrow().get(&(0, 0)) {
219             grid.focused_id.set(Some((0, 0)));
220             grid.focus(widget);
221         }
222 
223         if self.init_show == true {
224             self.init_show = false
225         } else {
226             self.loading_panel.draw();
227         }
228         self.panel.draw();
229     }
230 
refresh_list(&mut self)231     pub fn refresh_list(&mut self) {
232         self.items.clear();
233 
234         // 父目录
235         // let parent_asset_item = AssetItem_List::new("..", true);
236         // let _index= self.asset_list.add_element(&parent_asset_item);
237 
238         // 读取目录中的文件列表
239         if let Ok(entries) = fs::read_dir(&self.cur_path) {
240             for entry in entries {
241                 if let Ok(item) = entry {
242                     let is_dir = if let Ok(metadata) = item.metadata() {
243                         metadata.is_dir()
244                     } else {
245                         false
246                     };
247 
248                     let asset_item = AssetItemList::new(item.file_name().to_str().unwrap(), is_dir);
249                     let _index = self.asset_list.add_element(&asset_item);
250                 }
251             }
252         } else {
253             println!(
254                 "[Error] AssetManager failed to read dir {:?}",
255                 self.cur_path
256             );
257         }
258 
259         if self.init_show == true {
260             self.init_show = false
261         } else {
262             self.loading_panel.draw();
263         }
264         self.panel.draw();
265     }
266 
exec(&mut self)267     pub fn exec(&mut self) {
268         self.panel.exec();
269     }
270 }
271