diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fail.rs | 16 | ||||
-rw-r--r-- | src/file_browser.rs | 340 | ||||
-rw-r--r-- | src/files.rs | 21 | ||||
-rw-r--r-- | src/hbox.rs | 91 | ||||
-rw-r--r-- | src/miller_columns.rs | 86 | ||||
-rw-r--r-- | src/minibuffer.rs | 2 | ||||
-rw-r--r-- | src/preview.rs | 72 | ||||
-rw-r--r-- | src/proclist.rs | 154 | ||||
-rw-r--r-- | src/tabview.rs | 3 | ||||
-rw-r--r-- | src/widget.rs | 21 |
10 files changed, 504 insertions, 302 deletions
diff --git a/src/fail.rs b/src/fail.rs index a6f8abe..2c01885 100644 --- a/src/fail.rs +++ b/src/fail.rs @@ -45,13 +45,27 @@ pub enum HError { #[fail(display = "No header for widget")] NoHeaderError, #[fail(display = "You wanted this!")] - Quit + Quit, + #[fail(display = "HBox ratio mismatch: {} widgets, ratio is {:?}", wnum, ratio)] + HBoxWrongRatioError{ wnum: usize, ratio: Vec<usize> }, + #[fail(display = "Got wrong widget: {}! Wanted: {}", got, wanted)] + WrongWidgetError{got: String, wanted: String}, } impl HError { pub fn quit() -> HResult<()> { Err(HError::Quit) } + pub fn wrong_ratio<T>(wnum: usize, ratio: Vec<usize>) -> HResult<T> { + Err(HError::HBoxWrongRatioError{ wnum: wnum, ratio: ratio }) + } + pub fn no_widget<T>() -> HResult<T> { + Err(HError::NoWidgetError(Backtrace::new())) + } + pub fn wrong_widget<T>(got: &str, wanted: &str) -> HResult<T> { + Err(HError::WrongWidgetError{ got: got.to_string(), + wanted: wanted.to_string()}) + } } pub trait ErrorLog where Self: Sized { diff --git a/src/file_browser.rs b/src/file_browser.rs index 37a836c..fb8fea2 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -6,22 +6,55 @@ use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::time::Duration; use std::path::PathBuf; +use std::collections::HashMap; use crate::files::{File, Files}; use crate::listview::ListView; use crate::miller_columns::MillerColumns; use crate::widget::Widget; use crate::tabview::{TabView, Tabbable}; -use crate::preview::WillBeWidget; +use crate::preview::{Previewer, WillBeWidget}; use crate::fail::{HResult, HError, ErrorLog}; use crate::widget::{Events, WidgetCore}; use crate::proclist::ProcView; +#[derive(PartialEq)] +pub enum FileBrowserWidgets { + FileList(WillBeWidget<ListView<Files>>), + Previewer(Previewer), +} +impl Widget for FileBrowserWidgets { + fn get_core(&self) -> HResult<&WidgetCore> { + match self { + FileBrowserWidgets::FileList(widget) => widget.get_core(), + FileBrowserWidgets::Previewer(widget) => widget.get_core() + } + } + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + match self { + FileBrowserWidgets::FileList(widget) => widget.get_core_mut(), + FileBrowserWidgets::Previewer(widget) => widget.get_core_mut() + } + } + fn refresh(&mut self) -> HResult<()> { + match self { + FileBrowserWidgets::FileList(widget) => widget.refresh(), + FileBrowserWidgets::Previewer(widget) => widget.refresh() + } + } + fn get_drawlist(&self) -> HResult<String> { + match self { + FileBrowserWidgets::FileList(widget) => widget.get_drawlist(), + FileBrowserWidgets::Previewer(widget) => widget.get_drawlist() + } + } +} pub struct FileBrowser { - pub columns: MillerColumns<WillBeWidget<ListView<Files>>>, + pub columns: MillerColumns<FileBrowserWidgets>, pub cwd: File, + selections: HashMap<File, File>, core: WidgetCore, watcher: INotifyWatcher, watches: Vec<PathBuf>, @@ -105,15 +138,17 @@ fn watch_dir(rx: Receiver<DebouncedEvent>, impl FileBrowser { pub fn new_cored(core: &WidgetCore) -> HResult<FileBrowser> { let cwd = std::env::current_dir().unwrap(); - let coords = core.coordinates.clone(); - let core_m = core.clone(); - let core_l = core.clone(); + let mut core_m = core.clone(); + let mut core_l = core.clone(); + let mut core_p = core.clone(); let mut miller = MillerColumns::new(core); - miller.set_coordinates(&coords)?; - + miller.set_ratios(vec![20,30,49]); + let list_coords = miller.calculate_coordinates()?; - let (left_coords, main_coords, _) = miller.calculate_coordinates(); + core_l.coordinates = list_coords[0].clone(); + core_m.coordinates = list_coords[1].clone(); + core_p.coordinates = list_coords[2].clone(); let main_path = cwd.ancestors() .take(1) @@ -125,7 +160,6 @@ impl FileBrowser { let main_widget = WillBeWidget::new(&core, Box::new(move |_| { let mut list = ListView::new(&core_m, Files::new_from_path(&main_path)?); - list.set_coordinates(&main_coords).log(); list.animate_slide_up().log(); Ok(list) })); @@ -134,14 +168,18 @@ impl FileBrowser { let left_widget = WillBeWidget::new(&core, Box::new(move |_| { let mut list = ListView::new(&core_l, Files::new_from_path(&left_path)?); - list.set_coordinates(&left_coords).log(); list.animate_slide_up().log(); Ok(list) })); + let left_widget = FileBrowserWidgets::FileList(left_widget); miller.push_widget(left_widget); } - miller.push_widget(main_widget); + let previewer = Previewer::new(&core_p); + + miller.push_widget(FileBrowserWidgets::FileList(main_widget)); + miller.push_widget(FileBrowserWidgets::Previewer(previewer)); + miller.refresh().log(); let cwd = File::new_from_path(&cwd).unwrap(); @@ -151,11 +189,13 @@ impl FileBrowser { let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap(); watch_dir(rx_watch, dir_events.clone(), core.get_sender()); - let mut proc_view = ProcView::new(core); - proc_view.set_coordinates(&coords).log(); + let proc_view = ProcView::new(core); + + Ok(FileBrowser { columns: miller, cwd: cwd, + selections: HashMap::new(), core: core.clone(), watcher: watcher, watches: vec![], @@ -165,112 +205,138 @@ impl FileBrowser { pub fn enter_dir(&mut self) -> HResult<()> { let file = self.selected_file()?; - let (_, coords, _) = self.columns.calculate_coordinates(); - let core = self.core.clone(); - - match file.read_dir() { - Ok(files) => { - std::env::set_current_dir(&file.path).unwrap(); - self.cwd = file.clone(); - let view = WillBeWidget::new(&core.clone(), Box::new(move |_| { - let files = files.clone(); - let mut list = ListView::new(&core, files); - list.set_coordinates(&coords).log(); - list.animate_slide_up().log(); - Ok(list) - })); - self.columns.push_widget(view); - }, - _ => { - let status = std::process::Command::new("rifle") - .args(file.path.file_name()) - .status(); - - match status { - Ok(status) => - self.show_status(&format!("\"{}\" exited with {}", - "rifle", status)).log(), - Err(err) => - self.show_status(&format!("Can't run this \"{}\": {}", - "rifle", err)).log() - - }; + + if file.is_dir() { + self.main_widget_goto(&file).log(); + } else { + let status = std::process::Command::new("rifle") + .args(file.path.file_name()) + .status(); + + match status { + Ok(status) => + self.show_status(&format!("\"{}\" exited with {}", + "rifle", status)).log(), + Err(err) => + self.show_status(&format!("Can't run this \"{}\": {}", + "rifle", err)).log() } } Ok(()) } - pub fn go_back(&mut self) -> HResult<()> { - self.columns.pop_widget(); + pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> { + self.cwd = dir.clone(); + let dir = dir.clone(); + let selected_file = self.get_selection(&dir).ok().cloned(); + + let main_widget = self.main_widget_mut()?; + main_widget.change_to(Box::new(move |stale, core| { + let path = dir.path(); + let files = Files::new_from_path_cancellable(&path, stale)?; + + let mut list = ListView::new(&core, files); + + if let Some(file) = &selected_file { + list.select_file(file); + } + Ok(list) + })).log(); + + if let Ok(grand_parent) = self.cwd()?.parent_as_file() { + self.left_widget_goto(&grand_parent).log(); + } else { + self.left_widget_mut()?.set_stale().log(); + } + + Ok(()) + } + + pub fn left_widget_goto(&mut self, dir: &File) -> HResult<()> { + let dir = dir.clone(); + + let left_widget = self.left_widget_mut()?; + left_widget.change_to(Box::new(move |stale, core| { + let path = dir.path(); + let files = Files::new_from_path_cancellable(&path, stale)?; + let list = ListView::new(&core, files); + Ok(list) + }))?; + Ok(()) + } - if let Ok(new_cwd) = self.cwd.grand_parent_as_file() { - self.cwd = new_cwd; + pub fn go_back(&mut self) -> HResult<()> { + if let Ok(new_cwd) = self.cwd.parent_as_file() { + self.main_widget_goto(&new_cwd).log(); } self.refresh() } pub fn update_preview(&mut self) -> HResult<()> { + if !self.main_widget()?.ready() { return Ok(()) } let file = self.selected_file()?.clone(); - let preview = &mut self.columns.preview; - preview.set_file(&file); + let selection = self.get_selection(&file).ok().cloned(); + let preview = self.preview_widget_mut()?; + preview.set_file(&file, selection); Ok(()) } - pub fn fix_selection(&mut self) -> HResult<()> { - let cwd = self.cwd()?; - (*self.left_widget()?.lock()?).as_mut()?.select_file(&cwd); + pub fn set_left_selection(&mut self) -> HResult<()> { + if !self.left_widget()?.ready() { return Ok(()) } + + let parent = self.cwd()?.parent_as_file(); + + let left_selection = self.get_selection(&parent?)?; + self.left_widget()?.widget()?.lock()?.as_mut()?.select_file(&left_selection); + Ok(()) } - pub fn fix_left(&mut self) -> HResult<()> { - if self.left_widget().is_err() { - let cwd = self.selected_file()?.clone(); - if let Ok(grand_parent) = cwd.grand_parent_as_file() { - let (coords, _, _) = self.columns.calculate_coordinates(); - let core = self.core.clone(); - let left_view = WillBeWidget::new(&self.core, Box::new(move |_| { - let mut view - = ListView::new(&core, - Files::new_from_path(&grand_parent.path)?); - view.set_coordinates(&coords).log(); - Ok(view) - })); - self.columns.prepend_widget(left_view); - } + pub fn get_selection(&self, dir: &File) -> HResult<&File> { + Ok(self.selections.get(dir)?) + } + + pub fn save_selection(&mut self) -> HResult<()> { + let cwd = self.cwd()?.clone(); + if let Ok(main_selection) = self.selected_file() { + self.selections.insert(cwd.clone(), main_selection); + } + if let Ok(left_dir) = self.cwd()?.parent_as_file() { + self.selections.insert(left_dir, cwd); } Ok(()) } - pub fn cwd(&self) -> HResult<File> { - let widget = self.columns.get_main_widget()?.widget()?; - let cwd = (*widget.lock()?).as_ref()?.content.directory.clone(); - Ok(cwd) + pub fn cwd(&self) -> HResult<&File> { + Ok(&self.cwd) } pub fn set_cwd(&mut self) -> HResult<()> { let cwd = self.cwd()?; std::env::set_current_dir(&cwd.path)?; - self.cwd = cwd; Ok(()) } pub fn left_dir(&self) -> HResult<File> { - let widget = self.columns.get_left_widget()?.widget()?; - let dir = (*widget.lock()?).as_ref()?.content.directory.clone(); + let widget = self.left_widget()?.widget()?; + let dir = widget.lock()?.as_ref()?.content.directory.clone(); Ok(dir) } fn update_watches(&mut self) -> HResult<()> { + if !self.left_widget()?.ready() || !self.main_widget()?.ready() { + return Ok(()) + } let watched_dirs = self.watches.clone(); - let cwd = self.cwd()?; + let cwd = self.cwd()?.clone(); let left_dir = self.left_dir()?; let preview_dir = self.selected_file().ok().map(|f| f.path); for watched_dir in watched_dirs.iter() { if watched_dir != &cwd.path && watched_dir != &left_dir.path && Some(watched_dir.clone()) != preview_dir { - self.watcher.unwatch(&watched_dir).unwrap(); + self.watcher.unwatch(&watched_dir).ok(); self.watches.remove_item(&watched_dir); } } @@ -292,51 +358,85 @@ impl FileBrowser { } fn handle_dir_events(&mut self) -> HResult<()> { - let mut dir_events = self.dir_events.lock()?; - for event in dir_events.iter() { - let main_widget = self.columns.get_main_widget()?.widget()?; - let main_files = &mut (*main_widget.lock()?); - let main_files = &mut main_files.as_mut()?.content; - let main_result = main_files.handle_event(event); - - let left_widget = self.columns.get_left_widget()?.widget()?; - let left_files = &mut (*left_widget.lock()?); - let left_files = &mut left_files.as_mut()?.content; - let left_result = left_files.handle_event(event); + let dir_events = self.dir_events.clone(); + for event in dir_events.lock()?.iter() { + let main_widget = self.main_widget()?.widget()?; + let mut main_widget = main_widget.lock()?; + let main_result = main_widget.as_mut()?.content.handle_event(event); + + let left_widget = self.left_widget()?.widget()?; + let mut left_files = left_widget.lock()?; + let left_result = left_files.as_mut()?.content.handle_event(event); match main_result { Err(HError::WrongDirectoryError { .. }) => { match left_result { Err(HError::WrongDirectoryError { .. }) => { - let preview = &mut self.columns.preview; + let preview = self.preview_widget_mut()?; preview.reload(); }, _ => {} } }, _ => {} } } - dir_events.clear(); + dir_events.lock()?.clear(); Ok(()) } pub fn selected_file(&self) -> HResult<File> { - let widget = self.main_widget()?; + let widget = self.main_widget()?.widget()?; let file = widget.lock()?.as_ref()?.selected_file().clone(); Ok(file) } - pub fn main_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> { - let widget = self.columns.get_main_widget()?.widget()?; - Ok(widget) + pub fn main_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_main_widget()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn main_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_main_widget_mut()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn left_widget(&self) -> HResult<&WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_left_widget()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn left_widget_mut(&mut self) -> HResult<&mut WillBeWidget<ListView<Files>>> { + let widget = match self.columns.get_left_widget_mut()? { + FileBrowserWidgets::FileList(filelist) => Ok(filelist), + _ => { return HError::wrong_widget("previewer", "filelist"); } + }; + widget + } + + pub fn preview_widget(&self) -> HResult<&Previewer> { + match self.columns.get_right_widget()? { + FileBrowserWidgets::Previewer(previewer) => Ok(previewer), + _ => { return HError::wrong_widget("filelist", "previewer"); } + } } - pub fn left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> { - let widget = self.columns.get_left_widget()?.widget()?; - Ok(widget) + pub fn preview_widget_mut(&mut self) -> HResult<&mut Previewer> { + match self.columns.get_right_widget_mut()? { + FileBrowserWidgets::Previewer(previewer) => Ok(previewer), + _ => { return HError::wrong_widget("filelist", "previewer"); } + } } pub fn quit_with_dir(&self) -> HResult<()> { - let cwd = self.cwd()?.path; + let cwd = self.cwd()?.clone().path; let selected_file = self.selected_file()?; let selected_file = selected_file.path.to_string_lossy(); @@ -362,22 +462,22 @@ impl FileBrowser { self.cwd = cwd; let dir = std::path::PathBuf::from(&dir); let left_dir = std::path::PathBuf::from(&dir); - let (left_coords, main_coords, _) = self.columns.calculate_coordinates(); - let mcore = self.core.clone(); - let lcore = self.core.clone(); + let mcore = self.main_widget()?.get_core()?.clone(); + let lcore = self.left_widget()?.get_core()?.clone();; let middle = WillBeWidget::new(&self.core, Box::new(move |_| { let files = Files::new_from_path(&dir.clone())?; - let mut listview = ListView::new(&mcore, files); - listview.set_coordinates(&main_coords).log(); + let listview = ListView::new(&mcore, files); Ok(listview) })); + let middle = FileBrowserWidgets::FileList(middle); + let left = WillBeWidget::new(&self.core, Box::new(move |_| { let files = Files::new_from_path(&left_dir.parent()?)?; - let mut listview = ListView::new(&lcore, files); - listview.set_coordinates(&left_coords).log(); + let listview = ListView::new(&lcore, files); Ok(listview) })); + let left = FileBrowserWidgets::FileList(left); self.columns.push_widget(left); self.columns.push_widget(middle); }, @@ -388,9 +488,9 @@ impl FileBrowser { fn exec_cmd(&mut self, tab_dirs: Vec<File>) -> HResult<()> { let filename = self.selected_file()?.name.clone(); - let widget = self.main_widget()?; + let widget = self.main_widget()?.widget()?; let widget = widget.lock()?; - let selected_files = (*widget).as_ref()?.content.get_selected(); + let selected_files = widget.as_ref()?.content.get_selected(); let file_names = selected_files.iter().map(|f| f.name.clone()).collect::<Vec<String>>(); @@ -424,6 +524,9 @@ impl Widget for FileBrowser { fn get_core(&self) -> HResult<&WidgetCore> { Ok(&self.core) } + fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> { + Ok(&mut self.core) + } fn render_header(&self) -> HResult<String> { let xsize = self.get_coordinates()?.xsize(); let file = self.selected_file()?; @@ -449,9 +552,9 @@ impl Widget for FileBrowser { let group = file.pretty_group().unwrap_or("NOGROUP".into()); let mtime = file.pretty_mtime().unwrap_or("NOMTIME".into()); - - let selection = (*self.main_widget().as_ref().unwrap().lock()?).as_ref()?.get_selection(); - let file_count = (*self.main_widget()?.lock()?).as_ref()?.content.len(); + let main_widget = self.main_widget()?.widget()?; + let selection = main_widget.lock()?.as_ref().unwrap().get_selection(); + let file_count = main_widget.lock()?.as_ref().unwrap().content.len(); let file_count = format!("{}", file_count); let digits = file_count.len(); let file_count = format!("{:digits$}/{:digits$}", @@ -466,22 +569,23 @@ impl Widget for FileBrowser { } fn refresh(&mut self) -> HResult<()> { //self.proc_view.lock()?.set_coordinates(self.get_coordinates()?); - self.handle_dir_events()?; + self.handle_dir_events().ok(); self.columns.refresh().ok(); - self.fix_left().ok(); - self.fix_selection().ok(); + self.set_left_selection().log(); + self.save_selection().log(); self.set_cwd().ok(); self.update_watches().ok(); self.update_preview().ok(); + self.columns.refresh().ok(); Ok(()) } fn get_drawlist(&self) -> HResult<String> { - if self.columns.get_left_widget().is_err() { - Ok(self.columns.get_clearlist()? + &self.columns.get_drawlist()?) - } else { - Ok(self.columns.get_drawlist()?) - } + let left = self.left_widget()?.get_drawlist()?; + let main = self.main_widget()?.get_drawlist()?; + let prev = self.preview_widget()?.get_drawlist()?; + + Ok(left + &main + &prev) } fn on_key(&mut self, key: Key) -> HResult<()> { @@ -494,7 +598,7 @@ impl Widget for FileBrowser { self.proc_view.lock()?.popup()?; } , - _ => { self.columns.get_main_widget_mut()?.on_key(key)?; }, + _ => { self.main_widget_mut()?.on_key(key)?; }, } self.update_preview()?; Ok(()) diff --git a/src/files.rs b/src/files.rs index fe0dc8b..daabb9e 100644 --- a/src/files.rs +++ b/src/files.rs @@ -3,6 +3,7 @@ use std::ops::Index; use std::os::unix::fs::MetadataExt; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; +use std::hash::{Hash, Hasher}; use lscolors::LsColors; use mime_detective; @@ -294,6 +295,16 @@ impl PartialEq for File { } } +impl Hash for File { + fn hash<H: Hasher>(&self, state: &mut H) { + self.name.hash(state); + self.path.hash(state); + self.selected.hash(state); + } +} + +impl Eq for File {} + #[derive(Debug, Clone)] pub struct File { pub name: String, @@ -403,6 +414,16 @@ impl File { Some(mime.type_().as_str().to_string()) } + + pub fn parent(&self) -> Option<PathBuf> { + Some(self.path.parent()?.to_path_buf()) + } + + pub fn parent_as_file(&self) -> HResult<File> { + let pathbuf = self.parent()?; + File::new_from_path(&pathbuf) + } + pub fn grand_parent(&self) -> Option<PathBuf> { Some(self.path.parent()?.parent()?.to_path_buf()) } diff --git a/src/hbox.rs b/src/hbox.rs index 6a2aa8e..7982333 100644 --- a/src/hbox.rs +++ b/src/hbox.rs @@ -2,12 +2,13 @@ use termion::event::{Event}; use crate::widget::{Widget, WidgetCore}; use crate::coordinates::{Coordinates, Size, Position}; -use crate::fail::{HResult, ErrorLog}; +use crate::fail::{HResult, HError, ErrorLog}; #[derive(PartialEq)] pub struct HBox<T: Widget> { pub core: WidgetCore, pub widgets: Vec<T>, + pub ratios: Option<Vec<usize>>, pub active: Option<usize>, } @@ -16,59 +17,89 @@ impl<T> HBox<T> where T: Widget + PartialEq { pub fn new(core: &WidgetCore) -> HBox<T> { HBox { core: core.clone(), widgets: vec![], + ratios: None, active: None } } - pub fn resize_children(&mut self) { - let coords: Vec<Coordinates> - = self.widgets.iter().map( - |w| - self.calculate_coordinates(w)).collect(); + pub fn resize_children(&mut self) -> HResult<()> { + let len = self.widgets.len(); + if len == 0 { return Ok(()) } + + let coords: Vec<Coordinates> = self.calculate_coordinates()?; + + for (widget, coord) in self.widgets.iter_mut().zip(coords.iter()) { widget.set_coordinates(coord).log(); } + + Ok(()) } - pub fn push_widget(&mut self, widget: T) where T: PartialEq { + pub fn push_widget(&mut self, widget: T) { self.widgets.push(widget); - self.resize_children(); - self.refresh().log(); } pub fn pop_widget(&mut self) -> Option<T> { let widget = self.widgets.pop(); - self.resize_children(); - self.refresh().log(); widget } pub fn prepend_widget(&mut self, widget: T) { self.widgets.insert(0, widget); - self.resize_children(); - self.refresh().log(); } - pub fn calculate_coordinates(&self, widget: &T) - -> Coordinates where T: PartialEq { - let coordinates = self.get_coordinates().unwrap(); - let xsize = coordinates.xsize(); - let ysize = coordinates.ysize(); - let top = coordinates.top().y(); + pub fn set_ratios(&mut self, ratios: Vec<usize>) { + self.ratios = Some(ratios); + } - let pos = self.widgets.iter().position(|w | w == widget).unwrap(); - let num = self.widgets.len(); + pub fn calculate_equal_ratios(&self) -> HResult<Vec<usize>> { + let len = self.widgets.len(); + if len == 0 { return HError::no_widget(); } - let widget_xsize = (xsize / num as u16) + 1; - let widget_xpos = widget_xsize * pos as u16; + let ratios = (0..len).map(|_| 100 / len).collect(); + Ok(ratios) + } - Coordinates { - size: Size((widget_xsize, - ysize)), - position: Position((widget_xpos, - top)) - } + pub fn calculate_coordinates(&self) + -> HResult<Vec<Coordinates>> { + let box_coords = self.get_coordinates()?; + let box_xsize = box_coords.xsize(); + let box_ysize = box_coords.ysize(); + let box_top = box_coords.top().y(); + + let ratios = match &self.ratios { + Some(ratios) => ratios.clone(), + None => self.calculate_equal_ratios()? + }; + + let coords = ratios.iter().fold(Vec::<Coordinates>::new(), |mut coords, ratio| { + let ratio = *ratio as u16; + let len = coords.len(); + let gap = if len == 0 { 0 } else { 1 }; + + let widget_xsize = box_xsize * ratio / 100; + let widget_xpos = if len == 0 { + box_coords.top().x() + } else { + let prev_coords = coords.last().unwrap(); + let prev_xsize = prev_coords.xsize(); + let prev_xpos = prev_coords.position().x(); + + prev_xsize + prev_xpos + gap + }; + + coords.push(Coordinates { + size: Size((widget_xsize, + box_ysize)), + position: Position((widget_xpos, + box_top)) + }); + coords + }); + + Ok(coords) } pub fn active_widget(&self) -> &T { @@ -92,7 +123,7 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq { } fn refresh(&mut self) -> HResult<()> { - self.resize_children(); + self.resize_children().log(); for child in &mut self.widgets { child.refresh()? } diff --git a/src/miller_columns.rs b/src/miller_columns.rs index 3a240cb..ca621e4 100644 --- a/src/miller_columns.rs +++ b/src/miller_columns.rs @@ -1,8 +1,7 @@ use termion::event::Key; use failure::Backtrace; -use crate::coordinates::{Coordinates, Position, Size}; -use crate::preview::Previewer; +use crate::coordinates::{Coordinates}; use crate::widget::{Widget, WidgetCore}; use crate::hbox::HBox; use crate::fail::{HError, HResult, ErrorLog}; @@ -11,11 +10,6 @@ use crate::fail::{HError, HResult, ErrorLog}; pub struct MillerColumns<T> where T: Widget { pub widgets: HBox<T>, pub core: WidgetCore, - // pub left: Option<T>, - // pub main: Option<T>, - //pub preview: AsyncPreviewer, - pub preview: Previewer, - pub ratio: (u16, u16, u16), } impl<T> MillerColumns<T> @@ -26,8 +20,6 @@ where MillerColumns { widgets: HBox::new(core), core: core.clone(), - ratio: (20, 30, 50), - preview: Previewer::new(core) } } @@ -46,64 +38,45 @@ where self.widgets.prepend_widget(widget); } - pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates, Coordinates) { - let coordinates = self.get_coordinates().unwrap(); - let xsize = coordinates.xsize(); - let ysize = coordinates.ysize(); - let top = coordinates.top().y(); - let ratio = self.ratio; - - let left_xsize = xsize * ratio.0 / 100; - let left_size = Size((left_xsize, ysize)); - let left_pos = coordinates.top(); - - let main_xsize = xsize * ratio.1 / 100; - let main_size = Size((main_xsize, ysize)); - let main_pos = Position((left_xsize + 2, top)); - - let preview_xsize = xsize * ratio.2 / 100; - let preview_size = Size((preview_xsize - 1, ysize)); - let preview_pos = Position((left_xsize + main_xsize + 3, top)); - - let left_coords = Coordinates { - size: left_size, - position: left_pos, - }; - - let main_coords = Coordinates { - size: main_size, - position: main_pos, - }; - - let preview_coords = Coordinates { - size: preview_size, - position: preview_pos, - }; + pub fn set_ratios(&mut self, ratios: Vec<usize>) { + self.widgets.set_ratios(ratios); + } - (left_coords, main_coords, preview_coords) + pub fn calculate_coordinates(&self) -> HResult<Vec<Coordinates>> { + self.widgets.calculate_coordinates() } pub fn get_left_widget(&self) -> HResult<&T> { let len = self.widgets.widgets.len(); - if len < 2 { + if len < 3 { return Err(HError::NoWidgetError(Backtrace::new())); } - let widget = self.widgets.widgets.get(len - 2)?; + let widget = self.widgets.widgets.get(len - 3)?; Ok(widget) } pub fn get_left_widget_mut(&mut self) -> HResult<&mut T> { let len = self.widgets.widgets.len(); - if len < 2 { + if len < 3 { return Err(HError::NoWidgetError(Backtrace::new())); } - let widget = self.widgets.widgets.get_mut(len - 2)?; + let widget = self.widgets.widgets.get_mut(len - 3)?; Ok(widget) } pub fn get_main_widget(&self) -> HResult<&T> { - let widget = self.widgets.widgets.last()?; + let len = self.widgets.widgets.len(); + let widget = self.widgets.widgets.get(len-2)?; Ok(widget) } pub fn get_main_widget_mut(&mut self) -> HResult<&mut T> { + let len = self.widgets.widgets.len(); + let widget = self.widgets.widgets.get_mut(len-2)?; + Ok(widget) + } + pub fn get_right_widget(&self) -> HResult<&T> { + let widget = self.widgets.widgets.last()?; + Ok(widget) + } + pub fn get_right_widget_mut(&mut self) -> HResult<&mut T> { let widget = self.widgets.widgets.last_mut()?; Ok(widget) } @@ -121,29 +94,18 @@ where Ok(&mut self.core) } fn refresh(&mut self) -> HResult<()> { - let (left_coords, main_coords, preview_coords) = self.calculate_coordinates(); - - if let Ok(left_widget) = self.get_left_widget_mut() { - left_widget.set_coordinates(&left_coords).log(); - } - - if let Ok(main_widget) = self.get_main_widget_mut( |