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