diff --git a/src/components/utilities.rs b/src/components/utilities.rs index a0918a28..eafa15fc 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -25,245 +25,13 @@ use super::*; use text_processing::Reflow; mod widgets; - pub use self::widgets::*; + +mod layouts; +pub use self::layouts::*; + use std::collections::HashSet; -/// A horizontally split in half container. -#[derive(Debug)] -pub struct HSplit { - top: Box, - bottom: Box, - show_divider: bool, - ratio: usize, // bottom/whole height * 100 - id: ComponentId, -} - -impl fmt::Display for HSplit { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // TODO display subject/info - Display::fmt(&self.top, f) - } -} - -impl HSplit { - pub fn new( - top: Box, - bottom: Box, - ratio: usize, - show_divider: bool, - ) -> Self { - HSplit { - top, - bottom, - show_divider, - ratio, - id: ComponentId::new_v4(), - } - } -} - -impl Component for HSplit { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - if !is_valid_area!(area) { - return; - } - let upper_left = upper_left!(area); - let bottom_right = bottom_right!(area); - let total_rows = get_y(bottom_right) - get_y(upper_left); - let bottom_component_height = (self.ratio * total_rows) / 100; - let mid = get_y(upper_left) + total_rows - bottom_component_height; - - if self.show_divider { - for i in get_x(upper_left)..=get_x(bottom_right) { - grid[(i, mid)].set_ch('─'); - } - context - .dirty_areas - .push_back(((get_x(upper_left), mid), (get_x(bottom_right), mid))); - } - - self.top.draw( - grid, - ( - upper_left, - (get_x(bottom_right), get_y(upper_left) + mid - 1), - ), - context, - ); - self.bottom.draw( - grid, - ((get_x(upper_left), get_y(upper_left) + mid), bottom_right), - context, - ); - } - fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { - self.top.process_event(event, context) || self.bottom.process_event(event, context) - } - - fn is_dirty(&self) -> bool { - self.top.is_dirty() || self.bottom.is_dirty() - } - - fn set_dirty(&mut self, value: bool) { - self.top.set_dirty(value); - self.bottom.set_dirty(value); - } - - fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { - let mut top_map = self.top.get_shortcuts(context); - top_map.extend(self.bottom.get_shortcuts(context).into_iter()); - top_map - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} - -/// A vertically split in half container. -#[derive(Debug)] -pub struct VSplit { - left: Box, - right: Box, - show_divider: bool, - prev_visibility: (bool, bool), - /// This is the width of the right container to the entire width. - ratio: usize, // right/(container width) * 100 - id: ComponentId, -} - -impl fmt::Display for VSplit { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // TODO display focused component - Display::fmt(&self.right, f) - } -} - -impl VSplit { - pub fn new( - left: Box, - right: Box, - ratio: usize, - show_divider: bool, - ) -> Self { - VSplit { - left, - right, - show_divider, - prev_visibility: (true, true), - ratio, - id: ComponentId::new_v4(), - } - } -} - -impl Component for VSplit { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - if !is_valid_area!(area) { - return; - } - let upper_left = upper_left!(area); - let bottom_right = bottom_right!(area); - let total_cols = get_x(bottom_right) - get_x(upper_left); - let visibility = (self.left.is_visible(), self.right.is_visible()); - if visibility != self.prev_visibility { - self.set_dirty(true); - self.prev_visibility = visibility; - } - let right_component_width = match visibility { - (true, true) => (self.ratio * total_cols) / 100, - (false, true) => total_cols, - (true, false) => 0, - (false, false) => { - clear_area(grid, area, crate::conf::value(context, "theme_default")); - return; - } - }; - - let mid = get_x(bottom_right) - right_component_width; - - if get_y(upper_left) > 1 { - let c = grid - .get(mid, get_y(upper_left) - 1) - .map(Cell::ch) - .unwrap_or_else(|| ' '); - if let HORZ_BOUNDARY = c { - grid[(mid, get_y(upper_left) - 1)].set_ch(LIGHT_DOWN_AND_HORIZONTAL); - } - } - - if self.show_divider && mid != get_x(upper_left) { - for i in get_y(upper_left)..=get_y(bottom_right) { - grid[(mid, i)].set_ch(VERT_BOUNDARY); - grid[(mid, i)].set_fg(Color::Default); - grid[(mid, i)].set_bg(Color::Default); - } - if get_y(bottom_right) > 1 { - let c = grid - .get(mid, get_y(bottom_right) - 1) - .map(Cell::ch) - .unwrap_or_else(|| ' '); - if let HORZ_BOUNDARY = c { - grid[(mid, get_y(bottom_right) + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); - } - } - context - .dirty_areas - .push_back(((mid, get_y(upper_left)), (mid, get_y(bottom_right)))); - } - - if right_component_width == total_cols { - self.right.draw(grid, area, context); - } else if right_component_width == 0 { - self.left.draw(grid, area, context); - } else { - self.left.draw( - grid, - ( - upper_left, - ( - if self.show_divider { mid - 1 } else { mid }, - get_y(bottom_right), - ), - ), - context, - ); - self.right - .draw(grid, (set_x(upper_left, mid + 1), bottom_right), context); - } - } - - fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { - self.left.process_event(event, context) || self.right.process_event(event, context) - } - - fn is_dirty(&self) -> bool { - self.left.is_dirty() || self.right.is_dirty() - } - - fn set_dirty(&mut self, value: bool) { - self.left.set_dirty(value); - self.right.set_dirty(value); - } - - fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { - let mut right_map = self.right.get_shortcuts(context); - right_map.extend(self.left.get_shortcuts(context).into_iter()); - right_map - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} - #[derive(Debug, Clone, Copy)] pub enum PageMovement { Up(usize), diff --git a/src/components/utilities/layouts.rs b/src/components/utilities/layouts.rs new file mode 100644 index 00000000..a48578e5 --- /dev/null +++ b/src/components/utilities/layouts.rs @@ -0,0 +1,257 @@ +/* + * meli - layouts + * + * Copyright 2017-2018, 2020 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +/// A horizontally split in half container. +#[derive(Debug)] +pub struct HSplit { + top: Box, + bottom: Box, + show_divider: bool, + ratio: usize, // bottom/whole height * 100 + id: ComponentId, +} + +impl fmt::Display for HSplit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO display subject/info + Display::fmt(&self.top, f) + } +} + +impl HSplit { + pub fn new( + top: Box, + bottom: Box, + ratio: usize, + show_divider: bool, + ) -> Self { + HSplit { + top, + bottom, + show_divider, + ratio, + id: ComponentId::new_v4(), + } + } +} + +impl Component for HSplit { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + if !is_valid_area!(area) { + return; + } + let upper_left = upper_left!(area); + let bottom_right = bottom_right!(area); + let total_rows = get_y(bottom_right) - get_y(upper_left); + let bottom_component_height = (self.ratio * total_rows) / 100; + let mid = get_y(upper_left) + total_rows - bottom_component_height; + + if self.show_divider { + for i in get_x(upper_left)..=get_x(bottom_right) { + grid[(i, mid)].set_ch('─'); + } + context + .dirty_areas + .push_back(((get_x(upper_left), mid), (get_x(bottom_right), mid))); + } + + self.top.draw( + grid, + ( + upper_left, + (get_x(bottom_right), get_y(upper_left) + mid - 1), + ), + context, + ); + self.bottom.draw( + grid, + ((get_x(upper_left), get_y(upper_left) + mid), bottom_right), + context, + ); + } + fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { + self.top.process_event(event, context) || self.bottom.process_event(event, context) + } + + fn is_dirty(&self) -> bool { + self.top.is_dirty() || self.bottom.is_dirty() + } + + fn set_dirty(&mut self, value: bool) { + self.top.set_dirty(value); + self.bottom.set_dirty(value); + } + + fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { + let mut top_map = self.top.get_shortcuts(context); + top_map.extend(self.bottom.get_shortcuts(context).into_iter()); + top_map + } + + fn id(&self) -> ComponentId { + self.id + } + fn set_id(&mut self, id: ComponentId) { + self.id = id; + } +} + +/// A vertically split in half container. +#[derive(Debug)] +pub struct VSplit { + left: Box, + right: Box, + show_divider: bool, + prev_visibility: (bool, bool), + /// This is the width of the right container to the entire width. + ratio: usize, // right/(container width) * 100 + id: ComponentId, +} + +impl fmt::Display for VSplit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO display focused component + Display::fmt(&self.right, f) + } +} + +impl VSplit { + pub fn new( + left: Box, + right: Box, + ratio: usize, + show_divider: bool, + ) -> Self { + VSplit { + left, + right, + show_divider, + prev_visibility: (true, true), + ratio, + id: ComponentId::new_v4(), + } + } +} + +impl Component for VSplit { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + if !is_valid_area!(area) { + return; + } + let upper_left = upper_left!(area); + let bottom_right = bottom_right!(area); + let total_cols = get_x(bottom_right) - get_x(upper_left); + let visibility = (self.left.is_visible(), self.right.is_visible()); + if visibility != self.prev_visibility { + self.set_dirty(true); + self.prev_visibility = visibility; + } + let right_component_width = match visibility { + (true, true) => (self.ratio * total_cols) / 100, + (false, true) => total_cols, + (true, false) => 0, + (false, false) => { + clear_area(grid, area, crate::conf::value(context, "theme_default")); + return; + } + }; + + let mid = get_x(bottom_right) - right_component_width; + + if get_y(upper_left) > 1 { + let c = grid + .get(mid, get_y(upper_left) - 1) + .map(Cell::ch) + .unwrap_or_else(|| ' '); + if let HORZ_BOUNDARY = c { + grid[(mid, get_y(upper_left) - 1)].set_ch(LIGHT_DOWN_AND_HORIZONTAL); + } + } + + if self.show_divider && mid != get_x(upper_left) { + for i in get_y(upper_left)..=get_y(bottom_right) { + grid[(mid, i)].set_ch(VERT_BOUNDARY); + grid[(mid, i)].set_fg(Color::Default); + grid[(mid, i)].set_bg(Color::Default); + } + if get_y(bottom_right) > 1 { + let c = grid + .get(mid, get_y(bottom_right) - 1) + .map(Cell::ch) + .unwrap_or_else(|| ' '); + if let HORZ_BOUNDARY = c { + grid[(mid, get_y(bottom_right) + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); + } + } + context + .dirty_areas + .push_back(((mid, get_y(upper_left)), (mid, get_y(bottom_right)))); + } + + if right_component_width == total_cols { + self.right.draw(grid, area, context); + } else if right_component_width == 0 { + self.left.draw(grid, area, context); + } else { + self.left.draw( + grid, + ( + upper_left, + ( + if self.show_divider { mid - 1 } else { mid }, + get_y(bottom_right), + ), + ), + context, + ); + self.right + .draw(grid, (set_x(upper_left, mid + 1), bottom_right), context); + } + } + + fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { + self.left.process_event(event, context) || self.right.process_event(event, context) + } + + fn is_dirty(&self) -> bool { + self.left.is_dirty() || self.right.is_dirty() + } + + fn set_dirty(&mut self, value: bool) { + self.left.set_dirty(value); + self.right.set_dirty(value); + } + + fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { + let mut right_map = self.right.get_shortcuts(context); + right_map.extend(self.left.get_shortcuts(context).into_iter()); + right_map + } + + fn id(&self) -> ComponentId { + self.id + } + fn set_id(&mut self, id: ComponentId) { + self.id = id; + } +}