handle terminal resizing

This commit is contained in:
rabite 2019-03-19 01:08:22 +01:00
parent c719ec7a3c
commit 161ba5ac3f
15 changed files with 355 additions and 45 deletions

View File

@ -21,6 +21,7 @@ failure = "0.1.5"
failure_derive = "0.1.1"
notify = "4.0.9"
parse-ansi = "0.1.6"
signal-notify = "0.1.3"
#[profile.release]
#debug = true

View File

@ -4,6 +4,7 @@ use std::collections::HashMap;
use crate::fail::{HResult, HError, ErrorLog};
use crate::widget::{Widget, WidgetCore};
use crate::coordinates::Coordinates;
use crate::files::{Files, File};
use crate::term;
@ -68,19 +69,25 @@ pub struct BMPopup {
impl BMPopup {
pub fn new(core: &WidgetCore) -> BMPopup {
let bmpopup = BMPopup {
let mut bmpopup = BMPopup {
core: core.clone(),
bookmarks: Bookmarks::new(),
bookmark_path: None,
add_mode: false
};
bmpopup.set_coordinates(&core.coordinates).log();
bmpopup
}
pub fn pick(&mut self, cwd: String) -> HResult<String> {
self.bookmark_path = Some(cwd);
self.refresh()?;
self.popup()?;
match self.popup() {
Ok(_) => {},
Err(HError::PopupFinnished) => {},
err @ Err(HError::TerminalResizedError) => err?,
err @ Err(_) => err?,
}
self.clear()?;
let bookmark = self.bookmark_path.take();
@ -120,16 +127,24 @@ impl Widget for BMPopup {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
let tysize = crate::term::ysize();
let txsize = crate::term::xsize();
let len = self.bookmarks.mapping.len() as u16;
let ysize = tysize - (len + 1);
Ok(())
}
self.core.coordinates.set_position(1, ysize);
self.core.coordinates.set_size(txsize, len+1);
fn resize(&mut self) -> HResult<()> {
HError::terminal_resized()
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
let (xsize, ysize) = coordinates.size_u();
let len = self.bookmarks.mapping.len();
let ysize = ysize.saturating_sub( len + 1 );
self.core.coordinates.set_size_u(xsize.saturating_sub(1), len);
self.core.coordinates.set_position_u(1, ysize+2);
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
let ypos = self.get_coordinates()?.ypos();

View File

@ -32,6 +32,10 @@ impl Coordinates {
self.size.0 = (x, y);
}
pub fn set_size_u(&mut self, x: usize, y: usize) {
self.size.0 = ((x+1) as u16, (y+1) as u16);
}
pub fn set_xsize(&mut self, x: u16) {
(self.size.0).0 = x;
}
@ -44,6 +48,10 @@ impl Coordinates {
self.position.0 = (x, y);
}
pub fn set_position_u(&mut self, x: usize, y: usize) {
self.position.0 = ((x+1) as u16, (y+1) as u16);
}
pub fn set_xpos(&mut self, x: u16) {
(self.position.0).0 = x;
}

View File

@ -66,7 +66,9 @@ pub enum HError {
#[fail(display = "Empty input!")]
MiniBufferEmptyInput,
#[fail(display = "Undefined key: {:?}", key)]
WidgetUndefinedKeyError{key: Key}
WidgetUndefinedKeyError{key: Key},
#[fail(display = "Terminal has been resized!")]
TerminalResizedError,
}
impl HError {
@ -109,6 +111,10 @@ impl HError {
Err(HError::PreviewFailed{ file: name,
backtrace: Backtrace::new() })
}
pub fn terminal_resized<T>() -> HResult<T> {
Err(HError::TerminalResizedError)
}
}

View File

@ -20,6 +20,7 @@ use crate::proclist::ProcView;
use crate::bookmarks::BMPopup;
use crate::term::ScreenExt;
use crate::foldview::LogView;
use crate::coordinates::Coordinates;
#[derive(PartialEq)]
pub enum FileBrowserWidgets {
@ -40,6 +41,12 @@ impl Widget for FileBrowserWidgets {
FileBrowserWidgets::Previewer(widget) => widget.get_core_mut()
}
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
match self {
FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates),
FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates),
}
}
fn refresh(&mut self) -> HResult<()> {
match self {
FileBrowserWidgets::FileList(widget) => widget.refresh(),
@ -335,13 +342,28 @@ impl FileBrowser {
Ok(())
}
pub fn goto_bookmark(&mut self) -> HResult<()> {
let cwd = match self.prev_cwd.as_ref() {
fn get_boomark(&mut self) -> HResult<String> {
let cwd = &match self.prev_cwd.as_ref() {
Some(cwd) => cwd,
None => &self.cwd
}.path.to_string_lossy().to_string();
let path = self.bookmarks.lock()?.pick(cwd)?;
loop {
let bookmark = self.bookmarks.lock()?.pick(cwd.to_string());
if let Err(HError::TerminalResizedError) = bookmark {
self.core.screen.clear();
self.resize();
self.refresh();
self.draw();
continue;
}
return bookmark;
}
}
pub fn goto_bookmark(&mut self) -> HResult<()> {
let path = self.get_boomark()?;
let path = File::new_from_path(&PathBuf::from(path))?;
self.main_widget_goto(&path)?;
Ok(())
@ -727,6 +749,16 @@ impl Widget for FileBrowser {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
self.columns.set_coordinates(&coordinates).log();
self.proc_view.lock()?.set_coordinates(&coordinates).log();
self.log_view.lock()?.set_coordinates(&coordinates).log();
self.bookmarks.lock()?.set_coordinates(&coordinates).log();
Ok(())
}
fn render_header(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let file = self.selected_file()?;

View File

@ -5,7 +5,7 @@ use chrono::{DateTime, Local};
use crate::term;
use crate::widget::Widget;
use crate::listview::{ListView, Listable};
use crate::fail::{HResult, HError};
use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::Dirtyable;
pub type LogView = ListView<Vec<LogEntry>>;
@ -79,6 +79,8 @@ impl From<&HError> for LogEntry {
pub trait FoldableWidgetExt {
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
}
impl FoldableWidgetExt for ListView<Vec<LogEntry>> {
@ -88,6 +90,43 @@ impl FoldableWidgetExt for ListView<Vec<LogEntry>> {
}
Ok(())
}
fn render_header(&self) -> HResult<String> {
let (xsize, _) = self.core.coordinates.size_u();
let current = self.current_fold().unwrap_or(0);
let num = self.content.len();
let hint = format!("{} / {}", current, num);
let hint_xpos = xsize - hint.len();
let header = format!("Logged entries: {}{}{}",
num,
term::goto_xy_u(hint_xpos, 0),
hint);
Ok(header)
}
fn render_footer(&self) -> HResult<String> {
let current = self.current_fold()?;
if let Some(logentry) = self.content.get(current) {
let (xsize, ysize) = self.core.coordinates.size_u();
let (_, ypos) = self.core.coordinates.position_u();
let description = logentry.description();
let lines = logentry.lines();
let start_pos = self.fold_start_pos(current);
let selection = self.get_selection();
let current_line = (selection - start_pos) + 1;
let line_hint = format!("{} / {}", current_line, lines);
let hint_xpos = xsize - line_hint.len();
let hint_ypos = ysize + ypos + 1;
let footer = format!("LogEntry: {}{}{}{}{}",
description,
term::reset(),
term::status_bg(),
term::goto_xy_u(hint_xpos, hint_ypos),
line_hint);
Ok(footer)
} else { Ok("No log entries".to_string()) }
}
}
trait LogList {
@ -151,7 +190,7 @@ where
ListView<Vec<F>>: FoldableWidgetExt {
fn toggle_fold(&mut self) -> HResult<()> {
let fold = self.current_fold();
let fold = self.current_fold()?;
let fold_pos = self.fold_start_pos(fold);
self.content[fold].toggle_fold();
@ -173,7 +212,7 @@ where
})
}
fn current_fold(&self) -> usize {
fn current_fold(&self) -> Option<usize> {
let pos = self.get_selection();
let fold_lines = self
@ -194,7 +233,7 @@ where
} else {
(lines + current_fold_lines, None)
}
}}).1.unwrap()
}}).1
}
}
@ -220,6 +259,15 @@ where
.flatten()
.collect()
}
fn render_header(&self) -> HResult<String> {
FoldableWidgetExt::render_header(self)
}
fn render_footer(&self) -> HResult<String> {
FoldableWidgetExt::render_footer(self)
}
fn on_refresh(&mut self) -> HResult<()> {
FoldableWidgetExt::on_refresh(self)
}

View File

@ -118,6 +118,12 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
self.resize_children()
}
fn render_header(&self) -> HResult<String> {
self.active_widget().render_header()
}
@ -125,7 +131,7 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
fn refresh(&mut self) -> HResult<()> {
self.resize_children().log();
for child in &mut self.widgets {
child.refresh()?
child.refresh().log();
}
Ok(())
}

