notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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 }