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