Add some doc

embed
Manos Pitsidianakis 2018-07-11 18:58:57 +03:00
parent ba8508b987
commit c141496038
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
7 changed files with 102 additions and 60 deletions

View File

@ -19,12 +19,13 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
mod ui;
pub mod ui;
use ui::*;
extern crate melib;
extern crate nom;
extern crate termion;
use melib::*;
pub use melib::*;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::thread;
@ -64,12 +65,13 @@ fn main() {
})));
}
eprintln!("account is {:?}", account);
let mut state = State::new(_stdout);
let a = Entity {component: Box::new(TextBox::new("a text box".to_string())) };
let a = Entity {component: Box::new(AccountMenu::new(&account)) };
let listing = MailListing::new(Mailbox::new_dummy());
let b = Entity { component: Box::new(listing) };
let window = Entity { component: Box::new(VSplit::new(a,b,90)) };
@ -77,11 +79,6 @@ fn main() {
state.render();
'main: loop {
let mailbox = &mut account[j];
//let mut index: Box<Window> = match *mailbox.as_ref().unwrap() {
// Ok(ref v) => Box::new(Index::new(v)),
// Err(ref v) => Box::new(ErrorWindow::new((*v).clone())),
//};
////eprintln!("{:?}", set);
match *mailbox.as_ref().unwrap() {
Ok(ref v) => {
state.rcv_event(UIEvent { id: 0, event_type: UIEventType::RefreshMailbox(v.clone()) });
@ -89,8 +86,6 @@ fn main() {
Err(_) => {},
};
//index.draw();
//
state.render();
'inner: loop {
@ -100,13 +95,12 @@ fn main() {
key @ Key::Char('j') | key @ Key::Char('k') => {
state.rcv_event(UIEvent { id: 0, event_type: UIEventType::Input(key)});
state.render();
},
},
key @ Key::Up | key @ Key::Down => {
state.rcv_event(UIEvent { id: 0, event_type: UIEventType::Input(key)});
state.render();
}
Key::Char('\n') => {
// index.handle_input(k);
state.rcv_event(UIEvent { id: 0, event_type: UIEventType::Input(Key::Char('\n'))});
state.render();
}
@ -115,9 +109,6 @@ fn main() {
state.render();
}
Key::F(_) => {
// if !index.handle_input(k) {
// break 'main;
// }
},
Key::Char('q') | Key::Char('Q') => {
break 'main;

View File

@ -21,6 +21,8 @@
extern crate config;
extern crate xdg;
extern crate serde;
use std::collections::HashMap;
use std::io;
use std::fs;

View File

@ -23,6 +23,7 @@ use mailbox::*;
use mailbox::backends::{RefreshEventConsumer, Backends};
use conf::AccountSettings;
use std::ops::{Index, IndexMut};
#[derive(Debug)]
pub struct Account {
name: String,
@ -60,6 +61,13 @@ impl Account {
pub fn watch(&self, r: RefreshEventConsumer) -> () {
self.backend.watch(r, &self.settings.folders);
}
/* This doesn't represent the number of correctly parsed mailboxes though */
pub fn len(&self) -> usize {
self.folders.len()
}
pub fn list_folders(&self) -> Vec<String> {
self.settings.folders.clone()
}
}
impl Index<usize> for Account {

View File

@ -63,7 +63,7 @@ impl Mailbox {
threaded_collection: threaded_collection,
})
}
pub fn get_length(&self) -> usize {
pub fn len(&self) -> usize {
self.collection.len()
}
pub fn get_threaded_mail(&self, i: usize) -> usize {

View File

@ -5,8 +5,10 @@ fn make_entry_string(e: &Envelope, idx: usize) -> String {
format!("{} {} {:.85}",idx,&e.get_datetime().format("%Y-%m-%d %H:%M:%S").to_string(),e.get_subject())
}
const max_width: usize = 500;
const MAX_WIDTH: usize = 500;
/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a
/// `Pager`.
pub struct MailListing {
cursor_pos: usize,
new_cursor_pos: usize,
@ -14,6 +16,7 @@ pub struct MailListing {
// sorting
content: CellBuffer,
dirty: bool,
/// If `self.pager` exists or not.
unfocused: bool,
// content (2-d vec of bytes) or Cells?
// current view on top of content
@ -25,13 +28,13 @@ pub struct MailListing {
impl MailListing {
pub fn new(mailbox: Mailbox) -> Self {
let length = mailbox.get_length();
let length = mailbox.len();
MailListing {
cursor_pos: 0,
new_cursor_pos: 0,
length: length,
content: CellBuffer::new(max_width, length+1, Cell::with_char(' ')),
content: CellBuffer::new(MAX_WIDTH, length+1, Cell::with_char(' ')),
dirty: false,
unfocused: false,
mailbox: mailbox,
@ -42,11 +45,14 @@ impl MailListing {
impl MailListing {
/// Draw only the list of `Envelope`s.
fn draw_list(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
if self.length == 0 {
write_string_to_grid(&format!("Folder `{}` is empty.", self.mailbox.path), grid, Color::Default, Color::Default, upper_left, upper_left);
return;
}
/* If cursor position has changed, remove the highlight from the previous position and
* apply it in the new one. */
if self.cursor_pos != self.new_cursor_pos {
for idx in [self.cursor_pos, self.new_cursor_pos].iter() {
let color = if self.cursor_pos == *idx { if *idx % 2 == 0 { Color::Byte(236) } else {Color::Default } } else { Color::Byte(246) };
@ -60,17 +66,10 @@ impl MailListing {
return;
}
let mut idx = 0;
for y in get_y(upper_left)..get_y(bottom_right) {
if idx == self.length {
for _y in y..get_y(bottom_right) {
for x in get_x(upper_left)..get_x(bottom_right) {
grid[(x,_y)].set_ch(' ');
grid[(x,_y)].set_bg(Color::Default);
grid[(x,_y)].set_fg(Color::Default);
}
}
clear_area(grid, set_y(upper_left, y), bottom_right);
break;
}
/* Write an entire line for each envelope entry. */
@ -87,37 +86,17 @@ impl MailListing {
}
}
/// Create a pager for the `Envelope` currently under the cursor.
fn draw_mail_view(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
//Pager
let ref mail = self.mailbox.collection[self.cursor_pos];
let height = get_y(bottom_right) - get_y(upper_left);
let width = get_x(bottom_right) - get_x(upper_left);
self.pager = Some(Pager::new(mail, height, width));
let pager = self.pager.as_mut().unwrap();
pager.dirty = true;
pager.draw(grid, upper_left,bottom_right);
/*
let text = mail.get_body().get_text();
let lines: Vec<&str> = text.trim().split('\n').collect();
let lines_length = lines.len();
for y in get_y(upper_left)..get_y(bottom_right) {
for x in get_x(upper_left)..get_x(bottom_right) {
grid[(x,y)].set_ch(' ');
grid[(x,y)].set_bg(Color::Default);
}
}
for (i, l) in lines.iter().enumerate() {
write_string_to_grid(l, grid, Color::Default, Color::Default, set_y(upper_left, get_y(upper_left)+i), bottom_right);
}
*/
}
fn redraw_cursor(&mut self, _upper_left: Pos, _bottom_right: Pos, _grid: &mut CellBuffer) {
}
}
impl Component for MailListing {
@ -135,7 +114,7 @@ impl Component for MailListing {
}
/* Render the mail body in a pager, basically copy what HSplit does */
let total_rows = get_y(bottom_right) - get_y(upper_left);
/* TODO: ratio in Configuration */
/* TODO: define ratio in Configuration file */
let bottom_entity_height = (80*total_rows )/100;
let mid = get_y(upper_left) + total_rows - bottom_entity_height;
@ -150,8 +129,17 @@ impl Component for MailListing {
if self.length == 0 {
return;
}
for i in get_x(upper_left)..get_x(bottom_right)+1 {
grid[(i, mid)].set_ch('─');
{
/* TODO: Move the box drawing business in separate functions */
if get_x(upper_left) > 0 {
if grid[(get_x(upper_left) - 1, mid)].ch() == VERT_BOUNDARY {
grid[(get_x(upper_left) - 1, mid)].set_ch(LIGHT_VERTICAL_AND_RIGHT);
}
}
for i in get_x(upper_left)..get_x(bottom_right)+1 {
grid[(i, mid)].set_ch('─');
}
}
let headers_height: usize = 6;
@ -200,13 +188,13 @@ impl Component for MailListing {
match event.event_type {
UIEventType::Input(Key::Up) => {
if self.cursor_pos > 0 {
self.new_cursor_pos -= 1;
self.new_cursor_pos -= 1;
self.dirty = true;
}
},
UIEventType::Input(Key::Down) => {
if self.length > 0 && self.cursor_pos < self.length - 1 {
self.new_cursor_pos += 1;
self.new_cursor_pos += 1;
self.dirty = true;
}
},
@ -237,3 +225,47 @@ impl Component for MailListing {
}
}
}
#[derive(Debug)]
pub struct AccountMenu {
entries: Vec<(usize, String)>,
dirty: bool,
}
impl AccountMenu {
pub fn new(account: &Account) -> Self{
let mut entries = Vec::with_capacity(account.len());
for (idx, acc) in account.list_folders().iter().enumerate() {
eprintln!("acc[{}] is {:?}", idx, acc);
entries.push((idx, acc.clone()));
}
AccountMenu {
entries: entries,
dirty: true,
}
}
}
impl Component for AccountMenu {
fn draw(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
eprintln!("reached accountmenu draw {:?}", self);
if !(self.dirty) {
return;
}
self.dirty = false;
let mut idx = 0;
for y in get_y(upper_left)..get_y(bottom_right) {
if idx == self.entries.len() {
break;
}
let s = format!("{:?}",self.entries[idx]);
eprintln!("wrote {} to menu", s);
write_string_to_grid(&s, grid, Color::Red, Color::Default, set_y(upper_left, y), bottom_right);
idx += 1;
}
}
fn process_event(&mut self, _event: &UIEvent, _queue: &mut VecDeque<UIEvent>) {
return;
}
}

View File

@ -55,12 +55,15 @@ const LIGHT_DOWN_AND_HORIZONTAL: char = '┬';
const LIGHT_UP_AND_HORIZONTAL: char = '┴';
/// `Entity` is a container for Components. Totally useless now so if it is not useful in the
/// future (ie hold some information, id or state) it should be removed.
pub struct Entity {
//queue: VecDeque,
pub component: Box<Component>, // more than one?
}
impl Entity {
/// Pass events to child component.
pub fn rcv_event(&mut self, event: &UIEvent, queue: &mut VecDeque<UIEvent>) {
self.component.process_event(&event, queue);
}
@ -72,16 +75,18 @@ impl fmt::Debug for Entity {
}
}
/// Types implementing this Trait can draw on the terminal and receive events.
/// If a type wants to skip drawing if it has not changed anything, it can hold some flag in its
/// fields (eg self.dirty = false) and act upon that in their `draw` implementation.
pub trait Component {
fn draw(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos);
fn process_event(&mut self, &UIEvent, &mut VecDeque<UIEvent>);
fn process_event(&mut self, event: &UIEvent, queue: &mut VecDeque<UIEvent>);
}
fn write_string_to_grid(s: &str, grid: &mut CellBuffer, fg_color: Color, bg_color: Color, upper_left: Pos, bottom_right: Pos) -> usize {
let (mut x, mut y) = upper_left;
for c in s.chars() {
eprintln!(" (x,y) = ({},{})", x,y);
grid[(x,y)].set_ch(c);
grid[(x,y)].set_fg(fg_color);
grid[(x,y)].set_bg(bg_color);

View File

@ -70,10 +70,11 @@ impl Component for HSplit {
}
}
/// A horizontally split in half container.
/// A vertically split in half container.
pub struct VSplit {
left: Entity,
right: Entity,
/// This is the width of the right container to the entire width.
ratio: usize, // right/(container width) * 100
}
@ -93,7 +94,7 @@ impl Component for VSplit {
let total_cols = get_x(bottom_right) - get_x(upper_left);
let right_entity_width = (self.ratio*total_cols )/100;
let mid = get_x(bottom_right) - right_entity_width;
if get_y(upper_left)> 1 {
let c = grid.get(mid, get_y(upper_left)-1).map(|a| a.ch()).unwrap_or_else(|| ' ');
match c {
@ -159,6 +160,9 @@ impl Component for TextBox {
}
}
/// A pager for text.
/// `Pager` holds its own content in its own `CellBuffer` and when `draw` is called, it draws the
/// current view of the text. It is responsible for scrolling etc.
pub struct Pager {
cursor_pos: usize,
rows: usize,
@ -192,7 +196,7 @@ impl Component for Pager {
fn draw(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
if !self.dirty {
return;
}
}
clear_area(grid, (get_x(upper_left), get_y(upper_left)-1), bottom_right);
self.dirty = false;
let mut inner_x = 0;