Apply rustfmt

This commit is contained in:
Alexandre Bury 2016-07-09 19:05:51 -07:00
parent 08ab18608b
commit 4b095a0652
20 changed files with 283 additions and 221 deletions

View File

@ -37,8 +37,7 @@ impl backend::Backend for NcursesBackend {
} }
fn init_color_style(style: theme::ColorStyle, fn init_color_style(style: theme::ColorStyle, foreground: &theme::Color,
foreground: &theme::Color,
background: &theme::Color) { background: &theme::Color) {
// TODO: build the color on the spot // TODO: build the color on the spot
@ -86,7 +85,9 @@ impl backend::Backend for NcursesBackend {
// Is it a UTF-8 starting point? // Is it a UTF-8 starting point?
if 32 <= ch && ch < 0x100 && ch != 127 { if 32 <= ch && ch < 0x100 && ch != 127 {
event::Event::Char(utf8::read_char(ch as u8, || ncurses::getch() as u8).unwrap()) event::Event::Char(utf8::read_char(ch as u8,
|| ncurses::getch() as u8)
.unwrap())
} else { } else {
event::Event::Key(parse_ncurses_char(ch)) event::Event::Key(parse_ncurses_char(ch))
} }
@ -110,12 +111,14 @@ fn parse_ncurses_char(ch: i32) -> event::Key {
// Tab is '\t' // Tab is '\t'
9 => event::Key::Tab, 9 => event::Key::Tab,
// Treat '\n' and the numpad Enter the same // Treat '\n' and the numpad Enter the same
10 | ncurses::KEY_ENTER => event::Key::Enter, 10 |
ncurses::KEY_ENTER => event::Key::Enter,
// This is the escape key when pressed by itself. // This is the escape key when pressed by itself.
// When used for control sequences, it should have been caught earlier. // When used for control sequences, it should have been caught earlier.
27 => event::Key::Esc, 27 => event::Key::Esc,
// `Backspace` sends 127, but Ctrl-H sends `Backspace` // `Backspace` sends 127, but Ctrl-H sends `Backspace`
127 | ncurses::KEY_BACKSPACE => event::Key::Backspace, 127 |
ncurses::KEY_BACKSPACE => event::Key::Backspace,
410 => event::Key::Resize, 410 => event::Key::Resize,
@ -204,7 +207,9 @@ fn parse_ncurses_char(ch: i32) -> event::Key {
ncurses::KEY_SNEXT => event::Key::ShiftPageDown, ncurses::KEY_SNEXT => event::Key::ShiftPageDown,
ncurses::KEY_SPREVIOUS => event::Key::ShiftPageUp, ncurses::KEY_SPREVIOUS => event::Key::ShiftPageUp,
// All Fn keys use the same enum with associated number // All Fn keys use the same enum with associated number
f @ ncurses::KEY_F1...ncurses::KEY_F12 => event::Key::F((f - ncurses::KEY_F0) as u8), f @ ncurses::KEY_F1...ncurses::KEY_F12 => {
event::Key::F((f - ncurses::KEY_F0) as u8)
}
f @ 277...288 => event::Key::ShiftF((f - 277) as u8), f @ 277...288 => event::Key::ShiftF((f - 277) as u8),
f @ 289...300 => event::Key::CtrlF((f - 289) as u8), f @ 289...300 => event::Key::CtrlF((f - 289) as u8),
f @ 301...312 => event::Key::CtrlShiftF((f - 300) as u8), f @ 301...312 => event::Key::CtrlShiftF((f - 300) as u8),
@ -213,7 +218,9 @@ fn parse_ncurses_char(ch: i32) -> event::Key {
// //
// TODO: shift and ctrl Fn keys // TODO: shift and ctrl Fn keys
// Avoids 8-10 (H,I,J), they are used by other commands. // Avoids 8-10 (H,I,J), they are used by other commands.
c @ 1...7 | c @ 11...25 => event::Key::CtrlChar((b'a' + (c - 1) as u8) as char), c @ 1...7 | c @ 11...25 => {
event::Key::CtrlChar((b'a' + (c - 1) as u8) as char)
}
_ => event::Key::Unknown(ch), _ => event::Key::Unknown(ch),
} }
} }
@ -234,8 +241,6 @@ fn find_closest(color: &theme::Color) -> u8 {
let b = 6 * b as u16 / 256; let b = 6 * b as u16 / 256;
(16 + 36 * r + 6 * g + b) as u8 (16 + 36 * r + 6 * g + b) as u8
} }
theme::Color::RgbLowRes(r, g, b) => { theme::Color::RgbLowRes(r, g, b) => (16 + 36 * r + 6 * g + b) as u8,
(16 + 36 * r + 6 * g + b) as u8
}
} }
} }

View File

