use enum to allow multiple widget types in hbox

This commit is contained in:
rabite 2019-03-09 11:06:13 +01:00
parent 6e02ef6486
commit 5d45653901
10 changed files with 501 additions and 299 deletions

View File

@ -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 {

View File

@ -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();
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()
};
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();
if let Ok(new_cwd) = self.cwd.grand_parent_as_file() {
self.cwd = new_cwd;
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(())
}
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 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.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 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 left_widget(&self) -> HResult<Arc<Mutex<Option<ListView<Files>>>>> {
let widget = self.columns.get_left_widget()?.widget()?;
Ok(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 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(())

View File

@ -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())
}

View File

@ -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()?
}

View File

@ -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;
pub fn set_ratios(&mut self, ratios: Vec<usize>) {
self.widgets.set_ratios(ratios);
}
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,
};
(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() {
main_widget.set_coordinates(&main_coords).log();
}
let preview_widget = &mut self.preview;
preview_widget.set_coordinates(&preview_coords)?;
self.widgets.refresh().log();
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
let left_widget = self.get_left_widget()?;
let main_widget = self.get_main_widget()?;
let preview = self.preview.get_drawlist()?;
let right_widget = self.get_right_widget()?;
Ok(format!("{}{}{}",
main_widget.get_drawlist()?,
left_widget.get_drawlist()?,
preview))
right_widget.get_drawlist()?))
}
fn on_key(&mut self, key: Key) -> HResult<()> {

View File

@ -1,5 +1,3 @@
use std::io::Write;
use termion::event::Key;
use crate::coordinates::{Coordinates};

View File

@ -11,6 +11,7 @@ use crate::fail::{HResult, HError, ErrorLog};
type HClosure<T> = Box<Fn(Arc<Mutex<bool>>) -> Result<T, HError> + Send>;
type HCClosure<T> = Box<Fn(Arc<Mutex<bool>>, WidgetCore) -> Result<T, HError> + Send>;
type WidgetO = Box<dyn Widget + Send>;
lazy_static! {
@ -111,7 +112,7 @@ impl<W: Widget + Send + 'static> PartialEq for WillBeWidget<W> {
}
}
pub struct WillBeWidget<T: Widget + Send> {
pub struct WillBeWidget<T: Widget + Send + 'static> {
willbe: WillBe<T>,
core: WidgetCore
}
@ -129,6 +130,24 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
core: core.clone()
}
}
pub fn change_to(&mut self, closure: HCClosure<T>) -> HResult<()> {
self.set_stale().log();
let sender = self.get_core()?.get_sender();
let core = self.get_core()?.clone();
let mut willbe = WillBe::new_become(Box::new(move |stale| {
let core = core.clone();
closure(stale, core)
}));
willbe.on_ready(Box::new(move |_| {
sender.send(crate::widget::Events::WidgetReady)?;
Ok(())
}))?;
self.willbe = willbe;
Ok(())
}
pub fn set_stale(&mut self) -> HResult<()> {
self.willbe.set_stale()
}
@ -136,6 +155,12 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
self.willbe.check()?;
Ok(self.willbe.thing.clone())
}
pub fn ready(&self) -> bool {
match self.willbe.check() {
Ok(_) => true,
_ => false
}
}
}
// impl<T: Widget + Send> WillBeWidget<T> {
@ -157,11 +182,13 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
let widget = self.widget()?;
let mut widget = widget.lock()?;
let widget = widget.as_mut()?;
widget.set_coordinates(self.get_coordinates()?).log();
widget.refresh()
if let Ok(widget) = self.widget() {
let mut widget = widget.lock()?;
let widget = widget.as_mut()?;
widget.set_coordinates(self.get_coordinates()?).log();
widget.refresh().log();
}
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
if self.willbe.check().is_err() {
@ -170,6 +197,9 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
let pos = crate::term::goto_xy(xpos, ypos);
return Ok(clear + &pos + "...")
}
if is_stale(&self.willbe.stale)? {
return self.get_clearlist()
}
let widget = self.widget()?;
let widget = widget.lock()?;
let widget = widget.as_ref()?;
@ -199,7 +229,8 @@ impl PartialEq for Previewer {
pub struct Previewer {
widget: WillBeWidget<Box<dyn Widget + Send>>,
core: WidgetCore,
file: Option<File>
file: Option<File>,
selection: Option<File>
}
@ -212,7 +243,8 @@ impl Previewer {
}));
Previewer { widget: willbe,
core: core.clone(),
file: None}
file: None,
selection: None }
}
fn become_preview(&mut self,
@ -222,9 +254,10 @@ impl Previewer {
self.widget.set_coordinates(&coordinates).ok();
}
pub fn set_file(&mut self, file: &File) {
pub fn set_file(&mut self, file: &File, selection: Option<File>) {
if Some(file) == self.file.as_ref() { return }
self.file = Some(file.clone());
self.selection = selection.clone();
let coordinates = self.get_coordinates().unwrap().clone();
let file = file.clone();
@ -236,9 +269,13 @@ impl Previewer {
kill_proc().unwrap();
let file = file.clone();
let selection = selection.clone();
if file.kind == Kind::Directory {
let preview = Previewer::preview_dir(&file, &core, stale.clone());
let preview = Previewer::preview_dir(&file,
selection,
&core,
stale.clone());
return preview;
}
@ -261,7 +298,7 @@ impl Previewer {
pub fn reload(&mut self) {
if let Some(file) = self.file.clone() {
self.file = None;
self.set_file(&file);
self.set_file(&file, self.selection.clone());
}
}
@ -269,15 +306,21 @@ impl Previewer {
Err(HError::PreviewFailed { file: file.name.clone() })
}
fn preview_dir(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
fn preview_dir(file: &File,
selection: Option<File>,
core: &WidgetCore,
stale: Arc<Mutex<bool>>)
-> Result<WidgetO, HError> {
let files = Files::new_from_path_cancellable(&file.path,
stale.clone())?;
let len = files.len();
if len == 0 || is_stale(&stale)? { return Previewer::preview_failed(&file) }
let mut file_list = ListView::new(&core, files);
if let Some(selection) = selection {
file_list.select_file(&selection);
}
file_list.set_coordinates(&core.coordinates)?;
file_list.refresh()?;
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
@ -529,6 +572,9 @@ impl<T> Widget for Box<T> where T: Widget + ?Sized {
fn get_core(&self) -> HResult<&WidgetCore> {
Ok((**self).get_core()?)
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok((**self).get_core_mut()?)
}
fn render_header(&self) -> HResult<String> {
(**self).render_header()
}

View File

@ -7,10 +7,10 @@ use std::io::{BufRead, BufReader};
use termion::event::Key;
use unicode_width::UnicodeWidthStr;
use crate::coordinates::{Coordinates, Size, Position};
use crate::listview::{Listable, ListView};
use crate::textview::TextView;
use crate::widget::{Widget, Events, WidgetCore};
use crate::hbox::HBox;
use crate::preview::WillBeWidget;
use crate::fail::{HResult, HError, ErrorLog};
use crate::term;
@ -26,6 +26,12 @@ struct Process {
}
impl PartialEq for Process {
fn eq(&self, other: &Process) -> bool {
self.cmd == other.cmd
}
}
impl Process {
fn read_proc(&mut self) -> HResult<()> {
let handle = self.handle.clone();
@ -46,7 +52,8 @@ impl Process {
sender.send(Events::WidgetReady).unwrap();
}
Err(err) => {
dbg!(err);
let err: HResult<()> = Err(HError::from(err));
err.log();
break;
}
}
@ -143,96 +150,117 @@ impl ListView<Vec<Process>> {
}
}
#[derive(PartialEq)]
enum ProcViewWidgets {
List(ListView<Vec<Process>>),
TextView(WillBeWidget<TextView>),
}
impl Widget for ProcViewWidgets {
fn get_core(&self) -> HResult<&WidgetCore> {
match self {
ProcViewWidgets::List(widget) => widget.get_core(),
ProcViewWidgets::TextView(widget) => widget.get_core()
}
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
match self {
ProcViewWidgets::List(widget) => widget.get_core_mut(),
ProcViewWidgets::TextView(widget) => widget.get_core_mut()
}
}
fn refresh(&mut self) -> HResult<()> {
match self {
ProcViewWidgets::List(widget) => widget.refresh(),
ProcViewWidgets::TextView(widget) => widget.refresh()
}
}
fn get_drawlist(&self) -> HResult<String> {
match self {
ProcViewWidgets::List(widget) => widget.get_drawlist(),
ProcViewWidgets::TextView(widget) => widget.get_drawlist()
}
}
}
pub struct ProcView {
core: WidgetCore,
proc_list: ListView<Vec<Process>>,
textview: WillBeWidget<TextView>,
hbox: HBox<ProcViewWidgets>,
viewing: Option<usize>
}
impl HBox<ProcViewWidgets> {
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
match &mut self.widgets[0] {
ProcViewWidgets::List(listview) => listview,
_ => unreachable!()
}
}
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
match &mut self.widgets[1] {
ProcViewWidgets::TextView(textview) => textview,
_ => unreachable!()
}
}
}
impl ProcView {
pub fn new(core: &WidgetCore) -> ProcView {
let tcore = core.clone();
let listview = ListView::new(&core, vec![]);
let textview = Box::new(move |_| Ok(TextView::new_blank(&tcore)));
let textview = WillBeWidget::new(&core, textview);
let mut hbox = HBox::new(&core);
hbox.push_widget(ProcViewWidgets::List(listview));
hbox.push_widget(ProcViewWidgets::TextView(textview));
hbox.set_ratios(vec![33, 66]);
hbox.refresh().log();
ProcView {
core: core.clone(),
proc_list: ListView::new(&core, vec![]),
textview: WillBeWidget::new(&core, textview),
hbox: hbox,
viewing: None
}
}
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
self.hbox.get_listview()
}
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
self.hbox.get_textview()
}
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
self.proc_list.run_proc(cmd)?;
self.get_listview().run_proc(cmd)?;
Ok(())
}
pub fn remove_proc(&mut self) -> HResult<()> {
let (_, coords) = self.calculate_coordinates();
let coords2 = coords.clone();
let mut core = self.core.clone();
core.coordinates = coords;
self.proc_list.remove_proc()?;
self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| {
self.get_listview().remove_proc()?;
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
textview.refresh().log();
textview.animate_slide_up().log();
Ok(textview)
}));
self.textview.set_coordinates(&coords2).log();
})).log();
Ok(())
}
fn show_output(&mut self) -> HResult<()> {
if Some(self.proc_list.get_selection()) == self.viewing {
if Some(self.get_listview().get_selection()) == self.viewing {
return Ok(());
}
let output = self.proc_list.selected_proc()?.output.lock()?.clone();
let (_, coords) = self.calculate_coordinates();
let mut core = self.core.clone();
core.coordinates = coords;
let output = self.get_listview().selected_proc()?.output.lock()?.clone();
self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| {
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
textview.set_text(&output).log();
textview.animate_slide_up().log();
Ok(textview)
}));
self.viewing = Some(self.proc_list.get_selection());
})).log();
self.viewing = Some(self.get_listview().get_selection());
Ok(())
}
pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates) {
let coordinates = self.get_coordinates().unwrap();
let xsize = coordinates.xsize();
let ysize = coordinates.ysize();
let top = coordinates.top().y();
let ratio = (33, 66);
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 left_coords = Coordinates {
size: left_size,
position: left_pos,
};
let main_coords = Coordinates {
size: main_size,
position: main_pos,
};
(left_coords, main_coords)
}
}
impl Widget for ProcView {
@ -243,29 +271,27 @@ impl Widget for ProcView {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
let (lcoord, rcoord) = self.calculate_coordinates();
self.proc_list.set_coordinates(&lcoord).log();
self.textview.set_coordinates(&rcoord).log();
self.hbox.refresh().log();
self.show_output().log();
self.proc_list.refresh().log();
self.textview.refresh().log();
self.get_listview().refresh().log();
self.get_textview().refresh().log();
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
Ok(self.proc_list.get_drawlist()? + &self.textview.get_drawlist()?)
self.hbox.get_drawlist()
}
fn on_key(&mut self, key: Key) -> HResult<()> {
match key {
Key::Char('w') => { return Err(HError::PopupFinnished) }
Key::Char('d') => { self.remove_proc()? }
Key::Char('k') => { self.proc_list.kill_proc()? }
Key::Char('k') => { self.get_listview().kill_proc()? }
Key::Up | Key::Char('p') => {
self.proc_list.move_up();
self.get_listview().move_up();
}
Key::Down | Key::Char('n') => {
self.proc_list.move_down();
self.get_listview().move_down();
}
_ => {}
}

View File

@ -80,6 +80,9 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
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 header = self.active_tab_().render_header()?;

View File

@ -4,7 +4,6 @@ use std::sync::mpsc::{Sender, Receiver, channel};
use termion::event::{Event, Key, MouseEvent};
use termion::input::TermRead;
use termion::screen::AlternateScreen;
use failure::Backtrace;
use crate::coordinates::{Coordinates, Position, Size};
@ -81,15 +80,12 @@ impl WidgetCore {
}
pub trait Widget {
fn get_widget(&self) -> Box<dyn Widget> {
Box::new(crate::textview::TextView::new_blank(self.get_core().unwrap()))
}
fn get_core(&self) -> HResult<&WidgetCore> {
Err(HError::NoWidgetCoreError(Backtrace::new()))
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Err(HError::NoWidgetCoreError(Backtrace::new()))
}
fn get_core(&self) -> HResult<&WidgetCore>; // {
// Err(HError::NoWidgetCoreError(Backtrace::new()))
// }
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> ;// {
// Err(HError::NoWidgetCoreError(Backtrace::new()))
// }
fn get_coordinates(&self) -> HResult<&Coordinates> {
Ok(&self.get_core()?.coordinates)
}
@ -205,6 +201,7 @@ pub trait Widget {
fn popup(&mut self) -> HResult<()> {
self.run_widget().log();
self.clear().log();
self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?;
Ok(())
}
@ -355,9 +352,9 @@ fn dispatch_events(rx: Receiver<Events>, tx: Sender<Events>) {
_ => {}
}
if let Some(tx_event) = &tx_exclusive_event {
tx_event.send(event).unwrap();
tx_event.send(event).ok();
} else {
tx.send(event).unwrap();
tx.send(event).ok();
}
}
});