column.rs (6141B)
1 use crate::route::{Route, Router}; 2 use crate::timeline::{Timeline, TimelineId}; 3 use indexmap::IndexMap; 4 use std::iter::Iterator; 5 use std::sync::atomic::{AtomicU32, Ordering}; 6 use tracing::warn; 7 8 #[derive(Clone)] 9 pub struct Column { 10 router: Router<Route>, 11 } 12 13 impl Column { 14 pub fn new(routes: Vec<Route>) -> Self { 15 let router = Router::new(routes); 16 Column { router } 17 } 18 19 pub fn router(&self) -> &Router<Route> { 20 &self.router 21 } 22 23 pub fn router_mut(&mut self) -> &mut Router<Route> { 24 &mut self.router 25 } 26 } 27 28 #[derive(Default)] 29 pub struct Columns { 30 /// Columns are simply routers into settings, timelines, etc 31 columns: IndexMap<u32, Column>, 32 33 /// Timeline state is not tied to routing logic separately, so that 34 /// different columns can navigate to and from settings to timelines, 35 /// etc. 36 pub timelines: IndexMap<u32, Timeline>, 37 38 /// The selected column for key navigation 39 selected: i32, 40 } 41 static UIDS: AtomicU32 = AtomicU32::new(0); 42 43 impl Columns { 44 pub fn new() -> Self { 45 Columns::default() 46 } 47 48 pub fn add_new_timeline_column(&mut self, timeline: Timeline) { 49 let id = Self::get_new_id(); 50 let routes = vec![Route::timeline(timeline.id)]; 51 self.timelines.insert(id, timeline); 52 self.columns.insert(id, Column::new(routes)); 53 } 54 55 pub fn add_timeline_to_column(&mut self, col: usize, timeline: Timeline) { 56 let col_id = self.get_column_id_at_index(col); 57 self.column_mut(col) 58 .router_mut() 59 .route_to_replaced(Route::timeline(timeline.id)); 60 self.timelines.insert(col_id, timeline); 61 } 62 63 pub fn new_column_picker(&mut self) { 64 self.add_column(Column::new(vec![Route::AddColumn( 65 crate::ui::add_column::AddColumnRoute::Base, 66 )])); 67 } 68 69 pub fn insert_intermediary_routes(&mut self, intermediary_routes: Vec<IntermediaryRoute>) { 70 let id = Self::get_new_id(); 71 72 let routes = intermediary_routes 73 .into_iter() 74 .map(|r| match r { 75 IntermediaryRoute::Timeline(timeline) => { 76 let route = Route::timeline(timeline.id); 77 self.timelines.insert(id, timeline); 78 route 79 } 80 IntermediaryRoute::Route(route) => route, 81 }) 82 .collect(); 83 84 self.columns.insert(id, Column::new(routes)); 85 } 86 87 fn get_new_id() -> u32 { 88 UIDS.fetch_add(1, Ordering::Relaxed) 89 } 90 91 pub fn add_column_at(&mut self, column: Column, index: u32) { 92 self.columns.insert(index, column); 93 } 94 95 pub fn add_column(&mut self, column: Column) { 96 self.columns.insert(Self::get_new_id(), column); 97 } 98 99 pub fn columns_mut(&mut self) -> Vec<&mut Column> { 100 self.columns.values_mut().collect() 101 } 102 103 pub fn num_columns(&self) -> usize { 104 self.columns.len() 105 } 106 107 // Get the first router in the columns if there are columns present. 108 // Otherwise, create a new column picker and return the router 109 pub fn get_first_router(&mut self) -> &mut Router<Route> { 110 if self.columns.is_empty() { 111 self.new_column_picker(); 112 } 113 self.columns 114 .get_index_mut(0) 115 .expect("There should be at least one column") 116 .1 117 .router_mut() 118 } 119 120 pub fn timeline_mut(&mut self, timeline_ind: usize) -> &mut Timeline { 121 self.timelines 122 .get_index_mut(timeline_ind) 123 .expect("expected index to be in bounds") 124 .1 125 } 126 127 pub fn column(&self, ind: usize) -> &Column { 128 self.columns 129 .get_index(ind) 130 .expect("Expected index to be in bounds") 131 .1 132 } 133 134 pub fn columns(&self) -> Vec<&Column> { 135 self.columns.values().collect() 136 } 137 138 pub fn get_column_id_at_index(&self, ind: usize) -> u32 { 139 *self 140 .columns 141 .get_index(ind) 142 .expect("expected index to be within bounds") 143 .0 144 } 145 146 pub fn selected(&mut self) -> &mut Column { 147 self.columns 148 .get_index_mut(self.selected as usize) 149 .expect("Expected selected index to be in bounds") 150 .1 151 } 152 153 pub fn timelines_mut(&mut self) -> Vec<&mut Timeline> { 154 self.timelines.values_mut().collect() 155 } 156 157 pub fn timelines(&self) -> Vec<&Timeline> { 158 self.timelines.values().collect() 159 } 160 161 pub fn find_timeline_mut(&mut self, id: TimelineId) -> Option<&mut Timeline> { 162 self.timelines_mut().into_iter().find(|tl| tl.id == id) 163 } 164 165 pub fn find_timeline(&self, id: TimelineId) -> Option<&Timeline> { 166 self.timelines().into_iter().find(|tl| tl.id == id) 167 } 168 169 pub fn column_mut(&mut self, ind: usize) -> &mut Column { 170 self.columns 171 .get_index_mut(ind) 172 .expect("Expected index to be in bounds") 173 .1 174 } 175 176 pub fn find_timeline_for_column_index(&self, ind: usize) -> Option<&Timeline> { 177 let col_id = self.get_column_id_at_index(ind); 178 self.timelines.get(&col_id) 179 } 180 181 pub fn select_down(&mut self) { 182 warn!("todo: implement select_down"); 183 } 184 185 pub fn select_up(&mut self) { 186 warn!("todo: implement select_up"); 187 } 188 189 pub fn select_left(&mut self) { 190 if self.selected - 1 < 0 { 191 return; 192 } 193 self.selected -= 1; 194 } 195 196 pub fn select_right(&mut self) { 197 if self.selected + 1 >= self.columns.len() as i32 { 198 return; 199 } 200 self.selected += 1; 201 } 202 203 pub fn delete_column(&mut self, index: usize) { 204 if let Some((key, _)) = self.columns.get_index_mut(index) { 205 self.timelines.shift_remove(key); 206 } 207 208 self.columns.shift_remove_index(index); 209 210 if self.columns.is_empty() { 211 self.new_column_picker(); 212 } 213 } 214 } 215 216 pub enum IntermediaryRoute { 217 Timeline(Timeline), 218 Route(Route), 219 } 220 221 pub enum ColumnsAction { 222 // Switch(usize), TODO: could use for keyboard selection 223 Remove(usize), 224 }