xref: /StarryEngine/starry_applications/src/asset_manager/code/mod.rs (revision 731cae0674923fcc85c6e683a2eee596eb642796)
1*731cae06SR0ronoa use self::asset_item_grid::AssetItemGrid;
2*731cae06SR0ronoa use self::asset_item_list::AssetItemList;
349182ea7SR0ronoa use crate::starry_toolkit::traits::focus::Focus;
4b0262857SR0ronoa use starry_client::base::color::Color;
58a41b76cSR0ronoa use starry_server::base::image::Image as ImageResource;
649182ea7SR0ronoa use starry_server::core::{SCREEN_HEIGHT, SCREEN_WIDTH};
7*731cae06SR0ronoa use starry_toolkit::layout::list::{List, ListArrangeType};
849182ea7SR0ronoa use starry_toolkit::{
949182ea7SR0ronoa     base::{panel::Panel, rect::Rect},
10b0262857SR0ronoa     layout::grid::{Grid, GridArrangeType},
118a41b76cSR0ronoa     traits::enter::Enter,
122b942a51SR0ronoa     widgets::image::Image,
1349182ea7SR0ronoa };
148a41b76cSR0ronoa use std::{collections::BTreeMap, fs, sync::Arc};
15*731cae06SR0ronoa pub mod asset_item_grid;
16*731cae06SR0ronoa pub mod asset_item_list;
1749182ea7SR0ronoa 
1849182ea7SR0ronoa const DESKTOP_BG_PATH: &[u8] = include_bytes!("../resource/desktop_bg.png");
191bee64b6SR0ronoa const LOADING_IMG_PATH: &[u8] = include_bytes!("../resource/loading.png");
2049182ea7SR0ronoa 
218a41b76cSR0ronoa pub struct AssetManager {
2249182ea7SR0ronoa     cur_path: String,
238a41b76cSR0ronoa     asset_grid: Arc<Grid>,
24*731cae06SR0ronoa     asset_list: Arc<List>,
25*731cae06SR0ronoa     items: BTreeMap<(usize, usize), Arc<AssetItemGrid>>,
261bee64b6SR0ronoa     panel: Arc<Panel>,
271bee64b6SR0ronoa     // 原则上一个应用程序对应一个Panel和Window
281bee64b6SR0ronoa     // 这里额外创建一个Panel用于Loading图标优先显示
291bee64b6SR0ronoa     // 后续通过Server来显示Loading或不显示Loading
301bee64b6SR0ronoa     loading_panel: Arc<Panel>,
311bee64b6SR0ronoa     init_show: bool,
3249182ea7SR0ronoa }
3349182ea7SR0ronoa 
348a41b76cSR0ronoa impl AssetManager {
new() -> Self3549182ea7SR0ronoa     pub fn new() -> Self {
368a41b76cSR0ronoa         AssetManager {
3749182ea7SR0ronoa             cur_path: String::from("/"),
388a41b76cSR0ronoa             asset_grid: Grid::new(),
39*731cae06SR0ronoa             asset_list: List::new(),
408a41b76cSR0ronoa             items: BTreeMap::new(),
418a41b76cSR0ronoa             panel: Panel::new(
428a41b76cSR0ronoa                 Rect::new(0, 0, SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32),
438a41b76cSR0ronoa                 "Title",
448a41b76cSR0ronoa                 Color::rgb(0, 0, 0),
458a41b76cSR0ronoa             ),
461bee64b6SR0ronoa             loading_panel: Panel::new(
471bee64b6SR0ronoa                 Rect::new(SCREEN_WIDTH as i32 - 64, SCREEN_HEIGHT as i32 - 64, 64, 64),
481bee64b6SR0ronoa                 "Loading",
491bee64b6SR0ronoa                 Color::rgb(255, 255, 255),
501bee64b6SR0ronoa             ),
511bee64b6SR0ronoa             init_show: true,
5249182ea7SR0ronoa         }
5349182ea7SR0ronoa     }
5449182ea7SR0ronoa 
init_grid(&mut self)55*731cae06SR0ronoa     pub fn init_grid(&mut self) {
561bee64b6SR0ronoa         self.init_loading_panel();
571bee64b6SR0ronoa 
588a41b76cSR0ronoa         let grid = self.asset_grid.clone();
591bee64b6SR0ronoa         grid.set_upper_limit(8);
6049182ea7SR0ronoa         grid.set_space(20, 20);
61b0262857SR0ronoa         grid.set_arrange_type(GridArrangeType::Horizontal);
628a41b76cSR0ronoa 
632b942a51SR0ronoa         // 处理输入回调
648a41b76cSR0ronoa         let self_ptr = self as *mut AssetManager;
658a41b76cSR0ronoa         grid.set_enter_callback(move |grid, char, redraw| {
668a41b76cSR0ronoa             let asset_manager: &mut AssetManager = unsafe { &mut *self_ptr };
678a41b76cSR0ronoa 
681bee64b6SR0ronoa             if char == '\n' {
698a41b76cSR0ronoa                 if let Some(item) = asset_manager.items.get(&grid.focused_id.get().unwrap()) {
701bee64b6SR0ronoa                     // 判断是否是文件夹
711bee64b6SR0ronoa                     if item.is_dir.get() == false {
721bee64b6SR0ronoa                         return;
731bee64b6SR0ronoa                     }
741bee64b6SR0ronoa 
751bee64b6SR0ronoa                     // 返回上级目录
762b942a51SR0ronoa                     if item.file_path.borrow().eq(&"..".to_string()) {
772b942a51SR0ronoa                         if asset_manager.cur_path.len() == 1 {
782b942a51SR0ronoa                             return;
792b942a51SR0ronoa                         } else {
802b942a51SR0ronoa                             let split_path =
812b942a51SR0ronoa                                 &asset_manager.cur_path[..asset_manager.cur_path.len() - 1];
822b942a51SR0ronoa                             let slash_pos = split_path.rfind('/').unwrap();
832b942a51SR0ronoa                             let _ = asset_manager.cur_path.split_off(slash_pos + 1);
842b942a51SR0ronoa                         }
852b942a51SR0ronoa                     } else {
861bee64b6SR0ronoa                         // 打开文件夹
878a41b76cSR0ronoa                         asset_manager.cur_path.push_str(&item.file_path.borrow());
888a41b76cSR0ronoa                         asset_manager.cur_path.push_str(&"/");
892b942a51SR0ronoa                     }
90*731cae06SR0ronoa                     asset_manager.refresh_grid();
9149182ea7SR0ronoa                 }
9249182ea7SR0ronoa 
938a41b76cSR0ronoa                 return;
948a41b76cSR0ronoa             }
958a41b76cSR0ronoa 
968a41b76cSR0ronoa             let row_offset: i32 = match char {
978a41b76cSR0ronoa                 'a' => 0,
988a41b76cSR0ronoa                 'A' => 0,
998a41b76cSR0ronoa                 'd' => 0,
1008a41b76cSR0ronoa                 'D' => 0,
1018a41b76cSR0ronoa                 'w' => -1,
1028a41b76cSR0ronoa                 'W' => -1,
1038a41b76cSR0ronoa                 's' => 1,
1048a41b76cSR0ronoa                 'S' => 1,
1058a41b76cSR0ronoa                 _ => 0,
1068a41b76cSR0ronoa             };
1078a41b76cSR0ronoa 
1088a41b76cSR0ronoa             let col_offset: i32 = match char {
1098a41b76cSR0ronoa                 'a' => -1,
1108a41b76cSR0ronoa                 'A' => -1,
1118a41b76cSR0ronoa                 'd' => 1,
1128a41b76cSR0ronoa                 'D' => 1,
1138a41b76cSR0ronoa                 'w' => 0,
1148a41b76cSR0ronoa                 'W' => 0,
1158a41b76cSR0ronoa                 's' => 0,
1168a41b76cSR0ronoa                 'S' => 0,
1178a41b76cSR0ronoa                 _ => 0,
1188a41b76cSR0ronoa             };
1198a41b76cSR0ronoa 
1208a41b76cSR0ronoa             if row_offset == 0 && col_offset == 0 {
1218a41b76cSR0ronoa                 return;
1228a41b76cSR0ronoa             }
1238a41b76cSR0ronoa             let mut nxt_row = grid.focused_id.get().unwrap().0 as i32 + row_offset;
1248a41b76cSR0ronoa             let mut nxt_col = grid.focused_id.get().unwrap().1 as i32 + col_offset;
1258a41b76cSR0ronoa             loop {
1268a41b76cSR0ronoa                 if nxt_row < 0
1278a41b76cSR0ronoa                     || nxt_row >= grid.max_row.get() as i32
1288a41b76cSR0ronoa                     || nxt_col < 0
1298a41b76cSR0ronoa                     || nxt_col >= grid.max_column.get() as i32
1308a41b76cSR0ronoa                 {
1318a41b76cSR0ronoa                     return;
1328a41b76cSR0ronoa                 }
1338a41b76cSR0ronoa 
1348a41b76cSR0ronoa                 if grid
1358a41b76cSR0ronoa                     .elements
1368a41b76cSR0ronoa                     .borrow()
1378a41b76cSR0ronoa                     .contains_key(&(nxt_row as usize, nxt_col as usize))
1388a41b76cSR0ronoa                 {
1398a41b76cSR0ronoa                     break;
1408a41b76cSR0ronoa                 }
1418a41b76cSR0ronoa 
1428a41b76cSR0ronoa                 nxt_row += row_offset;
1438a41b76cSR0ronoa                 nxt_col += col_offset;
1448a41b76cSR0ronoa             }
1458a41b76cSR0ronoa 
1468a41b76cSR0ronoa             grid.focus(
1478a41b76cSR0ronoa                 grid.elements
1488a41b76cSR0ronoa                     .borrow()
1498a41b76cSR0ronoa                     .get(&(nxt_row as usize, nxt_col as usize))
1508a41b76cSR0ronoa                     .unwrap(),
1518a41b76cSR0ronoa             );
1528a41b76cSR0ronoa 
1531bee64b6SR0ronoa             asset_manager.loading_panel.draw();
1541bee64b6SR0ronoa             redraw.set(true);
1558a41b76cSR0ronoa         });
1568a41b76cSR0ronoa 
1571bee64b6SR0ronoa         self.panel.add_child(&Image::new_from_image(
1588a41b76cSR0ronoa             ImageResource::from_path(DESKTOP_BG_PATH).unwrap(),
1598a41b76cSR0ronoa         ));
1608a41b76cSR0ronoa 
1618a41b76cSR0ronoa         self.panel.add_child(&(self.asset_grid));
162*731cae06SR0ronoa         // self.panel.set_renderer_mode(PanelRendererMode::WithWireframe);
163*731cae06SR0ronoa     }
164*731cae06SR0ronoa 
init_list(&mut self)165*731cae06SR0ronoa     pub fn init_list(&mut self) {
166*731cae06SR0ronoa         self.init_loading_panel();
167*731cae06SR0ronoa 
168*731cae06SR0ronoa         let list = self.asset_list.clone();
169*731cae06SR0ronoa         list.set_arrange_type(ListArrangeType::Vertical);
170*731cae06SR0ronoa         list.set_space(3);
171*731cae06SR0ronoa 
172*731cae06SR0ronoa         self.panel.add_child(&Image::new_from_image(
173*731cae06SR0ronoa             ImageResource::from_path(DESKTOP_BG_PATH).unwrap(),
174*731cae06SR0ronoa         ));
175*731cae06SR0ronoa 
176*731cae06SR0ronoa         self.panel.add_child(&(self.asset_list));
177*731cae06SR0ronoa         // self.panel.set_renderer_mode(PanelRendererMode::WithWireframe);
1788a41b76cSR0ronoa     }
1798a41b76cSR0ronoa 
init_loading_panel(&mut self)1801bee64b6SR0ronoa     fn init_loading_panel(&mut self) {
1811bee64b6SR0ronoa         self.loading_panel.add_child(&Image::new_from_image(
1821bee64b6SR0ronoa             ImageResource::from_path(LOADING_IMG_PATH).unwrap(),
1831bee64b6SR0ronoa         ));
1841bee64b6SR0ronoa     }
1851bee64b6SR0ronoa 
refresh_grid(&mut self)186*731cae06SR0ronoa     pub fn refresh_grid(&mut self) {
1878a41b76cSR0ronoa         self.items.clear();
1888a41b76cSR0ronoa         self.asset_grid.clear();
1898a41b76cSR0ronoa 
1902b942a51SR0ronoa         // 父目录
191*731cae06SR0ronoa         let parent_asset_item = AssetItemGrid::new("..", true);
1921bee64b6SR0ronoa         let (row, col) = self.asset_grid.add_element(&parent_asset_item);
1932b942a51SR0ronoa         self.items.insert((row, col), parent_asset_item.clone());
1942b942a51SR0ronoa 
19549182ea7SR0ronoa         // 读取目录中的文件列表
19649182ea7SR0ronoa         if let Ok(entries) = fs::read_dir(&self.cur_path) {
19749182ea7SR0ronoa             for entry in entries {
19849182ea7SR0ronoa                 if let Ok(item) = entry {
1992b942a51SR0ronoa                     let is_dir = if let Ok(metadata) = item.metadata() {
2002b942a51SR0ronoa                         metadata.is_dir()
2012b942a51SR0ronoa                     } else {
2022b942a51SR0ronoa                         false
2032b942a51SR0ronoa                     };
2042b942a51SR0ronoa 
205*731cae06SR0ronoa                     let asset_item = AssetItemGrid::new(item.file_name().to_str().unwrap(), is_dir);
2061bee64b6SR0ronoa                     let (row, col) = self.asset_grid.add_element(&asset_item);
2078a41b76cSR0ronoa                     self.items.insert((row, col), asset_item.clone());
20849182ea7SR0ronoa                 }
20949182ea7SR0ronoa             }
2108a41b76cSR0ronoa         } else {
2118a41b76cSR0ronoa             println!(
2128a41b76cSR0ronoa                 "[Error] AssetManager failed to read dir {:?}",
2138a41b76cSR0ronoa                 self.cur_path
2148a41b76cSR0ronoa             );
21549182ea7SR0ronoa         }
21649182ea7SR0ronoa 
2178a41b76cSR0ronoa         let grid = self.asset_grid.clone();
2188a41b76cSR0ronoa         if let Some(widget) = grid.elements.borrow().get(&(0, 0)) {
21949182ea7SR0ronoa             grid.focused_id.set(Some((0, 0)));
22049182ea7SR0ronoa             grid.focus(widget);
22149182ea7SR0ronoa         }
2228a41b76cSR0ronoa 
2231bee64b6SR0ronoa         if self.init_show == true {
2241bee64b6SR0ronoa             self.init_show = false
2251bee64b6SR0ronoa         } else {
2261bee64b6SR0ronoa             self.loading_panel.draw();
2271bee64b6SR0ronoa         }
2288a41b76cSR0ronoa         self.panel.draw();
22949182ea7SR0ronoa     }
23049182ea7SR0ronoa 
refresh_list(&mut self)231*731cae06SR0ronoa     pub fn refresh_list(&mut self) {
232*731cae06SR0ronoa         self.items.clear();
233*731cae06SR0ronoa 
234*731cae06SR0ronoa         // 父目录
235*731cae06SR0ronoa         // let parent_asset_item = AssetItem_List::new("..", true);
236*731cae06SR0ronoa         // let _index= self.asset_list.add_element(&parent_asset_item);
237*731cae06SR0ronoa 
238*731cae06SR0ronoa         // 读取目录中的文件列表
239*731cae06SR0ronoa         if let Ok(entries) = fs::read_dir(&self.cur_path) {
240*731cae06SR0ronoa             for entry in entries {
241*731cae06SR0ronoa                 if let Ok(item) = entry {
242*731cae06SR0ronoa                     let is_dir = if let Ok(metadata) = item.metadata() {
243*731cae06SR0ronoa                         metadata.is_dir()
244*731cae06SR0ronoa                     } else {
245*731cae06SR0ronoa                         false
246*731cae06SR0ronoa                     };
247*731cae06SR0ronoa 
248*731cae06SR0ronoa                     let asset_item = AssetItemList::new(item.file_name().to_str().unwrap(), is_dir);
249*731cae06SR0ronoa                     let _index = self.asset_list.add_element(&asset_item);
250*731cae06SR0ronoa                 }
251*731cae06SR0ronoa             }
252*731cae06SR0ronoa         } else {
253*731cae06SR0ronoa             println!(
254*731cae06SR0ronoa                 "[Error] AssetManager failed to read dir {:?}",
255*731cae06SR0ronoa                 self.cur_path
256*731cae06SR0ronoa             );
257*731cae06SR0ronoa         }
258*731cae06SR0ronoa 
259*731cae06SR0ronoa         if self.init_show == true {
260*731cae06SR0ronoa             self.init_show = false
261*731cae06SR0ronoa         } else {
262*731cae06SR0ronoa             self.loading_panel.draw();
263*731cae06SR0ronoa         }
264*731cae06SR0ronoa         self.panel.draw();
265*731cae06SR0ronoa     }
266*731cae06SR0ronoa 
exec(&mut self)2678a41b76cSR0ronoa     pub fn exec(&mut self) {
2688a41b76cSR0ronoa         self.panel.exec();
26949182ea7SR0ronoa     }
27049182ea7SR0ronoa }
271