mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Apply rustfmt
This commit is contained in:
parent
08ab18608b
commit
4b095a0652
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
29
src/div.rs
29
src/div.rs
@ -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
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//
|
||||||
*/
|
|
||||||
|
28
src/lib.rs
28
src/lib.rs
@ -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),
|
||||||
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
67
src/theme.rs
67
src/theme.rs
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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`.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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) => {
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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, " ");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user