@ -7,7 +7,6 @@ mod curses;
pub use self::curses::NcursesBackend; pub use self::curses::NcursesBackend;
pub trait Backend { pub trait Backend {
fn init(); fn init();
fn finish(); fn finish();
@ -16,8 +15,7 @@ pub trait Backend {
fn has_colors() -> bool; fn has_colors() -> bool;
fn init_color_style(style: theme::ColorStyle, fn init_color_style(style: theme::ColorStyle, foreground: &theme::Color,
foreground: &theme::Color,
background: &theme::Color); background: &theme::Color);
fn print_at((usize, usize), &str); fn print_at((usize, usize), &str);

View File

@ -1,16 +1,15 @@
/* // Integer division that rounds up.
/// Integer division that rounds up. // pub fn div_up_usize(p: usize, q: usize) -> usize {
pub fn div_up_usize(p: usize, q: usize) -> usize { // div_up(p as u32, q as u32) as usize
div_up(p as u32, q as u32) as usize // }
} //
// Integer division that rounds up.
/// Integer division that rounds up. // pub fn div_up(p: u32, q: u32) -> u32 {
pub fn div_up(p: u32, q: u32) -> u32 { // if p % q == 0 {
if p % q == 0 { // p / q
p / q // } else {
} else { // 1 + p / q
1 + p / q // }
} // }
} //
*/

View File

@ -153,8 +153,10 @@ impl Cursive {
true true
} }
/// Regularly redraws everything, even when no input is given. Between 0 and 1000. /// Sets the refresh rate, in frames per second.
/// ///
/// Regularly redraws everything, even when no input is given.
/// Between 0 and 1000.
/// Call with fps=0 to disable (default value). /// Call with fps=0 to disable (default value).
pub fn set_fps(&self, fps: u32) { pub fn set_fps(&self, fps: u32) {
B::set_refresh_rate(fps) B::set_refresh_rate(fps)
@ -199,8 +201,8 @@ impl Cursive {
/// Tries to find the view pointed to by the given path. /// Tries to find the view pointed to by the given path.
/// If the view is not found, or if it is not of the asked type, /// If the view is not found, or if it is not of the asked type,
/// it returns None. /// it returns None.
pub fn find<V: View + Any>(&mut self, selector: &Selector) -> Option<&mut V> { pub fn find<V: View + Any>(&mut self, sel: &Selector) -> Option<&mut V> {
match self.find_any(selector) { match self.find_any(sel) {
None => None, None => None,
Some(b) => b.downcast_mut::<V>(), Some(b) => b.downcast_mut::<V>(),
} }
@ -211,7 +213,9 @@ impl Cursive {
self.find(&Selector::Id(id)) self.find(&Selector::Id(id))
} }
/// Adds a global callback, triggered on the given key press when no view catches it. /// Adds a global callback.
///
/// Will be triggered on the given key press when no view catches it.
pub fn add_global_callback<F, E: ToEvent>(&mut self, event: E, cb: F) pub fn add_global_callback<F, E: ToEvent>(&mut self, event: E, cb: F)
where F: Fn(&mut Cursive) + 'static where F: Fn(&mut Cursive) + 'static
{ {
@ -267,21 +271,26 @@ impl Cursive {
}; };
// Draw the menubar? // Draw the menubar?
if self.menubar.visible() { if self.menubar.visible() {
let printer = printer.sub_printer(Vec2::zero(), printer.size, self.menubar.receive_events()); let printer = printer.sub_printer(Vec2::zero(),
printer.size,
self.menubar.receive_events());
self.menubar.draw(&printer); self.menubar.draw(&printer);
} }
let selected = self.menubar.receive_events(); let selected = self.menubar.receive_events();
self.screen_mut() let printer =
.draw(&printer.sub_printer(Vec2::new(0, offset), printer.size, !selected)); printer.sub_printer(Vec2::new(0, offset), printer.size, !selected);
self.screen_mut().draw(&printer);
B::refresh(); B::refresh();
} }
/// Runs the event loop. /// Runs the event loop.
/// ///
/// It will wait for user input (key presses) and trigger callbacks accordingly. /// It will wait for user input (key presses)
/// and trigger callbacks accordingly.
///
/// Blocks until quit() is called. /// Blocks until quit() is called.
pub fn run(&mut self) { pub fn run(&mut self) {
@ -315,7 +324,8 @@ impl Cursive {
} }
} else { } else {
match self.screen_mut().on_event(event) { match self.screen_mut().on_event(event) {
// If the event was ignored, it is our turn to play with it. // If the event was ignored,
// it is our turn to play with it.
EventResult::Ignored => self.on_event(event), EventResult::Ignored => self.on_event(event),
EventResult::Consumed(None) => (), EventResult::Consumed(None) => (),
EventResult::Consumed(Some(cb)) => cb(self), EventResult::Consumed(Some(cb)) => cb(self),

View File

@ -31,7 +31,7 @@ impl MenuItem {
pub fn is_subtree(&self) -> bool { pub fn is_subtree(&self) -> bool {
match *self { match *self {
MenuItem::Subtree(_,_) => true, MenuItem::Subtree(_, _) => true,
_ => false, _ => false,
} }
} }
@ -62,7 +62,8 @@ impl MenuTree {
self.with(|menu| menu.add_delimiter()) self.with(|menu| menu.add_delimiter())
} }
pub fn add_leaf<F: 'static + Fn(&mut Cursive)>(&mut self, title: &str, cb: F) { pub fn add_leaf<F: 'static + Fn(&mut Cursive)>(&mut self, title: &str,
cb: F) {
self.children self.children
.push(MenuItem::Leaf(title.to_string(), Rc::new(cb))); .push(MenuItem::Leaf(title.to_string(), Rc::new(cb)));
} }

View File

@ -1,3 +1,4 @@
use Cursive;
use menu::MenuTree; use menu::MenuTree;
use view::MenuPopup; use view::MenuPopup;
use view::KeyEventView; use view::KeyEventView;
@ -109,42 +110,18 @@ impl Menubar {
let menu = self.menus[self.focus].1.clone(); let menu = self.menus[self.focus].1.clone();
self.state = State::Submenu; self.state = State::Submenu;
let offset = (self.menus[..self.focus] let offset = (self.menus[..self.focus]
.iter() .iter()
.map(|&(ref title, _)| title.width() + 2) .map(|&(ref title, _)| title.width() + 2)
.fold(0, |a, b| a + b), .fold(0, |a, b| a + b),
if self.autohide { if self.autohide {
1 1
} else { } else {
0 0
}); });
// Since the closure will be called multiple times,
// we also need a new Rc on every call.
return Some(Rc::new(move |s| { return Some(Rc::new(move |s| {
// Since the closure will be called multiple times, show_child(s, offset, menu.clone())
// we also need a new Rc on every call.
s.screen_mut()
.add_layer_at(Position::absolute(offset),
KeyEventView::new(MenuPopup::new(menu.clone())
.on_dismiss(|s| s.select_menubar())
.on_action(|s| {
s.menubar().state = State::Inactive
}))
.register(Key::Right, |s| {
s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar();
s.menubar().on_event(Event::Key(Key::Right));
if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
cb(s);
}
})
.register(Key::Left, |s| {
s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar();
s.menubar().on_event(Event::Key(Key::Left));
if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
cb(s);
}
}));
})); }));
} }
_ => (), _ => (),
@ -152,3 +129,34 @@ impl Menubar {
None None
} }
} }
fn show_child(s: &mut Cursive, offset: (usize, usize), menu: Rc<MenuTree>) {
s.screen_mut()
.add_layer_at(Position::absolute(offset),
KeyEventView::new(MenuPopup::new(menu)
.on_dismiss(|s| s.select_menubar())
.on_action(|s| {
s.menubar().state = State::Inactive
}))
.register(Key::Right, |s| {
s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar();
s.menubar().on_event(Event::Key(Key::Right));
if let Some(cb) = s.menubar()
.on_event(Event::Key(Key::Down)) {
cb(s);
}
})
.register(Key::Left, |s| {
s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar();
s.menubar().on_event(Event::Key(Key::Left));
if let Some(cb) = s.menubar()
.on_event(Event::Key(Key::Down)) {
cb(s);
}
}));
}

View File

@ -44,8 +44,12 @@ impl Orientation {
/// For a vertical view, returns (Max(x),Sum(y)). /// For a vertical view, returns (Max(x),Sum(y)).
pub fn stack<'a, T: Iterator<Item = &'a Vec2>>(&self, iter: T) -> Vec2 { pub fn stack<'a, T: Iterator<Item = &'a Vec2>>(&self, iter: T) -> Vec2 {
match *self { match *self {
Orientation::Horizontal => iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(b)), Orientation::Horizontal => {
Orientation::Vertical => iter.fold(Vec2::zero(), |a, b| a.stack_vertical(b)), iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(b))
}
Orientation::Vertical => {
iter.fold(Vec2::zero(), |a, b| a.stack_vertical(b))
}
} }
} }
} }

