summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2018-07-18 10:42:52 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-06-10 19:40:23 +0300
commitab099b524a504ff3b5e0a3d3dbac347f9e2551b6 (patch)
treed27b3f0abc557b6356b99879d056788ae285ddfd
parente95cc4c1e90d330423d6bf948a29160a8e506db6 (diff)
Add more documentation.
-rw-r--r--.gdbinit2
-rw-r--r--src/bin.rs6
-rw-r--r--src/ui/cells.rs11
-rw-r--r--src/ui/components/mail.rs144
-rw-r--r--src/ui/components/mod.rs11
-rw-r--r--src/ui/components/notifications.rs5
-rw-r--r--src/ui/components/utilities.rs18
-rw-r--r--src/ui/execute/mod.rs10
-rw-r--r--src/ui/mod.rs120
-rw-r--r--src/ui/position.rs69
10 files changed, 212 insertions, 184 deletions
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 00000000..dbc6aca4
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,2 @@
+break rust_panic
+break core::option::expect_failed::h4927e1fef06c4878
diff --git a/src/bin.rs b/src/bin.rs
index 96299f8f..c2e8c578 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -18,6 +18,12 @@
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
+
+/*! This crate contains the frontend stuff of the application. The application entry way on `src/bin.rs` creates an event loop and passes input to the `ui` module.
+
+The mail handling stuff is done in the `melib` crate which includes all backend needs. The split is done to theoretically be able to create different frontends with the same innards.
+ */
+
extern crate melib;
#[macro_use]
extern crate nom;
diff --git a/src/ui/cells.rs b/src/ui/cells.rs
index 0e7670c4..04e987c0 100644
--- a/src/ui/cells.rs
+++ b/src/ui/cells.rs
@@ -1,7 +1,14 @@
+/*!
+ Define a (x, y) point in the terminal display as a holder of a character, foreground/background
+ colors and attributes.
+ */
use std::ops::{Index, IndexMut, Deref, DerefMut};
use super::position::*;
use termion::color::AnsiValue;
+
+/// Types and implementations taken from rustty for convenience.
+
pub trait CellAccessor: HasSize {
fn cellvec(&self) -> &Vec<Cell>;
fn cellvec_mut(&mut self) -> &mut Vec<Cell>;
@@ -409,10 +416,10 @@ impl Color {
pub fn as_termion(&self) -> AnsiValue {
match *self {
b @ Color::Black | b @ Color::Red | b @ Color::Green | b @ Color::Yellow | b @ Color::Blue | b @ Color::Magenta | b @ Color::Cyan | b @ Color::White | b @ Color::Default =>
- {
+ {
AnsiValue(b.as_byte())
},
- Color::Byte(b) => {
+ Color::Byte(b) => {
AnsiValue(b as u8)
},
}
diff --git a/src/ui/components/mail.rs b/src/ui/components/mail.rs
index 1843c666..c3277202 100644
--- a/src/ui/components/mail.rs
+++ b/src/ui/components/mail.rs
@@ -1,3 +1,5 @@
+/*! Entities that handle Mail specific functions.
+ */
use ui::components::*;
use ui::cells::*;
@@ -90,10 +92,10 @@ impl MailListing {
match iter.peek() {
Some(&(_, x))
if mailbox.get_thread(*x).get_indentation() == indentation =>
- {
- indentations.pop();
- indentations.push(true);
- }
+ {
+ indentations.pop();
+ indentations.push(true);
+ }
_ => {
indentations.pop();
indentations.push(false);
@@ -115,8 +117,8 @@ impl MailListing {
Color::Byte(236)
} else {
Color::Default
- }
- let x = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, idx == self.cursor_pos.2, &indentations),
+ };
+ let x = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, &indentations),
&mut content,
fg_color,
bg_color,
@@ -129,23 +131,23 @@ impl MailListing {
match iter.peek() {
Some(&(_, x))
if mailbox.get_thread(*x).get_indentation() > indentation =>
- {
- indentations.push(false);
- }
+ {
+ indentations.push(false);
+ }
Some(&(_, x))
if mailbox.get_thread(*x).get_indentation() < indentation =>
- {
- for _ in 0..(indentation - mailbox.get_thread(*x).get_indentation()) {
- indentations.pop();
+ {
+ for _ in 0..(indentation - mailbox.get_thread(*x).get_indentation()) {
+ indentations.pop();
+ }
}
- }
_ => {}
}
}
} else {
- // Populate `CellBuffer` with every entry.
- // TODO: Lazy load?
+ // Populate `CellBuffer` with every entry.
+ // TODO: Lazy load?
let mut idx = 0;
for y in 0..=self.length {
if idx >= self.length {
@@ -255,6 +257,40 @@ impl MailListing {
}
/// Create a pager for the `Envelope` currently under the cursor.
+ fn draw_header_view(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
+ {
+ let threaded = context.accounts[self.cursor_pos.0].settings.threaded;
+ let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1].as_ref().unwrap().as_ref().unwrap();
+ let envelope: &Envelope = if threaded {
+ let i = mailbox.get_threaded_mail(self.cursor_pos.2);
+ &mailbox.collection[i]
+ } else {
+ &mailbox.collection[self.cursor_pos.2]
+ };
+
+ let pager_filter = context.settings.pager.filter.clone();
+ self.pager = Some(Pager::new(&envelope, pager_filter));
+ }
+ self.pager.as_mut().map(|p| p.draw(grid, area, context));
+ }
+ /// Create a pager for the `Envelope` currently under the cursor.
+ fn draw_attachment_view(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
+ {
+ let threaded = context.accounts[self.cursor_pos.0].settings.threaded;
+ let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1].as_ref().unwrap().as_ref().unwrap();
+ let envelope: &Envelope = if threaded {
+ let i = mailbox.get_threaded_mail(self.cursor_pos.2);
+ &mailbox.collection[i]
+ } else {
+ &mailbox.collection[self.cursor_pos.2]
+ };
+
+ let pager_filter = context.settings.pager.filter.clone();
+ self.pager = Some(Pager::new(&envelope, pager_filter));
+ }
+ self.pager.as_mut().map(|p| p.draw(grid, area, context));
+ }
+ /// Create a pager for the `Envelope` currently under the cursor.
fn draw_mail_view(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
{
let threaded = context.accounts[self.cursor_pos.0].settings.threaded;
@@ -272,28 +308,12 @@ impl MailListing {
self.pager.as_mut().map(|p| p.draw(grid, area, context));
}
fn make_thread_entry(envelope: &Envelope, idx: usize, indent: usize,
- container: &Container, highlight: bool, indentations: &Vec<bool>) -> String {
+ container: &Container, indentations: &Vec<bool>) -> String {
let has_sibling = container.has_sibling();
let has_parent = container.has_parent();
let show_subject = container.get_show_subject();
- let fg_color = if !envelope.is_seen() {
- Color::Byte(0)
- } else {
- Color::Default
- };
- let bg_color = if highlight {
- if !envelope.is_seen() {
- Color::Byte(252)
- } else if idx % 2 == 0 {
- Color::Byte(236)
- } else {
- Color::Default
- }
- } else {
- Color::Byte(246)
- };
- let mut s = format!("{} {} ", idx, &envelope.get_datetime().format("%Y-%m-%d %H:%M:%S").to_string()); // {} {:.85}",idx,),e.get_subject())
+ let mut s = format!("{} {} ", idx, &envelope.get_datetime().format("%Y-%m-%d %H:%M:%S").to_string());
for i in 0..indent {
if indentations.len() > i && indentations[i]
{
@@ -398,50 +418,50 @@ impl Component for MailListing {
};
let x = write_string_to_grid(&format!("Date: {}", envelope.get_date_as_str()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, mid+1), set_y(bottom_right, mid+1)));
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, mid+1), set_y(bottom_right, mid+1)));
for x in x..=get_x(bottom_right) {
grid[(x, mid+1)].set_ch(' ');
grid[(x, mid+1)].set_bg(Color::Default);
grid[(x, mid+1)].set_fg(Color::Default);
}
let x = write_string_to_grid(&format!("From: {}", envelope.get_from()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, mid+2), set_y(bottom_right, mid+2)));
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, mid+2), set_y(bottom_right, mid+2)));
for x in x..=get_x(bottom_right) {
grid[(x, mid+2)].set_ch(' ');
grid[(x, mid+2)].set_bg(Color::Default);
grid[(x, mid+2)].set_fg(Color::Default);
}
let x = write_string_to_grid(&format!("To: {}", envelope.get_to()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, mid+3), set_y(bottom_right, mid+3)));
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, mid+3), set_y(bottom_right, mid+3)));
for x in x..=get_x(bottom_right) {
grid[(x, mid+3)].set_ch(' ');
grid[(x, mid+3)].set_bg(Color::Default);
grid[(x, mid+3)].set_fg(Color::Default);
}
let x = write_string_to_grid(&format!("Subject: {}", envelope.get_subject()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, mid+4), set_y(bottom_right, mid+4)));
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, mid+4), set_y(bottom_right, mid+4)));
for x in x..=get_x(bottom_right) {
grid[(x, mid+4)].set_ch(' ');
grid[(x, mid+4)].set_bg(Color::Default);
grid[(x, mid+4)].set_fg(Color::Default);
}
let x = write_string_to_grid(&format!("Message-ID: {}", envelope.get_message_id_raw()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, mid+5), set_y(bottom_right, mid+5)));
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, mid+5), set_y(bottom_right, mid+5)));
for x in x..=get_x(bottom_right) {
grid[(x, mid+5)].set_ch(' ');
grid[(x, mid+5)].set_bg(Color::Default);
@@ -588,7 +608,7 @@ impl AccountMenu {
let highlight = self.cursor.map(|(x,_)| x == a.index).unwrap_or(false);
-
+
let mut parents: Vec<Option<usize>> = vec!(None; a.entries.len());
for (idx, e) in a.entries.iter().enumerate() {
@@ -648,9 +668,9 @@ impl AccountMenu {
};
let color_fg = if highlight {
if idx > 1 && self.cursor.unwrap().1 == idx - 2 {
- Color::Byte(233)
+ Color::Byte(233)
} else {
- Color::Byte(15)
+ Color::Byte(15)
}
} else {
Color::Default
@@ -658,19 +678,19 @@ impl AccountMenu {
let color_bg = if highlight {
if idx > 1 && self.cursor.unwrap().1 == idx - 2 {
- Color::Byte(15)
+ Color::Byte(15)
} else {
- Color::Byte(233)
+ Color::Byte(233)
}
} else {
Color::Default
};
let x = write_string_to_grid(&s,
- grid,
- color_fg,
- color_bg,
- (set_y(upper_left, y), bottom_right));
+ grid,
+ color_fg,
+ color_bg,
+ (set_y(upper_left, y), bottom_right));
if highlight && idx > 1 && self.cursor.unwrap().1 == idx - 2 {
change_colors(grid, ((x, y),(get_x(bottom_right)+1, y)), color_fg , color_bg);
diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs
index 569b31e6..3f85cc0e 100644
--- a/src/ui/components/mod.rs
+++ b/src/ui/components/mod.rs
@@ -19,6 +19,12 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
+/*!
+ Components are ways to handle application data. They can draw on the terminal and receive events, but also do other stuff as well. (For example, see the `notifications` module.)
+
+ See the `Component` Trait for more details.
+ */
+
pub mod utilities;
pub mod mail;
pub mod notifications;
@@ -78,7 +84,7 @@ pub trait Component {
}
}
-/// Copy Area src to dest
+/// Copy a source `Area` to a destination.
pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area, src: Area) {
if !is_valid_area!(dest) || !is_valid_area!(src) {
eprintln!("BUG: Invalid areas in copy_area:\n src: {:?}\n dest: {:?}", src, dest);
@@ -104,6 +110,7 @@ pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area,
}
}
+/// Change foreground and background colors in an `Area`
pub fn change_colors(grid: &mut CellBuffer, area: Area, fg_color: Color, bg_color: Color) {
if !is_valid_area!(area) {
eprintln!("BUG: Invalid area in change_colors:\n area: {:?}", area);
@@ -118,6 +125,7 @@ pub fn change_colors(grid: &mut CellBuffer, area: Area, fg_color: Color, bg_colo
}
+/// Write an `&str` to a `CellBuffer` in a specified `Area` with the passed colors.
fn write_string_to_grid(s: &str, grid: &mut CellBuffer, fg_color: Color, bg_color: Color, area: Area) -> usize {
let bounds = grid.size();
let upper_left = upper_left!(area);
@@ -144,6 +152,7 @@ fn write_string_to_grid(s: &str, grid: &mut CellBuffer, fg_color: Color, bg_colo
x
}
+/// Completely clear an `Area` with an empty char and the terminal's default colors.
fn clear_area(grid: &mut CellBuffer, area: Area) {
let upper_left = upper_left!(area);
let bottom_right = bottom_right!(area);
diff --git a/src/ui/components/notifications.rs b/src/ui/components/notifications.rs
index 61b01556..31497f08 100644
--- a/src/ui/components/notifications.rs
+++ b/src/ui/components/notifications.rs
@@ -1,7 +1,12 @@
+/*!
+ Notification handling components.
+ */
use notify_rust::Notification as notify_Notification;
use ui::*;
use ui::components::*;
+
+/// Passes notifications to the OS using the XDG specifications.
pub struct XDGNotifications {}
impl Component for XDGNotifications {
diff --git a/src/ui/components/utilities.rs b/src/ui/components/utilities.rs
index 13c8054f..3324761c 100644
--- a/src/ui/components/utilities.rs
+++ b/src/ui/components/utilities.rs
@@ -1,3 +1,6 @@
+/*! Various useful components that can be used in a generic fashion.
+ */
+
use ui::components::*;
use ui::cells::*;
@@ -125,6 +128,7 @@ pub struct Pager {
content: CellBuffer,
}
+// TODO: Make the `new` method content agnostic.
impl Pager {
pub fn new(mail: &Envelope, pager_filter: Option<String>) -> Self {
let mut text = mail.get_body().get_text();
@@ -159,6 +163,20 @@ impl Pager {
content: content,
}
}
+ pub fn new_from_str(s: &str) -> Self {
+ let lines: Vec<&str> = s.trim().split('\n').collect();
+ let height = lines.len();
+ let width = lines.iter().map(|l| l.len()).max().unwrap_or(0);
+ let mut content = CellBuffer::new(width, height, Cell::with_char(' '));
+ Pager::print_string(&mut content, s);
+ Pager {
+ cursor_pos: 0,
+ height: height,
+ width: width,
+ dirty: true,
+ content: content,
+ }
+ }
pub fn print_string(content: &mut CellBuffer, s: &str) {
let lines: Vec<&str> = s.trim().split('\n').collect();
let width = lines.iter().map(|l| l.len()).max().unwrap_or(0);
diff --git a/src/ui/execute/mod.rs b/src/ui/execute/mod.rs
index 3aebe565..be949f4a 100644
--- a/src/ui/execute/mod.rs
+++ b/src/ui/execute/mod.rs
@@ -1,11 +1,13 @@
+/*! A parser module for user commands passed through the Ex mode.
+*/
use std;
use nom::digit;
named!(usize_c<usize>,
-map_res!(map_res!(ws!(digit), std::str::from_utf8), std::str::FromStr::from_str));
+ map_res!(map_res!(ws!(digit), std::str::from_utf8), std::str::FromStr::from_str));
named!(pub goto<usize>,
- preceded!(tag!("b "),
- call!(usize_c))
- );
+ preceded!(tag!("b "),
+ call!(usize_c))
+ );
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index d6a25b72..ce2ff32f 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -19,57 +19,41 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
+
+/*!
+ The UI module has an Entity-Component-System design. The System part, is also the application's state, so they're both merged in the `State` struct.
+
+ `State` owns all the Entities of the UI, which are currently plain Containers for `Component`s. In the application's main event loop, input is handed to the state in the form of `UIEvent` objects which traverse the entity graph. Components decide to handle each input or not.
+
+ Input is received in the main loop from threads which listen on the stdin for user input, observe folders for file changes etc. The relevant struct is `ThreadEvent`.
+ */
+
#[macro_use]
-pub mod position;
+mod position;
pub mod components;
-pub mod cells;
+mod cells;
#[macro_use]
mod execute;
use self::execute::goto;
-
-extern crate termion;
-extern crate melib;
-
-use std::collections::VecDeque;
-use std::fmt;
-
pub use self::position::*;
+use self::cells::*;
+pub use self::components::*;
+extern crate melib;
use melib::*;
-
use std;
+use std::io::{Write, };
+use std::collections::VecDeque;
+use std::fmt;
+extern crate termion;
use termion::{clear, style, cursor};
use termion::raw::IntoRawMode;
use termion::event::{Key as TermionKey, };
-
-use chan::Sender;
-
-
-use std::io::{Write, };
use termion::input::TermRead;
-use self::cells::*;
-pub use self::components::*;
-
-/* Color pairs; foreground && background. */
-/// Default color.
-pub static COLOR_PAIR_DEFAULT: i16 = 1;
-/// Highlighted cursor line in index view.
-pub static COLOR_PAIR_CURSOR: i16 = 2;
-/// Header colour in pager view.
-pub static COLOR_PAIR_HEADERS: i16 = 3;
-/// Indentation symbol color in index view.
-pub static COLOR_PAIR_THREAD_INDENT: i16 = 4;
-/// Line color for odd entries in index view.
-pub static COLOR_PAIR_THREAD_ODD: i16 = 5;
-/// Line color for even entries in index view.
-pub static COLOR_PAIR_THREAD_EVEN: i16 = 6;
-/// Line color for unread odd entries in index view.
-pub static COLOR_PAIR_UNREAD_ODD: i16 = 7;
-/// Line color for unread even entries in index view.
-pub static COLOR_PAIR_UNREAD_EVEN: i16 = 8;
+use chan::Sender;
/// `ThreadEvent` encapsulates all of the possible values we need to transfer between our threads
/// to the main process.
@@ -103,6 +87,7 @@ pub enum UIEventType {
}
+/// An event passed from `State` to its Entities.
#[derive(Debug)]
pub struct UIEvent {
pub id: u64,
@@ -124,6 +109,7 @@ impl fmt::Display for UIMode {
}
}
+/// An event notification that is passed to Entities for handling.
pub struct Notification {
title: String,
content: String,
@@ -131,6 +117,7 @@ pub struct Notification {
timestamp: std::time::Instant,
}
+/// A context container for loaded settings, accounts, UI changes, etc.
pub struct Context {
pub accounts: Vec<Account>,
settings: Settings,
@@ -149,6 +136,8 @@ impl Context {
}
+/// A State object to manage and own components and entities of the UI. `State` is responsible for
+/// managing the terminal and interfacing with `melib`
pub struct State<W: Write> {
cols: usize,
rows: usize,
@@ -285,24 +274,22 @@ impl<W: Write> State<W> {
pub fn register_entity(&mut self, entity: Entity) {
self.entities.push(entity);
}
+ /// Convert user commands to actions/method calls.
fn parse_command(&mut self, cmd: String) {
+ //TODO: Make ex mode useful
eprintln!("received command: {}", cmd);
let result = goto(&cmd.as_bytes()).to_full_result();
eprintln!("result is {:?}", result);
if let Ok(v) = result {
-
self.refresh_mailbox(0, v);
-
-
}
-
}
pub fn rcv_event(&mut self, event: UIEvent) {
match event.event_type {
- // Command type is only for the State itself.
+ // Command type is handled only by State.
UIEventType::Command(cmd) => {
self.parse_command(cmd);
return;
@@ -331,29 +318,8 @@ impl<W: Write> State<W> {
}
}
-pub fn convert_key(k: TermionKey ) -> Key {
- match k {
- TermionKey::Backspace => Key::Backspace,
- TermionKey::Left => Key::Left,
- TermionKey::Right => Key::Right,
- TermionKey::Up => Key::Up,
- TermionKey::Down => Key::Down,
- TermionKey::Home => Key::Home,
- TermionKey::End => Key::End,
- TermionKey::PageUp => Key::PageUp,
- TermionKey::PageDown => Key::PageDown,
- TermionKey::Delete => Key::Delete,
- TermionKey::Insert => Key::Insert,
- TermionKey::F(u) => Key::F(u),
- TermionKey::Char(c) => Key::Char(c),
- TermionKey::Alt(c) => Key::Alt(c),
- TermionKey::Ctrl(c) => Key::Ctrl(c),
- TermionKey::Null => Key::Null,
- TermionKey::Esc => Key::Esc,
- _ => Key::Char(' '),
- }
-}
+// TODO: Pass Ctrl C etc to the terminal.
#[derive(Debug)]
pub enum Key {
/// Backspace.
@@ -396,12 +362,36 @@ pub enum Key {
Esc,
}
-pub fn get_events<F>(stdin: std::io::Stdin, mut closure: F) where F: FnMut(Key) -> (){
+impl From<TermionKey> for Key {
+ fn from(k: TermionKey ) -> Self {
+ match k {
+ TermionKey::Backspace => Key::Backspace,
+ TermionKey::Left => Key::Left,
+ TermionKey::Right => Key::Right,
+ TermionKey::Up => Key::Up,
+ TermionKey::Down => Key::Down,
+ TermionKey::Home => Key::Home,
+ TermionKey::End => Key::End,
+ TermionKey::PageUp => Key::PageUp,
+ TermionKey::PageDown => Key::PageDown,
+ TermionKey::Delete => Key::Delete,
+ TermionKey::Insert => Key::Insert,
+ TermionKey::F(u) => Key::F(u),
+ TermionKey::Char(c) => Key::Char(c),
+ TermionKey::Alt(c) => Key::Alt(c),
+ TermionKey::Ctrl(c) => Key::Ctrl(c),
+ TermionKey::Null => Key::Null,
+ TermionKey::Esc => Key::Esc,
+ _ => Key::Char(' '),
+ }
+ }
+}
+
+pub fn get_events(stdin: std::io::Stdin, mut closure: impl FnMut(Key)) -> (){
let stdin = stdin.lock();
for c in stdin.keys() {
if let Ok(k) = c {
- let k = convert_key(k);
- closure(k);
+ closure(Key::from(k));
}
}
}
diff --git a/src/ui/position.rs b/src/ui/position.rs
index 0fe342e8..844e559f 100644
--- a/src/ui/position.rs
+++ b/src/ui/position.rs
@@ -1,3 +1,9 @@
+/*!
+ Simple type definitions and macro helper for a (x,y) position on the terminal and the areas they define.
+
+ An `Area` consists of two points: the upper left and bottom right corners.
+ */
+
/// A `(x, y)` position on screen.
pub type Pos = (usize, usize);
@@ -18,6 +24,7 @@ pub fn set_y(p: Pos, new_y: usize) -> Pos {
(p.0, new_y)
}
+/// An `Area` consists of two points: the upper left and bottom right corners.
pub type Area = (Pos, Pos);
#[macro_export]
@@ -25,15 +32,19 @@ macro_rules! upper_left { ($a:expr) => ( $a.0 ) }
#[macro_export]
macro_rules! bottom_right { ($a:expr) => ( $a.1 ) }
#[macro_export]
-macro_rules! is_valid_area { ($a:expr) => { {
- let upper_left = upper_left!($a);
- let bottom_right = bottom_right!($a);
- if get_y(upper_left) > get_y(bottom_right) || get_x(upper_left) > get_x(bottom_right) {
- false
- } else {
- true
+macro_rules! is_valid_area { ($a:expr) =>
+ {
+ {
+ let upper_left = upper_left!($a);
+ let bottom_right = bottom_right!($a);
+ if get_y(upper_left) > get_y(bottom_right) || get_x(upper_left) > get_x(bottom_right) {
+ false
+ } else {
+ true
+ }
}
- } } }
+ }
+}
/// A `(cols, rows)` size.
pub type Size = (usize, usize);
@@ -46,45 +57,3 @@ pub trait HasPosition {
fn origin(&self) -> Pos;
fn set_origin(&mut self, new_origin: Pos);
}
-
-/// A cursor position.
-pub struct Cursor {
- pos: Option<Pos>,
- last_pos: Option<Pos>,
-}
-
-impl Cursor {
- pub fn new() -> Cursor {
- Cursor {
- pos: None,
- last_pos: None,
- }
- }
-
- /// Checks whether the current and last coordinates are sequential and returns `true` if they
- /// are and `false` otherwise.
- pub fn is_seq(&self) -> bool {
- if let Some((cx, cy)) = self.pos {
- if let Some((lx, ly)) = self.last_pos {
- (lx + 1, ly) == (cx, cy)
- } else {
- false
- }
- } else {
- false
- }
- }
-
- pub fn pos(&self) -> Option<Pos> {
- self.pos
- }
-
- pub fn set_pos(&mut self, newpos: Option<Pos>) {
- self.last_pos = self.pos;
- self.pos = newpos;
- }
-
- pub fn invalidate_last_pos(&mut self) {
- self.last_pos = None;
- }
-}