View File

@ -12,6 +12,8 @@ use crate::dirty::Dirtyable;
pub trait Listable {
fn len(&self) -> usize;
fn render(&self) -> Vec<String>;
fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) }
}
@ -304,6 +306,7 @@ impl ListView<Files>
fn toggle_tag(&mut self) -> HResult<()> {
self.selected_file_mut().toggle_tag()?;
self.move_down();
self.core.set_dirty();
Ok(())
}
@ -412,6 +415,13 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
Ok(())
}
fn render_header(&self) -> HResult<String> {
Listable::render_header(self)
}
fn render_footer(&self) -> HResult<String> {
Listable::render_footer(self)
}
fn get_drawlist(&self) -> HResult<String> {
let mut output = term::reset();

View File

@ -18,6 +18,7 @@ extern crate rayon;
extern crate libc;
extern crate notify;
extern crate parse_ansi;
extern crate signal_notify;
use failure::Fail;

View File

@ -93,9 +93,14 @@ where
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
self.widgets.set_coordinates(&coordinates)
}
fn refresh(&mut self) -> HResult<()> {
self.widgets.refresh().log();
Ok(())
self.widgets.refresh()
}
fn get_drawlist(&self) -> HResult<String> {

View File

@ -6,6 +6,7 @@ use crate::files::{File, Files, Kind};
use crate::listview::ListView;
use crate::textview::TextView;
use crate::widget::{Widget, WidgetCore};
use crate::coordinates::Coordinates;
use crate::fail::{HResult, HError, ErrorLog};
@ -189,12 +190,29 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
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();
widget.set_coordinates(&coordinates)?;
}
Ok(())
}
fn refresh(&mut self) -> HResult<()> {
let coords = self.get_coordinates()?;
if let Ok(widget) = self.widget() {
let mut widget = widget.lock()?;
let widget = widget.as_mut()?;
if widget.get_coordinates()? != coords {
widget.set_coordinates(self.get_coordinates()?)?;
widget.refresh()?;
} else {
widget.refresh()?;
}
}
Ok(())
}
@ -427,6 +445,12 @@ impl Widget for Previewer {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
self.widget.set_coordinates(&coordinates)
}
fn refresh(&mut self) -> HResult<()> {
self.widget.refresh()
}