View File

@ -6,7 +6,7 @@ use backend::Backend;
use B; use B;
use theme::{ColorStyle, Theme, Effect}; use theme::{ColorStyle, Effect, Theme};
use vec::{ToVec2, Vec2}; use vec::{ToVec2, Vec2};
/// Convenient interface to draw on a subset of the screen. /// Convenient interface to draw on a subset of the screen.
@ -136,20 +136,25 @@ impl Printer {
self.print_hline(start_v + (1, 0), size_v.x - 1, ""); self.print_hline(start_v + (1, 0), size_v.x - 1, "");
self.print_vline(start_v + (0, 1), size_v.y - 1, ""); self.print_vline(start_v + (0, 1), size_v.y - 1, "");
self.print_hline(start_v + (1, 0) + size_v.keep_y(), size_v.x - 1, ""); self.print_hline(start_v + (1, 0) + size_v.keep_y(),
self.print_vline(start_v + (0, 1) + size_v.keep_x(), size_v.y - 1, ""); size_v.x - 1,
"");
self.print_vline(start_v + (0, 1) + size_v.keep_x(),
size_v.y - 1,
"");
} }
pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) { pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) {
self.with_color(if selection { self.with_color(if selection {
if self.focused { if self.focused {
ColorStyle::Highlight ColorStyle::Highlight
} else { } else {
ColorStyle::HighlightInactive ColorStyle::HighlightInactive
} }
} else { } else {
ColorStyle::Primary ColorStyle::Primary
}, f); },
f);
} }
pub fn print_hdelim<T: ToVec2>(&self, start: T, len: usize) { pub fn print_hdelim<T: ToVec2>(&self, start: T, len: usize) {
@ -160,7 +165,8 @@ impl Printer {
} }
/// Returns a printer on a subset of this one's area. /// Returns a printer on a subset of this one's area.
pub fn sub_printer<S: ToVec2>(&self, offset: S, size: S, focused: bool) -> Printer { pub fn sub_printer<S: ToVec2>(&self, offset: S, size: S, focused: bool)
-> Printer {
let offset_v = offset.to_vec2(); let offset_v = offset.to_vec2();
Printer { Printer {
offset: self.offset + offset_v, offset: self.offset + offset_v,

View File

@ -112,32 +112,32 @@ impl Theme {
fn activate(&self) { fn activate(&self) {
// Initialize each color with the backend // Initialize each color with the backend
B::init_color_style(ColorStyle::Background, B::init_color_style(ColorStyle::Background,
&self.colors.view, &self.colors.view,
&self.colors.background); &self.colors.background);
B::init_color_style(ColorStyle::Shadow, B::init_color_style(ColorStyle::Shadow,
&self.colors.shadow, &self.colors.shadow,
&self.colors.shadow); &self.colors.shadow);
B::init_color_style(ColorStyle::Primary, B::init_color_style(ColorStyle::Primary,
&self.colors.primary, &self.colors.primary,
&self.colors.view); &self.colors.view);
B::init_color_style(ColorStyle::Secondary, B::init_color_style(ColorStyle::Secondary,
&self.colors.secondary, &self.colors.secondary,
&self.colors.view); &self.colors.view);
B::init_color_style(ColorStyle::Tertiary, B::init_color_style(ColorStyle::Tertiary,
&self.colors.tertiary, &self.colors.tertiary,
&self.colors.view); &self.colors.view);
B::init_color_style(ColorStyle::TitlePrimary, B::init_color_style(ColorStyle::TitlePrimary,
&self.colors.title_primary, &self.colors.title_primary,
&self.colors.view); &self.colors.view);
B::init_color_style(ColorStyle::TitleSecondary, B::init_color_style(ColorStyle::TitleSecondary,
&self.colors.title_secondary, &self.colors.title_secondary,
&self.colors.view); &self.colors.view);
B::init_color_style(ColorStyle::Highlight, B::init_color_style(ColorStyle::Highlight,
&self.colors.view, &self.colors.view,
&self.colors.highlight); &self.colors.highlight);
B::init_color_style(ColorStyle::HighlightInactive, B::init_color_style(ColorStyle::HighlightInactive,
&self.colors.view, &self.colors.view,
&self.colors.highlight_inactive); &self.colors.highlight_inactive);
} }
} }
@ -207,20 +207,25 @@ impl Palette {
load_color(&mut self.title_primary, table.get("title_primary")); load_color(&mut self.title_primary, table.get("title_primary"));
load_color(&mut self.title_secondary, table.get("title_secondary")); load_color(&mut self.title_secondary, table.get("title_secondary"));
load_color(&mut self.highlight, table.get("highlight")); load_color(&mut self.highlight, table.get("highlight"));
load_color(&mut self.highlight_inactive, table.get("highlight_inactive")); load_color(&mut self.highlight_inactive,
table.get("highlight_inactive"));
} }
} }
fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool { fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
if let Some(value) = value { if let Some(value) = value {
match *value { match *value {
toml::Value::String(ref value) => if let Some(color) = Color::parse(value) { toml::Value::String(ref value) => {
*target = color; if let Some(color) = Color::parse(value) {
true *target = color;
} else { true
false } else {
}, false
toml::Value::Array(ref array) => array.iter().any(|item| load_color(target, Some(item))), }
}
toml::Value::Array(ref array) => {
array.iter().any(|item| load_color(target, Some(item)))
}
_ => false, _ => false,
} }
} else { } else {
@ -245,8 +250,7 @@ pub enum Color {
RgbLowRes(u8, u8, u8), RgbLowRes(u8, u8, u8),
} }
impl Color { impl Color {}
}
/// Possible error returned when loading a theme. /// Possible error returned when loading a theme.
#[derive(Debug)] #[derive(Debug)]
@ -294,9 +298,12 @@ impl Color {
Some(Color::Rgb(r as u8, g as u8, b as u8)) Some(Color::Rgb(r as u8, g as u8, b as u8))
} else if value.len() == 3 { } else if value.len() == 3 {
// RGB values between 0 and 5 maybe? // RGB values between 0 and 5 maybe?
let rgb: Vec<_> = value.chars().map(|c| c as i16 - '0' as i16).collect(); let rgb: Vec<_> =
value.chars().map(|c| c as i16 - '0' as i16).collect();
if rgb.iter().all(|&i| i >= 0 && i < 6) { if rgb.iter().all(|&i| i >= 0 && i < 6) {
Some(Color::RgbLowRes(rgb[0] as u8, rgb[1] as u8, rgb[2] as u8)) Some(Color::RgbLowRes(rgb[0] as u8,
rgb[1] as u8,
rgb[2] as u8))
} else { } else {
None None
} }

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use theme::ColorStyle; use theme::ColorStyle;
use Cursive; use Cursive;
use vec::Vec2; use vec::Vec2;
use view::{View}; use view::View;
use event::*; use event::*;
use printer::Printer; use printer::Printer;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
@ -51,7 +51,9 @@ impl View for Button {
fn on_event(&mut self, event: Event) -> EventResult { fn on_event(&mut self, event: Event) -> EventResult {
match event { match event {
// 10 is the ascii code for '\n', that is the return key // 10 is the ascii code for '\n', that is the return key
Event::Key(Key::Enter) => EventResult::Consumed(Some(self.callback.clone())), Event::Key(Key::Enter) => {
EventResult::Consumed(Some(self.callback.clone()))
}
_ => EventResult::Ignored, _ => EventResult::Ignored,
} }
} }

View File

@ -55,7 +55,9 @@ impl EditView {
&self.content &self.content
} }
/// Sets the current content to the given value. Convenient chainable method. /// Sets the current content to the given value.
///
/// Convenient chainable method.
pub fn content(mut self, content: &str) -> Self { pub fn content(mut self, content: &str) -> Self {
self.set_content(content); self.set_content(content);
self self
@ -77,7 +79,6 @@ impl EditView {
impl View for EditView { impl View for EditView {
fn draw(&mut self, printer: &Printer) { fn draw(&mut self, printer: &Printer) {
// let style = if focused { color::HIGHLIGHT } else { color::HIGHLIGHT_INACTIVE };
assert!(printer.size.x == self.last_length); assert!(printer.size.x == self.last_length);
let width = self.content.width(); let width = self.content.width();
@ -92,16 +93,16 @@ impl View for EditView {
} else { } else {
let content = &self.content[self.offset..]; let content = &self.content[self.offset..];
let display_bytes = content.graphemes(true) let display_bytes = content.graphemes(true)
.scan(0, |w, g| { .scan(0, |w, g| {
*w += g.width(); *w += g.width();
if *w > self.last_length { if *w > self.last_length {
None None
} else { } else {
Some(g) Some(g)
} }
}) })
.map(|g| g.len()) .map(|g| g.len())
.fold(0, |a, b| a + b); .fold(0, |a, b| a + b);
let content = &content[..display_bytes]; let content = &content[..display_bytes];
@ -163,26 +164,26 @@ impl View for EditView {
Key::End => self.cursor = self.content.len(), Key::End => self.cursor = self.content.len(),
Key::Left if self.cursor > 0 => { Key::Left if self.cursor > 0 => {
let len = self.content[..self.cursor] let len = self.content[..self.cursor]
.graphemes(true) .graphemes(true)
.last() .last()
.unwrap() .unwrap()
.len(); .len();
self.cursor -= len; self.cursor -= len;
} }
Key::Right if self.cursor < self.content.len() => { Key::Right if self.cursor < self.content.len() => {
let len = self.content[self.cursor..] let len = self.content[self.cursor..]
.graphemes(true) .graphemes(true)
.next() .next()
.unwrap() .unwrap()
.len(); .len();
self.cursor += len; self.cursor += len;
} }
Key::Backspace if self.cursor > 0 => { Key::Backspace if self.cursor > 0 => {
let len = self.content[..self.cursor] let len = self.content[..self.cursor]
.graphemes(true) .graphemes(true)
.last() .last()
.unwrap() .unwrap()
.len(); .len();
self.cursor -= len; self.cursor -= len;
self.content.remove(self.cursor); self.content.remove(self.cursor);
} }
@ -196,18 +197,21 @@ impl View for EditView {
// Keep cursor in [offset, offset+last_length] by changing offset // Keep cursor in [offset, offset+last_length] by changing offset
// So keep offset in [last_length-cursor,cursor] // So keep offset in [last_length-cursor,cursor]
// Also call this on resize, but right now it is an event like any other // Also call this on resize,
// but right now it is an event like any other
if self.cursor < self.offset { if self.cursor < self.offset {
self.offset = self.cursor; self.offset = self.cursor;
} else { } else {
// So we're against the right wall. // So we're against the right wall.
// Let's find how much space will be taken by the selection (either a char, or _) // Let's find how much space will be taken by the selection
// (either a char, or _)
let c_len = self.content[self.cursor..] let c_len = self.content[self.cursor..]
.graphemes(true) .graphemes(true)
.map(|g| g.width()) .map(|g| g.width())
.next() .next()
.unwrap_or(1); .unwrap_or(1);
// Now, we have to fit self.content[..self.cursor] into self.last_length - c_len. // Now, we have to fit self.content[..self.cursor]
// into self.last_length - c_len.
let available = self.last_length - c_len; let available = self.last_length - c_len;
// Look at the content before the cursor (we will print its tail). // Look at the content before the cursor (we will print its tail).
// From the end, count the length until we reach `available`. // From the end, count the length until we reach `available`.

View File

@ -118,7 +118,7 @@ impl View for LinearLayout {
// On the axis given by the orientation, // On the axis given by the orientation,
// add the child size to the offset. // add the child size to the offset.
*self.orientation.get_ref(&mut offset) += self.orientation *self.orientation.get_ref(&mut offset) += self.orientation
.get(&child.size); .get(&child.size);
} }
} }
@ -127,9 +127,9 @@ impl View for LinearLayout {
// Look how mean we are: we offer the whole size to every child. // Look how mean we are: we offer the whole size to every child.
// As if they could get it all. // As if they could get it all.
let min_sizes: Vec<Vec2> = self.children let min_sizes: Vec<Vec2> = self.children
.iter_mut() .iter_mut()
.map(|child| Vec2::min(size, child.view.get_min_size(size))) .map(|child| Vec2::min(size, child.view.get_min_size(size)))
.collect(); .collect();
let min_size = self.orientation.stack(min_sizes.iter()); let min_size = self.orientation.stack(min_sizes.iter());
// Emulate 'non-strict inequality' on integers // Emulate 'non-strict inequality' on integers
@ -150,11 +150,12 @@ impl View for LinearLayout {
for (child, (child_size, extra)) in self.children for (child, (child_size, extra)) in self.children
.iter_mut() .iter_mut()
.zip(min_sizes.iter().zip(extras.iter())) { .zip(min_sizes.iter().zip(extras.iter())) {
let mut child_size = *child_size; let mut child_size = *child_size;
*self.orientation.get_ref(&mut child_size) += *extra; *self.orientation.get_ref(&mut child_size) += *extra;
*self.orientation.swap().get_ref(&mut child_size) = self.orientation.swap().get(&size); *self.orientation.swap().get_ref(&mut child_size) =
self.orientation.swap().get(&size);
child.size = child_size; child.size = child_size;
child.view.layout(child_size); child.view.layout(child_size);
} }
@ -163,9 +164,9 @@ impl View for LinearLayout {
fn get_min_size(&mut self, req: Vec2) -> Vec2 { fn get_min_size(&mut self, req: Vec2) -> Vec2 {
// First, make a naive scenario: everything will work fine. // First, make a naive scenario: everything will work fine.
let sizes: Vec<Vec2> = self.children let sizes: Vec<Vec2> = self.children
.iter_mut() .iter_mut()
.map(|view| view.view.get_min_size(req)) .map(|view| view.view.get_min_size(req))
.collect(); .collect();
self.orientation.stack(sizes.iter()) self.orientation.stack(sizes.iter())
@ -188,27 +189,34 @@ impl View for LinearLayout {
self.focus -= 1; self.focus -= 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::ShiftTab) if self.focus + 1 < self.children.len() => { Event::Key(Key::ShiftTab) if self.focus + 1 <
self.children.len() => {
self.focus += 1; self.focus += 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::Left) if self.orientation == Orientation::Horizontal && Event::Key(Key::Left) if self.orientation ==
Orientation::Horizontal &&
self.focus > 0 => { self.focus > 0 => {
self.focus -= 1; self.focus -= 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::Up) if self.orientation == Orientation::Vertical && Event::Key(Key::Up) if self.orientation ==
Orientation::Vertical &&
self.focus > 0 => { self.focus > 0 => {
self.focus -= 1; self.focus -= 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::Right) if self.orientation == Orientation::Horizontal && Event::Key(Key::Right) if self.orientation ==
self.focus + 1 < self.children.len() => { Orientation::Horizontal &&
self.focus + 1 <
self.children.len() => {
self.focus += 1; self.focus += 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::Down) if self.orientation == Orientation::Vertical && Event::Key(Key::Down) if self.orientation ==
self.focus + 1 < self.children.len() => { Orientation::Vertical &&
self.focus + 1 <
self.children.len() => {
self.focus += 1; self.focus += 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }

View File

@ -96,28 +96,28 @@ impl MenuPopup {
let tree = tree.clone(); let tree = tree.clone();
let max_width = 4 + let max_width = 4 +
self.menu self.menu
.children .children
.iter() .iter()
.map(Self::item_width) .map(Self::item_width)
.max() .max()
.unwrap_or(1); .unwrap_or(1);
let offset = Vec2::new(max_width, self.focus); let offset = Vec2::new(max_width, self.focus);
let action_cb = self.on_action.clone(); let action_cb = self.on_action.clone();
EventResult::with_cb(move |s| { EventResult::with_cb(move |s| {
let action_cb = action_cb.clone(); let action_cb = action_cb.clone();
s.screen_mut() s.screen_mut()
.add_layer_at(Position::parent(offset), .add_layer_at(Position::parent(offset),
KeyEventView::new(MenuPopup::new(tree.clone()) KeyEventView::new(MenuPopup::new(tree.clone())
.on_action(move |s| { .on_action(move |s| {
// This will happen when the subtree popup // This will happen when the subtree popup
// activates something; // activates something;
// First, remove ourselve. // First, remove ourselve.
s.pop_layer(); s.pop_layer();
if let Some(ref action_cb) = action_cb { if let Some(ref action_cb) = action_cb {
action_cb.clone()(s); action_cb.clone()(s);
} }
})) }))
.register(Key::Left, |s| s.pop_layer())); .register(Key::Left, |s| s.pop_layer()));
}) })
} }
} }
@ -126,9 +126,8 @@ impl View for MenuPopup {
fn draw(&mut self, printer: &Printer) { fn draw(&mut self, printer: &Printer) {
let h = self.menu.len(); let h = self.menu.len();
let offset = self.align.v.get_offset(h, printer.size.y); let offset = self.align.v.get_offset(h, printer.size.y);
let printer = &printer.sub_printer(Vec2::new(0, offset), let printer =
printer.size, &printer.sub_printer(Vec2::new(0, offset), printer.size, true);
true);
// Start with a box // Start with a box
printer.print_box(Vec2::new(0, 0), printer.size); printer.print_box(Vec2::new(0, 0), printer.size);
@ -164,11 +163,11 @@ impl View for MenuPopup {
// We can't really shrink our items here, so it's not flexible. // We can't really shrink our items here, so it's not flexible.
let w = 4 + let w = 4 +
self.menu self.menu
.children .children
.iter() .iter()
.map(Self::item_width) .map(Self::item_width)
.max() .max()
.unwrap_or(1); .unwrap_or(1);
let h = 2 + self.menu.children.len(); let h = 2 + self.menu.children.len();
@ -203,7 +202,7 @@ impl View for MenuPopup {
Event::Key(Key::End) => self.focus = self.menu.children.len() - 1, Event::Key(Key::End) => self.focus = self.menu.children.len() - 1,
Event::Key(Key::Right) if self.menu.children[self.focus] Event::Key(Key::Right) if self.menu.children[self.focus]
.is_subtree() => { .is_subtree() => {
return match self.menu.children[self.focus] { return match self.menu.children[self.focus] {
MenuItem::Subtree(_, ref tree) => { MenuItem::Subtree(_, ref tree) => {
self.make_subtree_cb(tree) self.make_subtree_cb(tree)
@ -213,7 +212,7 @@ impl View for MenuPopup {
}; };
} }
Event::Key(Key::Enter) if !self.menu.children[self.focus] Event::Key(Key::Enter) if !self.menu.children[self.focus]
.is_delimiter() => { .is_delimiter() => {
return match self.menu.children[self.focus] { return match self.menu.children[self.focus] {
MenuItem::Leaf(_, ref cb) => { MenuItem::Leaf(_, ref cb) => {

View File

@ -34,7 +34,7 @@ use event::{Event, EventResult};
use vec::Vec2; use vec::Vec2;
use printer::Printer; use printer::Printer;
pub use self::position::{Position, Offset}; pub use self::position::{Offset, Position};
pub use self::scroll::ScrollBase; pub use self::scroll::ScrollBase;
@ -64,7 +64,7 @@ pub trait View {
EventResult::Ignored EventResult::Ignored
} }
/// Returns the minimum size the view requires under the given restrictions. /// Returns the minimum size the view requires with the given restrictions.
fn get_min_size(&mut self, Vec2) -> Vec2 { fn get_min_size(&mut self, Vec2) -> Vec2 {
Vec2::new(1, 1) Vec2::new(1, 1)
} }

View File

@ -27,7 +27,8 @@ impl Position {
Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y)) Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y))
} }
pub fn compute_offset(&self, size: Vec2, available: Vec2, parent: Vec2) -> Vec2 { pub fn compute_offset(&self, size: Vec2, available: Vec2, parent: Vec2)
-> Vec2 {
Vec2::new(self.x.compute_offset(size.x, available.x, parent.x), Vec2::new(self.x.compute_offset(size.x, available.x, parent.x),
self.y.compute_offset(size.y, available.y, parent.y)) self.y.compute_offset(size.y, available.y, parent.y))
} }
@ -40,14 +41,15 @@ pub enum Offset {
/// Place top-left corner at the given absolute coordinates /// Place top-left corner at the given absolute coordinates
Absolute(usize), Absolute(usize),
/// Place top-left corner at the given offset from the previous layer's top-left corner. /// Offset from the previous layer's top-left corner.
/// ///
/// If this is the first layer, behaves like `Absolute`. /// If this is the first layer, behaves like `Absolute`.
Parent(usize), // TODO: use a signed vec for negative offset? Parent(usize), // TODO: use a signed vec for negative offset?
} }
impl Offset { impl Offset {
pub fn compute_offset(&self, size: usize, available: usize, parent: usize) -> usize { pub fn compute_offset(&self, size: usize, available: usize, parent: usize)
-> usize {
match *self { match *self {
Offset::Center => (available - size) / 2, Offset::Center => (available - size) / 2,
Offset::Absolute(offset) => min(offset, available - size), Offset::Absolute(offset) => min(offset, available - size),

View File

@ -34,7 +34,8 @@ impl ScrollBase {
self.content_height = content_height; self.content_height = content_height;
if self.scrollable() { if self.scrollable() {
self.start_line = min(self.start_line, self.content_height - self.view_height); self.start_line = min(self.start_line,
self.content_height - self.view_height);
} else { } else {
self.start_line = 0; self.start_line = 0;
} }
@ -76,7 +77,8 @@ impl ScrollBase {
/// Scroll down by the given number of line, never going further than the bottom of the view. /// Scroll down by the given number of line, never going further than the bottom of the view.
pub fn scroll_down(&mut self, n: usize) { pub fn scroll_down(&mut self, n: usize) {
self.start_line = min(self.start_line + n, self.content_height - self.view_height); self.start_line = min(self.start_line + n,
self.content_height - self.view_height);
} }
/// Scroll up by the given number of lines, never going above the top of the view. /// Scroll up by the given number of lines, never going above the top of the view.
@ -109,7 +111,8 @@ impl ScrollBase {
where F: Fn(&Printer, usize) where F: Fn(&Printer, usize)
{ {
// Print the content in a sub_printer // Print the content in a sub_printer
let max_y = min(self.view_height, self.content_height - self.start_line); let max_y = min(self.view_height,
self.content_height - self.start_line);
let w = if self.scrollable() { let w = if self.scrollable() {
printer.size.x - 1 // TODO: 2 printer.size.x - 1 // TODO: 2
} else { } else {
@ -118,7 +121,9 @@ impl ScrollBase {
for y in 0..max_y { for y in 0..max_y {
// Y is the actual coordinate of the line. // Y is the actual coordinate of the line.
// The item ID is then Y + self.start_line // The item ID is then Y + self.start_line
line_drawer(&printer.sub_printer(Vec2::new(0, y), Vec2::new(w, 1), true), line_drawer(&printer.sub_printer(Vec2::new(0, y),
Vec2::new(w, 1),
true),
y + self.start_line); y + self.start_line);
} }
@ -128,12 +133,15 @@ impl ScrollBase {
// We directly compute the size of the scrollbar (this allow use to avoid using floats). // We directly compute the size of the scrollbar (this allow use to avoid using floats).
// (ratio) * max_height // (ratio) * max_height
// Where ratio is ({start or end} / content.height) // Where ratio is ({start or end} / content.height)
let height = max(1, self.view_height * self.view_height / self.content_height); let height = max(1,
self.view_height * self.view_height /
self.content_height);
// Number of different possible positions // Number of different possible positions
let steps = self.view_height - height + 1; let steps = self.view_height - height + 1;
// Now // Now
let start = steps * self.start_line / (1 + self.content_height - self.view_height); let start = steps * self.start_line /
(1 + self.content_height - self.view_height);
let color = if printer.focused { let color = if printer.focused {
ColorStyle::Highlight ColorStyle::Highlight

View File

@ -130,9 +130,8 @@ impl<T: 'static> View for SelectView<T> {
let h = self.items.len(); let h = self.items.len();
let offset = self.align.v.get_offset(h, printer.size.y); let offset = self.align.v.get_offset(h, printer.size.y);
let printer = &printer.sub_printer(Vec2::new(0, offset), let printer =
printer.size, &printer.sub_printer(Vec2::new(0, offset), printer.size, true);
true);
self.scrollbase.draw(printer, |printer, i| { self.scrollbase.draw(printer, |printer, i| {
printer.with_selection(i == self.focus, |printer| { printer.with_selection(i == self.focus, |printer| {
@ -150,10 +149,10 @@ impl<T: 'static> View for SelectView<T> {
// So no matter what the horizontal requirements are, // So no matter what the horizontal requirements are,
// we'll still return our longest item. // we'll still return our longest item.
let w = self.items let w = self.items
.iter() .iter()
.map(|item| item.label.width()) .map(|item| item.label.width())
.max() .max()
.unwrap_or(1); .unwrap_or(1);
let h = self.items.len(); let h = self.items.len();
let scrolling = req.y < h; let scrolling = req.y < h;
@ -184,7 +183,9 @@ impl<T: 'static> View for SelectView<T> {
let cb = self.select_cb.as_ref().unwrap().clone(); let cb = self.select_cb.as_ref().unwrap().clone();
let v = self.selection(); let v = self.selection();
// We return a Callback Rc<|s| cb(s, &*v)> // We return a Callback Rc<|s| cb(s, &*v)>
return EventResult::Consumed(Some(Rc::new(move |s| cb(s, &*v)))); return EventResult::Consumed(Some(Rc::new(move |s| {
cb(s, &*v)
})));
} }
Event::Char(c) => { Event::Char(c) => {
// Starting from the current focus, // Starting from the current focus,
@ -194,10 +195,8 @@ impl<T: 'static> View for SelectView<T> {
// This is achieved by chaining twice the iterator // This is achieved by chaining twice the iterator
let iter = self.items.iter().chain(self.items.iter()); let iter = self.items.iter().chain(self.items.iter());
if let Some((i, _)) = iter.enumerate() if let Some((i, _)) = iter.enumerate()
.skip(self.focus + 1) .skip(self.focus + 1)
.find(|&(_, item)| { .find(|&(_, item)| item.label.starts_with(c)) {
item.label.starts_with(c)
}) {
// Apply modulo in case we have a hit // Apply modulo in case we have a hit
// from the chained iterator // from the chained iterator
self.focus = i % self.items.len(); self.focus = i % self.items.len();

View File

@ -23,8 +23,7 @@ impl<T: View> ShadowView<T> {
} }
fn padding(&self) -> (usize, usize) { fn padding(&self) -> (usize, usize) {
(1 + self.left_padding as usize, (1 + self.left_padding as usize, 1 + self.top_padding as usize)
1 + self.top_padding as usize)
} }
pub fn left_padding(mut self, value: bool) -> Self { pub fn left_padding(mut self, value: bool) -> Self {
@ -35,7 +34,6 @@ impl<T: View> ShadowView<T> {
self.top_padding = value; self.top_padding = value;
self self
} }
} }
impl<T: View> ViewWrapper for ShadowView<T> { impl<T: View> ViewWrapper for ShadowView<T> {
@ -54,7 +52,11 @@ impl<T: View> ViewWrapper for ShadowView<T> {
fn wrap_draw(&mut self, printer: &Printer) { fn wrap_draw(&mut self, printer: &Printer) {
// Skip the first row/column // Skip the first row/column
let printer = &printer.sub_printer(Vec2::new(self.left_padding as usize, self.top_padding as usize), printer.size, true); let printer =
&printer.sub_printer(Vec2::new(self.left_padding as usize,
self.top_padding as usize),
printer.size,
true);
// Draw the view background // Draw the view background
for y in 0..printer.size.y - 1 { for y in 0..printer.size.y - 1 {
@ -69,8 +71,8 @@ impl<T: View> ViewWrapper for ShadowView<T> {
let w = printer.size.x; let w = printer.size.x;
printer.with_color(ColorStyle::Shadow, |printer| { printer.with_color(ColorStyle::Shadow, |printer| {
printer.print_hline((1, h-1), w - 1, " "); printer.print_hline((1, h - 1), w - 1, " ");
printer.print_vline((w-1, 1), h - 1, " "); printer.print_vline((w - 1, 1), h - 1, " ");
}); });
} }
} }

View File

@ -44,8 +44,8 @@ impl StackView {
self.layers.push(Layer { self.layers.push(Layer {
// Skip padding for absolute/parent-placed views // Skip padding for absolute/parent-placed views
view: Box::new(ShadowView::new(view) view: Box::new(ShadowView::new(view)
.top_padding(position.y == Offset::Center) .top_padding(position.y == Offset::Center)
.left_padding(position.x == Offset::Center)), .left_padding(position.x == Offset::Center)),
size: Vec2::new(0, 0), size: Vec2::new(0, 0),
position: position, position: position,
virgin: true, virgin: true,
@ -68,11 +68,11 @@ impl View for StackView {
// Place the view // Place the view
// Center the view // Center the view
let offset = v.position let offset = v.position
.compute_offset(v.size, printer.size, previous); .compute_offset(v.size, printer.size, previous);
previous = offset; previous = offset;
v.view v.view
.draw(&printer.sub_printer(offset, v.size, i + 1 == last)); .draw(&printer.sub_printer(offset, v.size, i + 1 == last));
} }
}); });
} }

View File

@ -7,7 +7,7 @@ pub struct TrackedView<T: View> {
pub offset: Vec2, pub offset: Vec2,
} }
impl <T: View> TrackedView<T> { impl<T: View> TrackedView<T> {
pub fn new(view: T) -> Self { pub fn new(view: T) -> Self {
TrackedView { TrackedView {
view: view, view: view,