View File

@ -10,6 +10,7 @@ use unicode_width::UnicodeWidthStr;
use crate::listview::{Listable, ListView};
use crate::textview::TextView;
use crate::widget::{Widget, Events, WidgetCore};
use crate::coordinates::Coordinates;
use crate::hbox::HBox;
use crate::preview::WillBeWidget;
use crate::fail::{HResult, HError, ErrorLog};
@ -227,7 +228,13 @@ pub struct ProcView {
}
impl HBox<ProcViewWidgets> {
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
fn get_listview(&self) -> &ListView<Vec<Process>> {
match &self.widgets[0] {
ProcViewWidgets::List(listview) => listview,
_ => unreachable!()
}
}
fn get_listview_mut(&mut self) -> &mut ListView<Vec<Process>> {
match &mut self.widgets[0] {
ProcViewWidgets::List(listview) => listview,
_ => unreachable!()
@ -259,22 +266,26 @@ impl ProcView {
}
}
fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
fn get_listview(& self) -> & ListView<Vec<Process>> {
self.hbox.get_listview()
}
fn get_listview_mut(&mut self) -> &mut ListView<Vec<Process>> {
self.hbox.get_listview_mut()
}
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
self.hbox.get_textview()
}
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
self.get_listview().run_proc(cmd)?;
self.get_listview_mut().run_proc(cmd)?;
Ok(())
}
pub fn remove_proc(&mut self) -> HResult<()> {
if self.get_listview().content.len() == 0 { return Ok(()) }
self.get_listview().remove_proc()?;
if self.get_listview_mut().content.len() == 0 { return Ok(()) }
self.get_listview_mut().remove_proc()?;
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
textview.refresh().log();
@ -285,10 +296,10 @@ impl ProcView {
}
fn show_output(&mut self) -> HResult<()> {
if Some(self.get_listview().get_selection()) == self.viewing {
if Some(self.get_listview_mut().get_selection()) == self.viewing {
return Ok(());
}
let output = self.get_listview().selected_proc()?.output.lock()?.clone();
let output = self.get_listview_mut().selected_proc()?.output.lock()?.clone();
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
@ -296,7 +307,7 @@ impl ProcView {
textview.animate_slide_up().log();
Ok(textview)
})).log();
self.viewing = Some(self.get_listview().get_selection());
self.viewing = Some(self.get_listview_mut().get_selection());
Ok(())
}
@ -343,11 +354,75 @@ impl Widget for ProcView {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
self.hbox.core.coordinates = coordinates.clone();
self.hbox.set_coordinates(&coordinates)
}
fn render_header(&self) -> HResult<String> {
let listview = self.get_listview();
let procs_num = listview.len();
let procs_running = listview
.content
.iter()
.filter(|proc| proc.status.lock().unwrap().is_none())
.count();
let header = format!("Running processes: {} / {}",
procs_running,
procs_num);
Ok(header)
}
fn render_footer(&self) -> HResult<String> {
let listview = self.get_listview();
let selection = listview.get_selection();
if let Some(proc) = listview.content.get(selection) {
let cmd = &proc.cmd;
let pid = proc.handle.lock()?.id();
let proc_status = proc.status.lock()?;
let proc_success = proc.success.lock()?;
let procinfo = if proc_status.is_some() {
let color_success =
if let Some(_) = *proc_success {
format!("{}successfully", term::color_green())
} else {
format!("{}unsuccessfully", term::color_red())
};
let color_status =
if let Some(success) = *proc_success {
if success {
format!("{}{}", term::color_green(), proc_status.unwrap())
} else {
format!("{}{}", term::color_red(), proc_status.unwrap())
}
} else { "wtf".to_string() };
let procinfo = format!("Process: {}:{} exited {}{}{} with status: {}",
cmd,
pid,
color_success,
term::reset(),
term::status_bg(),
color_status);
procinfo
} else { "still running".to_string() };
let footer = format!("{}: {}", cmd, procinfo);
Ok(footer)
} else { Ok("No proccesses".to_string()) }
}
fn refresh(&mut self) -> HResult<()> {
self.hbox.refresh().log();
self.show_output().log();
self.get_listview().refresh().log();
self.get_listview_mut().refresh().log();
self.get_textview().refresh().log();
Ok(())
@ -359,12 +434,12 @@ impl Widget for ProcView {
match key {
Key::Char('w') => { return Err(HError::PopupFinnished) }
Key::Char('d') => { self.remove_proc()? }
Key::Char('k') => { self.get_listview().kill_proc()? }
Key::Char('k') => { self.get_listview_mut().kill_proc()? }
Key::Up | Key::Char('p') => {
self.get_listview().move_up();
self.get_listview_mut().move_up();
}
Key::Down | Key::Char('n') => {
self.get_listview().move_down();
self.get_listview_mut().move_down();
}
Key::Char('f') => { self.toggle_follow().log(); }
Key::Ctrl('n') => { self.scroll_down().log(); },

View File

@ -2,6 +2,8 @@ use termion::event::Key;
use crate::widget::{Widget, WidgetCore};
use crate::fail::{HResult, ErrorLog};
use crate::coordinates::Coordinates;
use crate::dirty::Dirtyable;
pub trait Tabbable {
fn new_tab(&mut self) -> HResult<()>;
@ -105,6 +107,15 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
for widget in &mut self.widgets {
widget.set_coordinates(coordinates).log();
}
Ok(())
}
fn render_header(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let header = self.active_tab_().render_header()?;

View File

@ -1,5 +1,5 @@
use std::io::{Stdout, Write, BufWriter};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
use termion;
use termion::screen::AlternateScreen;
@ -14,7 +14,8 @@ pub type TermMode = AlternateScreen<MouseTerminal<RawTerminal<BufWriter<Stdout>>
#[derive(Clone)]
pub struct Screen {
screen: Arc<Mutex<Option<TermMode>>>
screen: Arc<Mutex<Option<TermMode>>>,
size: Arc<RwLock<Option<(usize, usize)>>>
}
impl Screen {
@ -25,7 +26,8 @@ impl Screen {
screen.cursor_hide()?;
Ok(Screen {
screen: Arc::new(Mutex::new(Some(screen)))
screen: Arc::new(Mutex::new(Some(screen))),
size: Arc::new(RwLock::new(None))
})
}
@ -43,6 +45,19 @@ impl Screen {
*self.screen.lock()? = Some(screen);
Ok(())
}
pub fn set_size(&self, size: (usize, usize)) -> HResult<()> {
*self.size.write()? = Some(size);
Ok(())
}
pub fn is_resized(&self) -> HResult<(usize, usize)> {
Ok(self.size.read()?.clone()?)
}
pub fn take_size(&self) -> HResult<(usize, usize)> {
Ok(self.size.write()?.take()?)
}
}
impl Write for Screen {
@ -70,7 +85,9 @@ pub trait ScreenExt: Write {
Ok(())
}
fn clear(&mut self) -> HResult<()> {
write!(self, "{}", termion::clear::All)?;
write!(self, "{}{}",
termion::style::Reset,
termion::clear::All)?;
Ok(())
}
fn write_str(&mut self, str: &str) -> HResult<()> {
@ -83,6 +100,10 @@ pub trait ScreenExt: Write {
write!(self, "{}", goto_xy(x + 1, y + 1))?;
Ok(())
}
fn size(&self) -> HResult<(usize, usize)> {
let (xsize, ysize) = termion::terminal_size()?;
Ok(((xsize-1) as usize, (ysize-1) as usize))
}
fn xsize(&self) -> HResult<usize> {
let (xsize, _) = termion::terminal_size()?;
Ok((xsize - 1) as usize)
@ -116,6 +137,11 @@ pub fn ysize() -> u16 {
ysize
}
pub fn size() -> HResult<(usize, usize)> {
let (xsize, ysize) = termion::terminal_size()?;
Ok(((xsize-1) as usize, (ysize-1) as usize))
}
pub fn sized_string(string: &str, xsize: u16) -> String {
string.chars().fold("".to_string(), |acc, ch| {
let width: usize = unicode_width::UnicodeWidthStr::width_cjk(acc.as_str());

View File

@ -11,6 +11,7 @@ use crate::minibuffer::MiniBuffer;
use crate::term;
use crate::term::{Screen, ScreenExt};
use crate::dirty::{Dirtyable, DirtyBit};
use crate::signal_notify::{notify, Signal};
use std::io::stdin;
@ -18,6 +19,7 @@ use std::io::stdin;
pub enum Events {
InputEvent(Event),
WidgetReady,
TerminalResized,
ExclusiveEvent(Option<Sender<Events>>),
InputEnabled(bool),
RequestInput,
@ -52,12 +54,14 @@ pub struct WidgetCore {
pub event_sender: Sender<Events>,
event_receiver: Arc<Mutex<Option<Receiver<Events>>>>,
pub status_bar_content: Arc<Mutex<Option<String>>>,
term_size: (usize, usize),
dirty: DirtyBit
}
impl WidgetCore {
pub fn new() -> HResult<WidgetCore> {
let screen = Screen::new()?;
let (xsize, ysize) = screen.size()?;
let coords = Coordinates::new_at(term::xsize(),
term::ysize() - 2,
1,
@ -72,6 +76,7 @@ impl WidgetCore {
event_sender: sender,
event_receiver: Arc::new(Mutex::new(Some(receiver))),
status_bar_content: status_bar_content,
term_size: (xsize, ysize),
dirty: DirtyBit::new() };
let minibuffer = MiniBuffer::new(&core);
@ -106,11 +111,10 @@ pub trait Widget {
Ok(&self.get_core()?.coordinates)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
let widget_coords = &mut self.get_core_mut()?.coordinates;
if widget_coords != coordinates {
*widget_coords = coordinates.clone();
self.get_core_mut()?.set_dirty();
self.refresh()?;
let core = &mut self.get_core_mut()?;
if &core.coordinates != coordinates {
core.coordinates = coordinates.clone();
core.set_dirty();
}
Ok(())
}
@ -259,6 +263,13 @@ pub trait Widget {
Events::Status(status) => {
self.show_status(&status).log();
}
Events::TerminalResized => {
self.screen()?.clear().log();
match self.resize() {
err @ Err(HError::TerminalResizedError) => err?,
_ => {}
}
}
_ => {}
}
self.refresh().log();
@ -313,7 +324,7 @@ pub trait Widget {
let (tx_internal_event, rx_internal_event) = channel();
let rx_global_event = self.get_core()?.event_receiver.lock()?.take()?;
dispatch_events(tx_internal_event, rx_global_event);
dispatch_events(tx_internal_event, rx_global_event, self.screen()?);
for event in rx_internal_event.iter() {
match event {
@ -327,8 +338,13 @@ pub trait Widget {
Events::Status(status) => {
self.show_status(&status).log();
}
Events::TerminalResized => {
self.screen()?.clear().log();
}
_ => {}
}
self.resize().log();
self.screen()?.take_size().ok();
self.refresh().ok();
self.draw().ok();
}
@ -387,14 +403,26 @@ pub trait Widget {
let mut screen = self.screen()?;
screen.write_str(s)
}
fn resize(&mut self) -> HResult<()> {
if let Ok((xsize, ysize)) = self.screen()?.is_resized() {
let mut coords = self.get_core()?.coordinates.clone();
coords.set_size_u(xsize, ysize-2);
self.set_coordinates(&coords)?;
}
Ok(())
}
}
fn dispatch_events(tx_internal: Sender<Events>, rx_global: Receiver<Events>) {
fn dispatch_events(tx_internal: Sender<Events>,
rx_global: Receiver<Events>,
screen: Screen) {
let (tx_event, rx_event) = channel();
let (tx_input_req, rx_input_req) = channel();
input_thread(tx_event.clone(), rx_input_req);
event_thread(rx_global, tx_event.clone());
signal_thread(tx_event.clone());
std::thread::spawn(move || {
let mut tx_exclusive_event: Option<Sender<Events>> = None;
@ -415,6 +443,11 @@ fn dispatch_events(tx_internal: Sender<Events>, rx_global: Receiver<Events>) {
}
continue;
}
Events::TerminalResized => {
if let Ok(size) = term::size() {
screen.set_size(size).log();
}
}
_ => {}
}
if let Some(tx_exclusive) = &tx_exclusive_event {
@ -444,3 +477,12 @@ fn input_thread(tx: Sender<Events>, rx_input_request: Receiver<()>) {
}
});
}
fn signal_thread(tx: Sender<Events>) {
std::thread::spawn(move || {
let rx = notify(&[Signal::WINCH]);
for _ in rx.iter() {
tx.send(Events::TerminalResized).unwrap();
}
});
}