This commit is contained in:
Alexandre Bury 2018-03-22 11:04:10 -07:00
parent 5c3c750033
commit 1ad515e5f0
47 changed files with 571 additions and 201 deletions

View File

@ -19,7 +19,11 @@ use cursive::views::Canvas;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
siv.add_layer(Canvas::new(()).with_draw(draw).fixed_size((20, 10))); siv.add_layer(
Canvas::new(())
.with_draw(draw)
.fixed_size((20, 10)),
);
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());

View File

@ -9,7 +9,11 @@ use cursive::traits::*;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
siv.add_layer(KeyCodeView::new(10).full_width().fixed_height(10)); siv.add_layer(
KeyCodeView::new(10)
.full_width()
.fixed_height(10),
);
siv.run(); siv.run();
} }

View File

@ -87,8 +87,11 @@ impl View for BufferView {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
// Print the end of the buffer // Print the end of the buffer
for (i, line) in for (i, line) in self.buffer
self.buffer.iter().rev().take(printer.size.y).enumerate() .iter()
.rev()
.take(printer.size.y)
.enumerate()
{ {
printer.print((0, printer.size.y - 1 - i), line); printer.print((0, printer.size.y - 1 - i), line);
} }

View File

@ -12,7 +12,10 @@ fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
let mut styled = StyledString::plain("Isn't "); let mut styled = StyledString::plain("Isn't ");
styled.append(StyledString::styled("that ", Color::Dark(BaseColor::Red))); styled.append(StyledString::styled(
"that ",
Color::Dark(BaseColor::Red),
));
styled.append(StyledString::styled( styled.append(StyledString::styled(
"cool?", "cool?",
Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold), Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),

View File

@ -64,7 +64,8 @@ impl Board {
} }
fn get_mut(&mut self, pos: Vec2) -> Option<&mut Cell> { fn get_mut(&mut self, pos: Vec2) -> Option<&mut Cell> {
self.cell_id(pos).map(move |i| &mut self.cells[i]) self.cell_id(pos)
.map(move |i| &mut self.cells[i])
} }
pub fn cell_id(&self, pos: Vec2) -> Option<usize> { pub fn cell_id(&self, pos: Vec2) -> Option<usize> {

View File

@ -189,7 +189,9 @@ impl cursive::view::View for BoardView {
Cell::Unknown => "[]", Cell::Unknown => "[]",
Cell::Flag => "()", Cell::Flag => "()",
Cell::Visible(n) => { Cell::Visible(n) => {
[" ", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8"][n] [
" ", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8"
][n]
} }
}; };

View File

@ -87,7 +87,11 @@ fn phase_2(s: &mut Cursive) {
// Let's prepare the progress bars... // Let's prepare the progress bars...
let mut linear = LinearLayout::vertical(); let mut linear = LinearLayout::vertical();
for c in &counters { for c in &counters {
linear.add_child(ProgressBar::new().max(n_max).with_value(c.clone())); linear.add_child(
ProgressBar::new()
.max(n_max)
.with_value(c.clone()),
);
} }
s.pop_layer(); s.pop_layer();

View File

@ -38,6 +38,10 @@ fn on_edit(siv: &mut Cursive, _content: &str, _cursor: usize) {
let matches = edit_1.get_content() == edit_2.get_content(); let matches = edit_1.get_content() == edit_2.get_content();
siv.call_on_id("match", |v: &mut TextView| { siv.call_on_id("match", |v: &mut TextView| {
v.set_content(if matches { "match" } else { "no match" }) v.set_content(if matches {
"match"
} else {
"no match"
})
}); });
} }

View File

@ -19,7 +19,9 @@ fn main() {
); );
// We'll add a find feature! // We'll add a find feature!
siv.add_layer(Dialog::info("Hint: press Ctrl-F to find in text!")); siv.add_layer(Dialog::info(
"Hint: press Ctrl-F to find in text!",
));
siv.add_global_callback(Event::CtrlChar('f'), |s| { siv.add_global_callback(Event::CtrlChar('f'), |s| {
// When Ctrl-F is pressed, show the Find popup. // When Ctrl-F is pressed, show the Find popup.

View File

@ -6,7 +6,8 @@ use cursive::views::{Dialog, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
// You can load a theme from a file at runtime for fast development. // You can load a theme from a file at runtime for fast development.
siv.load_theme_file("assets/style.toml").unwrap(); siv.load_theme_file("assets/style.toml")
.unwrap();
// Or you can directly load it from a string for easy deployment. // Or you can directly load it from a string for easy deployment.
// siv.load_theme(include_str!("../assets/style.toml")).unwrap(); // siv.load_theme(include_str!("../assets/style.toml")).unwrap();

View File

@ -8,7 +8,9 @@ fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
let layout = LinearLayout::vertical() let layout = LinearLayout::vertical()
.child(TextView::new("This is a dynamic theme example!")) .child(TextView::new(
"This is a dynamic theme example!",
))
.child(EditView::new().content("Woo! colors!").style( .child(EditView::new().content("Woo! colors!").style(
ColorStyle::new( ColorStyle::new(
Color::Rgb(200, 150, 150), Color::Rgb(200, 150, 150),

View File

@ -252,9 +252,11 @@ impl backend::Backend for Concrete {
position: self.mouse_position, position: self.mouse_position,
offset: Vec2::zero(), offset: Vec2::zero(),
}, },
BltEvent::KeyPressed { key, ctrl, shift } => { BltEvent::KeyPressed {
self.blt_keycode_to_ev(key, shift, ctrl) key,
} ctrl,
shift,
} => self.blt_keycode_to_ev(key, shift, ctrl),
// TODO: there's no Key::Shift/Ctrl for w/e reason // TODO: there's no Key::Shift/Ctrl for w/e reason
BltEvent::ShiftPressed => Event::Refresh, BltEvent::ShiftPressed => Event::Refresh,
BltEvent::ControlPressed => Event::Refresh, BltEvent::ControlPressed => Event::Refresh,

View File

@ -13,7 +13,9 @@ mod pan;
pub use self::pan::*; pub use self::pan::*;
fn split_i32(code: i32) -> Vec<u8> { fn split_i32(code: i32) -> Vec<u8> {
(0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect() (0..4)
.map(|i| ((code >> (8 * i)) & 0xFF) as u8)
.collect()
} }
fn fill_key_codes<F>(target: &mut HashMap<i32, Event>, f: F) fn fill_key_codes<F>(target: &mut HashMap<i32, Event>, f: F)

View File

@ -184,7 +184,9 @@ impl backend::Backend for Concrete {
// (Mouse move when a button is pressed). // (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move. // Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h"); print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout"); stdout()
.flush()
.expect("could not flush stdout");
Concrete { Concrete {
current_style: Cell::new(ColorPair::from_256colors(0, 0)), current_style: Cell::new(ColorPair::from_256colors(0, 0)),
@ -210,7 +212,9 @@ impl backend::Backend for Concrete {
fn finish(&mut self) { fn finish(&mut self) {
print!("\x1B[?1002l"); print!("\x1B[?1002l");
stdout().flush().expect("could not flush stdout"); stdout()
.flush()
.expect("could not flush stdout");
ncurses::endwin(); ncurses::endwin();
} }

View File

@ -153,7 +153,9 @@ impl backend::Backend for Concrete {
// (Mouse move when a button is pressed). // (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move. // Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h"); print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout"); stdout()
.flush()
.expect("could not flush stdout");
Concrete { Concrete {
current_style: Cell::new(ColorPair::from_256colors(0, 0)), current_style: Cell::new(ColorPair::from_256colors(0, 0)),
@ -176,7 +178,9 @@ impl backend::Backend for Concrete {
fn finish(&mut self) { fn finish(&mut self) {
print!("\x1B[?1002l"); print!("\x1B[?1002l");
stdout().flush().expect("could not flush stdout"); stdout()
.flush()
.expect("could not flush stdout");
pancurses::endwin(); pancurses::endwin();
} }

View File

@ -168,7 +168,11 @@ impl backend::Backend for Concrete {
} }
fn finish(&mut self) { fn finish(&mut self) {
print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1)); print!(
"{}{}",
termion::cursor::Show,
termion::cursor::Goto(1, 1)
);
print!( print!(
"{}[49m{}[39m{}", "{}[49m{}[39m{}",
27 as char, 27 as char,

View File

@ -119,7 +119,8 @@ impl Cursive {
/// Selects the menubar. /// Selects the menubar.
pub fn select_menubar(&mut self) { pub fn select_menubar(&mut self) {
self.menubar.take_focus(direction::Direction::none()); self.menubar
.take_focus(direction::Direction::none());
} }
/// Sets the menubar autohide feature. /// Sets the menubar autohide feature.
@ -480,7 +481,8 @@ impl Cursive {
pub fn reposition_layer( pub fn reposition_layer(
&mut self, layer: LayerPosition, position: Position &mut self, layer: LayerPosition, position: Position
) { ) {
self.screen_mut().reposition_layer(layer, position); self.screen_mut()
.reposition_layer(layer, position);
} }
// Handles a key event when it was ignored by the current view // Handles a key event when it was ignored by the current view
@ -507,7 +509,11 @@ impl Cursive {
fn layout(&mut self) { fn layout(&mut self) {
let size = self.screen_size(); let size = self.screen_size();
let offset = if self.menubar.autohide { 0 } else { 1 }; let offset = if self.menubar.autohide {
0
} else {
1
};
let size = size.saturating_sub((0, offset)); let size = size.saturating_sub((0, offset));
self.screen_mut().layout(size); self.screen_mut().layout(size);
} }
@ -525,7 +531,11 @@ impl Cursive {
let selected = self.menubar.receive_events(); let selected = self.menubar.receive_events();
// Print the stackview background before the menubar // Print the stackview background before the menubar
let offset = if self.menubar.autohide { 0 } else { 1 }; let offset = if self.menubar.autohide {
0
} else {
1
};
let id = self.active_screen; let id = self.active_screen;
let sv_printer = printer.offset((0, offset), !selected); let sv_printer = printer.offset((0, offset), !selected);
@ -609,7 +619,9 @@ impl Cursive {
} }
if let Event::Mouse { if let Event::Mouse {
event, position, .. event,
position,
..
} = event } = event
{ {
if event.grabs_focus() && !self.menubar.autohide if event.grabs_focus() && !self.menubar.autohide
@ -628,8 +640,14 @@ impl Cursive {
if self.menubar.receive_events() { if self.menubar.receive_events() {
self.menubar.on_event(event).process(self); self.menubar.on_event(event).process(self);
} else { } else {
let offset = if self.menubar.autohide { 0 } else { 1 }; let offset = if self.menubar.autohide {
match self.screen_mut().on_event(event.relativized((0, offset))) { 0
} else {
1
};
match self.screen_mut()
.on_event(event.relativized((0, offset)))
{
// If the event was ignored, // If the event was ignored,
// it is our turn to play with it. // it is our turn to play with it.
EventResult::Ignored => self.on_event(event), EventResult::Ignored => self.on_event(event),

View File

@ -351,7 +351,10 @@ impl Event {
where where
V: Into<Vec2>, V: Into<Vec2>,
{ {
if let Event::Mouse { ref mut offset, .. } = *self { if let Event::Mouse {
ref mut offset, ..
} = *self
{
*offset = *offset + top_left; *offset = *offset + top_left;
} }
} }

View File

@ -224,8 +224,16 @@ impl<'a> Printer<'a> {
self.with_low_border(invert, |s| { self.with_low_border(invert, |s| {
s.print(start + size.keep_x(), ""); s.print(start + size.keep_x(), "");
s.print(start + size, ""); s.print(start + size, "");
s.print_hline(start + (1, 0) + size.keep_y(), size.x - 1, ""); s.print_hline(
s.print_vline(start + (0, 1) + size.keep_x(), size.y - 1, ""); start + (1, 0) + size.keep_y(),
size.x - 1,
"",
);
s.print_vline(
start + (0, 1) + size.keep_x(),
size.y - 1,
"",
);
}); });
} }

View File

@ -1,6 +1,5 @@
//! Rectangles on the 2D character grid. //! Rectangles on the 2D character grid.
use std::ops::Add; use std::ops::Add;
use vec::Vec2; use vec::Vec2;
/// A non-empty rectangle on the 2D grid. /// A non-empty rectangle on the 2D grid.
@ -22,8 +21,10 @@ where
} }
} }
impl <T> Add<T> for Rect impl<T> Add<T> for Rect
where T: Into<Vec2> { where
T: Into<Vec2>,
{
type Output = Rect; type Output = Rect;
fn add(mut self, rhs: T) -> Self { fn add(mut self, rhs: T) -> Self {
@ -91,7 +92,10 @@ impl Rect {
} }
/// Adds the given offset to this rectangle. /// Adds the given offset to this rectangle.
pub fn offset<V>(&mut self, offset: V) where V: Into<Vec2> { pub fn offset<V>(&mut self, offset: V)
where
V: Into<Vec2>,
{
let offset = offset.into(); let offset = offset.into();
self.top_left = self.top_left + offset; self.top_left = self.top_left + offset;
self.bottom_right = self.bottom_right + offset; self.bottom_right = self.bottom_right + offset;

View File

@ -152,8 +152,10 @@ 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<_> = let rgb: Vec<_> = value
value.chars().map(|c| c as i16 - '0' as i16).collect(); .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( Some(Color::RgbLowRes(
rgb[0] as u8, rgb[0] as u8,

View File

@ -33,7 +33,10 @@ impl ColorStyle {
/// Application background, where no view is present. /// Application background, where no view is present.
pub fn background() -> Self { pub fn background() -> Self {
Self::new(PaletteColor::Background, PaletteColor::Background) Self::new(
PaletteColor::Background,
PaletteColor::Background,
)
} }
/// Color used by view shadows. Only background matters. /// Color used by view shadows. Only background matters.
@ -73,7 +76,10 @@ impl ColorStyle {
/// Highlight color for inactive views (not in focus). /// Highlight color for inactive views (not in focus).
pub fn highlight_inactive() -> Self { pub fn highlight_inactive() -> Self {
Self::new(PaletteColor::View, PaletteColor::HighlightInactive) Self::new(
PaletteColor::View,
PaletteColor::HighlightInactive,
)
} }
/// Return the color pair that this style represents. /// Return the color pair that this style represents.

View File

@ -62,14 +62,26 @@ pub(crate) fn load_table(palette: &mut Palette, table: &toml::value::Table) {
&mut palette[PaletteColor::Background], &mut palette[PaletteColor::Background],
table.get("background"), table.get("background"),
); );
load_color(&mut palette[PaletteColor::Shadow], table.get("shadow")); load_color(
load_color(&mut palette[PaletteColor::View], table.get("view")); &mut palette[PaletteColor::Shadow],
load_color(&mut palette[PaletteColor::Primary], table.get("primary")); table.get("shadow"),
);
load_color(
&mut palette[PaletteColor::View],
table.get("view"),
);
load_color(
&mut palette[PaletteColor::Primary],
table.get("primary"),
);
load_color( load_color(
&mut palette[PaletteColor::Secondary], &mut palette[PaletteColor::Secondary],
table.get("secondary"), table.get("secondary"),
); );
load_color(&mut palette[PaletteColor::Tertiary], table.get("tertiary")); load_color(
&mut palette[PaletteColor::Tertiary],
table.get("tertiary"),
);
load_color( load_color(
&mut palette[PaletteColor::TitlePrimary], &mut palette[PaletteColor::TitlePrimary],
table.get("title_primary"), table.get("title_primary"),
@ -134,9 +146,9 @@ fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
false false
} }
} }
toml::Value::Array(ref array) => { toml::Value::Array(ref array) => array
array.iter().any(|item| load_color(target, Some(item))) .iter()
} .any(|item| load_color(target, Some(item))),
_ => false, _ => false,
} }
} else { } else {

View File

@ -70,6 +70,10 @@ impl<'a> Iterator for LinesIterator<'a> {
let width = row.width; let width = row.width;
Some(Row { start, end, width }) Some(Row {
start,
end,
width,
})
} }
} }

View File

@ -47,7 +47,10 @@ where
} }
// Skip empty spans // Skip empty spans
if self.source.spans()[self.current_span].as_ref().is_empty() { if self.source.spans()[self.current_span]
.as_ref()
.is_empty()
{
self.current_span += 1; self.current_span += 1;
return self.next(); return self.next();
} }
@ -120,9 +123,13 @@ where
self.current_span += 1; self.current_span += 1;
// Skip empty spans // Skip empty spans
while let Some(true) = while let Some(true) = self.source
self.source.spans().get(self.current_span).map(|span| { .spans()
span.as_ref().resolve(self.source.source()).is_empty() .get(self.current_span)
.map(|span| {
span.as_ref()
.resolve(self.source.source())
.is_empty()
}) { }) {
self.current_span += 1; self.current_span += 1;
} }

View File

@ -76,8 +76,11 @@ where
self.width self.width
}; };
let mut chunks = let mut chunks = prefix(
prefix(&mut self.iter, allowed_width, &mut self.chunk_offset); &mut self.iter,
allowed_width,
&mut self.chunk_offset,
);
// println!("Chunks..: {:?}", chunks); // println!("Chunks..: {:?}", chunks);
@ -162,6 +165,9 @@ where
// TODO: merge consecutive segments of the same span // TODO: merge consecutive segments of the same span
Some(Row { segments, width }) Some(Row {
segments,
width,
})
} }
} }

View File

@ -8,7 +8,9 @@ fn input() -> StyledString {
text.append(StyledString::styled("didn't", Effect::Bold)); text.append(StyledString::styled("didn't", Effect::Bold));
text.append(StyledString::plain(" say ")); text.append(StyledString::plain(" say "));
text.append(StyledString::styled("half", Effect::Italic)); text.append(StyledString::styled("half", Effect::Italic));
text.append(StyledString::plain(" the things people say I did.")); text.append(StyledString::plain(
" the things people say I did.",
));
text.append(StyledString::plain("\n")); text.append(StyledString::plain("\n"));
text.append(StyledString::plain("\n")); text.append(StyledString::plain("\n"));
text.append(StyledString::plain(" - A. Einstein")); text.append(StyledString::plain(" - A. Einstein"));

View File

@ -139,8 +139,10 @@ Attention
==== ====
I *really* love __Cursive__!"; I *really* love __Cursive__!";
let spans = parse_spans(input); let spans = parse_spans(input);
let spans: Vec<_> = let spans: Vec<_> = spans
spans.iter().map(|span| span.resolve(input)).collect(); .iter()
.map(|span| span.resolve(input))
.collect();
// println!("{:?}", spans); // println!("{:?}", spans);
assert_eq!( assert_eq!(

View File

@ -1,5 +1,5 @@
use vec::Vec2;
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};
use vec::Vec2;
/// Four values representing each direction. /// Four values representing each direction.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -52,19 +52,28 @@ impl Margins {
} }
impl From<(usize, usize, usize, usize)> for Margins { impl From<(usize, usize, usize, usize)> for Margins {
fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Margins { fn from(
(left, right, top, bottom): (usize, usize, usize, usize)
) -> Margins {
Margins::new(left, right, top, bottom) Margins::new(left, right, top, bottom)
} }
} }
impl From<(i32, i32, i32, i32)> for Margins { impl From<(i32, i32, i32, i32)> for Margins {
fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Margins { fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Margins {
(left as usize, right as usize, top as usize, bottom as usize).into() (
left as usize,
right as usize,
top as usize,
bottom as usize,
).into()
} }
} }
impl From<((i32, i32), (i32, i32))> for Margins { impl From<((i32, i32), (i32, i32))> for Margins {
fn from(((left, right), (top, bottom)): ((i32, i32), (i32, i32))) -> Margins { fn from(
((left, right), (top, bottom)): ((i32, i32), (i32, i32))
) -> Margins {
(left, right, top, bottom).into() (left, right, top, bottom).into()
} }
} }
@ -131,5 +140,3 @@ impl Mul<usize> for Margins {
} }
} }
} }

View File

@ -14,13 +14,19 @@ impl Position {
/// Returns a position absolute on both axis. /// Returns a position absolute on both axis.
pub fn absolute<T: Into<Vec2>>(offset: T) -> Self { pub fn absolute<T: Into<Vec2>>(offset: T) -> Self {
let offset = offset.into(); let offset = offset.into();
Position::new(Offset::Absolute(offset.x), Offset::Absolute(offset.y)) Position::new(
Offset::Absolute(offset.x),
Offset::Absolute(offset.y),
)
} }
/// Returns a position relative to the parent on both axis. /// Returns a position relative to the parent on both axis.
pub fn parent<T: Into<XY<isize>>>(offset: T) -> Self { pub fn parent<T: Into<XY<isize>>>(offset: T) -> Self {
let offset = offset.into(); let offset = offset.into();
Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y)) Position::new(
Offset::Parent(offset.x),
Offset::Parent(offset.y),
)
} }
/// Computes the offset required to draw a view. /// Computes the offset required to draw a view.
@ -42,8 +48,10 @@ impl Position {
let parent = parent.into(); let parent = parent.into();
Vec2::new( Vec2::new(
self.x.compute_offset(size.x, available.x, parent.x), self.x
self.y.compute_offset(size.y, available.y, parent.y), .compute_offset(size.x, available.x, parent.x),
self.y
.compute_offset(size.y, available.y, parent.y),
) )
} }
} }
@ -73,9 +81,10 @@ impl Offset {
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),
Offset::Parent(offset) => { Offset::Parent(offset) => min(
min((parent as isize + offset) as usize, available - size) (parent as isize + offset) as usize,
} available - size,
),
} }
} }
} }
@ -90,11 +99,29 @@ mod tests {
#[test] #[test]
fn test_center() { fn test_center() {
let c = Position::center(); let c = Position::center();
assert_eq!(Vec2::new(2, 1), c.compute_offset((1, 1), (5, 3), (0, 0))); assert_eq!(
assert_eq!(Vec2::new(2, 0), c.compute_offset((1, 3), (5, 3), (0, 0))); Vec2::new(2, 1),
assert_eq!(Vec2::new(1, 1), c.compute_offset((3, 1), (5, 3), (0, 0))); c.compute_offset((1, 1), (5, 3), (0, 0))
assert_eq!(Vec2::new(0, 1), c.compute_offset((5, 1), (5, 3), (0, 0))); );
assert_eq!(Vec2::new(0, 0), c.compute_offset((5, 3), (5, 3), (0, 0))); assert_eq!(
assert_eq!(Vec2::new(0, 0), c.compute_offset((5, 3), (3, 1), (0, 0))); Vec2::new(2, 0),
c.compute_offset((1, 3), (5, 3), (0, 0))
);
assert_eq!(
Vec2::new(1, 1),
c.compute_offset((3, 1), (5, 3), (0, 0))
);
assert_eq!(
Vec2::new(0, 1),
c.compute_offset((5, 1), (5, 3), (0, 0))
);
assert_eq!(
Vec2::new(0, 0),
c.compute_offset((5, 3), (5, 3), (0, 0))
);
assert_eq!(
Vec2::new(0, 0),
c.compute_offset((5, 3), (3, 1), (0, 0))
);
} }
} }

View File

@ -91,8 +91,10 @@ impl ScrollBase {
// eprintln!("Setting heights: {} in {}", content_height, view_height); // eprintln!("Setting heights: {} in {}", content_height, view_height);
if self.scrollable() { if self.scrollable() {
self.start_line = self.start_line = min(
min(self.start_line, self.content_height - self.view_height); self.start_line,
self.content_height - self.view_height,
);
} else { } else {
self.start_line = 0; self.start_line = 0;
} }
@ -249,11 +251,16 @@ impl ScrollBase {
return; return;
} }
// Print the content in a sub_printer // Print the content in a sub_printer
let max_y = let max_y = min(
min(self.view_height, self.content_height - self.start_line); self.view_height,
self.content_height - self.start_line,
);
let w = if self.scrollable() { let w = if self.scrollable() {
// We have to remove the bar width and the padding. // We have to remove the bar width and the padding.
printer.size.x.saturating_sub(1 + self.right_padding) printer
.size
.x
.saturating_sub(1 + self.right_padding)
} else { } else {
printer.size.x printer.size.x
}; };
@ -305,7 +312,10 @@ impl ScrollBase {
/// Returns the height of the scrollbar thumb. /// Returns the height of the scrollbar thumb.
pub fn scrollbar_thumb_height(&self) -> usize { pub fn scrollbar_thumb_height(&self) -> usize {
max(1, self.view_height * self.view_height / self.content_height) max(
1,
self.view_height * self.view_height / self.content_height,
)
} }
/// Returns the y position of the scrollbar thumb. /// Returns the y position of the scrollbar thumb.

View File

@ -10,7 +10,9 @@ new_default!(ViewPath);
impl ViewPath { impl ViewPath {
/// Creates a new empty path. /// Creates a new empty path.
pub fn new() -> Self { pub fn new() -> Self {
ViewPath { path: Vec::new() } ViewPath {
path: Vec::new(),
}
} }
/// Creates a path from the given item. /// Creates a path from the given item.

View File

@ -91,7 +91,8 @@ pub trait ViewWrapper: 'static {
/// Wraps the `needs_relayout` method. /// Wraps the `needs_relayout` method.
fn wrap_needs_relayout(&self) -> bool { fn wrap_needs_relayout(&self) -> bool {
self.with_view(|v| v.needs_relayout()).unwrap_or(true) self.with_view(|v| v.needs_relayout())
.unwrap_or(true)
} }
} }

View File

@ -96,12 +96,20 @@ impl<T: View> BoxView<T> {
/// Wraps `view` in a new `BoxView` with fixed width. /// Wraps `view` in a new `BoxView` with fixed width.
pub fn with_fixed_width(width: usize, view: T) -> Self { pub fn with_fixed_width(width: usize, view: T) -> Self {
BoxView::new(SizeConstraint::Fixed(width), SizeConstraint::Free, view) BoxView::new(
SizeConstraint::Fixed(width),
SizeConstraint::Free,
view,
)
} }
/// Wraps `view` in a new `BoxView` with fixed height. /// Wraps `view` in a new `BoxView` with fixed height.
pub fn with_fixed_height(height: usize, view: T) -> Self { pub fn with_fixed_height(height: usize, view: T) -> Self {
BoxView::new(SizeConstraint::Free, SizeConstraint::Fixed(height), view) BoxView::new(
SizeConstraint::Free,
SizeConstraint::Fixed(height),
view,
)
} }
/// Wraps `view` in a `BoxView` which will take all available space. /// Wraps `view` in a `BoxView` which will take all available space.
@ -192,7 +200,8 @@ impl<T: View> ViewWrapper for BoxView<T> {
wrap_impl!(self.view: T); wrap_impl!(self.view: T);
fn wrap_required_size(&mut self, req: Vec2) -> Vec2 { fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
let req = self.size.zip_map(req, SizeConstraint::available); let req = self.size
.zip_map(req, SizeConstraint::available);
let child_size = self.view.required_size(req); let child_size = self.view.required_size(req);
let result = self.size let result = self.size
@ -234,58 +243,142 @@ mod tests {
fn min_size() { fn min_size() {
let mut min_w = DummyView.full_screen().min_width(5); let mut min_w = DummyView.full_screen().min_width(5);
assert_eq!(Vec2::new(5, 1), min_w.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(5, 10), min_w.required_size(Vec2::new(1, 10))); Vec2::new(5, 1),
assert_eq!(Vec2::new(10, 1), min_w.required_size(Vec2::new(10, 1))); min_w.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(10, 10), min_w.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(5, 10),
min_w.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(10, 1),
min_w.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(10, 10),
min_w.required_size(Vec2::new(10, 10))
);
let mut min_h = DummyView.full_screen().min_height(5); let mut min_h = DummyView.full_screen().min_height(5);
assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(1, 10), min_h.required_size(Vec2::new(1, 10))); Vec2::new(1, 5),
assert_eq!(Vec2::new(10, 5), min_h.required_size(Vec2::new(10, 1))); min_h.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(10, 10), min_h.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(1, 10),
min_h.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(10, 5),
min_h.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(10, 10),
min_h.required_size(Vec2::new(10, 10))
);
let mut min_s = DummyView.full_screen().min_size((5, 5)); let mut min_s = DummyView.full_screen().min_size((5, 5));
assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(5, 10), min_s.required_size(Vec2::new(1, 10))); Vec2::new(5, 5),
assert_eq!(Vec2::new(10, 5), min_s.required_size(Vec2::new(10, 1))); min_s.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(10, 10), min_s.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(5, 10),
min_s.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(10, 5),
min_s.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(10, 10),
min_s.required_size(Vec2::new(10, 10))
);
} }
#[test] #[test]
fn max_size() { fn max_size() {
let mut max_w = DummyView.full_screen().max_width(5); let mut max_w = DummyView.full_screen().max_width(5);
assert_eq!(Vec2::new(1, 1), max_w.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(1, 10), max_w.required_size(Vec2::new(1, 10))); Vec2::new(1, 1),
assert_eq!(Vec2::new(5, 1), max_w.required_size(Vec2::new(10, 1))); max_w.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(5, 10), max_w.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(1, 10),
max_w.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(5, 1),
max_w.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(5, 10),
max_w.required_size(Vec2::new(10, 10))
);
let mut max_h = DummyView.full_screen().max_height(5); let mut max_h = DummyView.full_screen().max_height(5);
assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(1, 5), max_h.required_size(Vec2::new(1, 10))); Vec2::new(1, 1),
assert_eq!(Vec2::new(10, 1), max_h.required_size(Vec2::new(10, 1))); max_h.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(10, 5), max_h.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(1, 5),
max_h.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(10, 1),
max_h.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(10, 5),
max_h.required_size(Vec2::new(10, 10))
);
let mut max_s = DummyView.full_screen().max_size((5, 5)); let mut max_s = DummyView.full_screen().max_size((5, 5));
assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(1, 5), max_s.required_size(Vec2::new(1, 10))); Vec2::new(1, 1),
assert_eq!(Vec2::new(5, 1), max_s.required_size(Vec2::new(10, 1))); max_s.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(5, 5), max_s.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(1, 5),
max_s.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(5, 1),
max_s.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(5, 5),
max_s.required_size(Vec2::new(10, 10))
);
} }
#[test] #[test]
fn full_screen() { fn full_screen() {
let mut full = DummyView.full_screen(); let mut full = DummyView.full_screen();
assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1))); assert_eq!(
assert_eq!(Vec2::new(1, 10), full.required_size(Vec2::new(1, 10))); Vec2::new(1, 1),
assert_eq!(Vec2::new(10, 1), full.required_size(Vec2::new(10, 1))); full.required_size(Vec2::new(1, 1))
assert_eq!(Vec2::new(10, 10), full.required_size(Vec2::new(10, 10))); );
assert_eq!(
Vec2::new(1, 10),
full.required_size(Vec2::new(1, 10))
);
assert_eq!(
Vec2::new(10, 1),
full.required_size(Vec2::new(10, 1))
);
assert_eq!(
Vec2::new(10, 10),
full.required_size(Vec2::new(10, 10))
);
} }
#[test] #[test]

View File

@ -248,7 +248,11 @@ impl Dialog {
pub fn buttons_mut<'a>( pub fn buttons_mut<'a>(
&'a mut self &'a mut self
) -> Box<'a + Iterator<Item = &'a mut Button>> { ) -> Box<'a + Iterator<Item = &'a mut Button>> {
Box::new(self.buttons.iter_mut().map(|b| &mut b.button.view)) Box::new(
self.buttons
.iter_mut()
.map(|b| &mut b.button.view),
)
} }
/// Returns currently focused element /// Returns currently focused element

View File

@ -367,7 +367,8 @@ impl EditView {
self.offset = 0; self.offset = 0;
self.set_cursor(len); self.set_cursor(len);
self.make_edit_cb().unwrap_or_else(Callback::dummy) self.make_edit_cb()
.unwrap_or_else(Callback::dummy)
} }
/// Get the current text. /// Get the current text.
@ -419,7 +420,8 @@ impl EditView {
self.keep_cursor_in_view(); self.keep_cursor_in_view();
self.make_edit_cb().unwrap_or_else(Callback::dummy) self.make_edit_cb()
.unwrap_or_else(Callback::dummy)
} }
/// Remove the character at the current cursor position. /// Remove the character at the current cursor position.
@ -434,7 +436,8 @@ impl EditView {
self.keep_cursor_in_view(); self.keep_cursor_in_view();
self.make_edit_cb().unwrap_or_else(Callback::dummy) self.make_edit_cb()
.unwrap_or_else(Callback::dummy)
} }
fn make_edit_cb(&self) -> Option<Callback> { fn make_edit_cb(&self) -> Option<Callback> {

View File

@ -58,7 +58,10 @@ impl<T: View + 'static> ViewWrapper for IdView<T> {
where where
F: FnOnce(&mut Self::V) -> R, F: FnOnce(&mut Self::V) -> R,
{ {
self.view.try_borrow_mut().ok().map(|mut v| f(&mut *v)) self.view
.try_borrow_mut()
.ok()
.map(|mut v| f(&mut *v))
} }
fn into_inner(mut self) -> Result<Self::V, Self> fn into_inner(mut self) -> Result<Self::V, Self>

View File

@ -81,8 +81,10 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
// eprintln!("Available: {}", self.available); // eprintln!("Available: {}", self.available);
let length = let length = min(
min(self.available, *child.size.get(self.orientation)); self.available,
*child.size.get(self.orientation),
);
// Allocated width // Allocated width
self.available = self.available.saturating_sub(length); self.available = self.available.saturating_sub(length);
@ -173,7 +175,9 @@ impl LinearLayout {
/// Returns a mutable reference to a child. /// Returns a mutable reference to a child.
pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> { pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> {
self.children.get_mut(i).map(|child| &mut *child.view) self.children
.get_mut(i)
.map(|child| &mut *child.view)
} }
// If the cache can be used, return the cached size. // If the cache can be used, return the cached size.
@ -222,21 +226,27 @@ impl LinearLayout {
} else { } else {
self.children.len() self.children.len()
}; };
Box::new(self.children[..end].iter_mut().enumerate().rev()) Box::new(
self.children[..end]
.iter_mut()
.enumerate()
.rev(),
)
} }
} }
} }
fn move_focus(&mut self, source: direction::Direction) -> EventResult { fn move_focus(&mut self, source: direction::Direction) -> EventResult {
let i = if let Some(i) = let i = if let Some(i) = source.relative(self.orientation).and_then(
source.relative(self.orientation).and_then(|rel| { |rel| {
// The iterator starts at the focused element. // The iterator starts at the focused element.
// We don't want that one. // We don't want that one.
self.iter_mut(true, rel) self.iter_mut(true, rel)
.skip(1) .skip(1)
.filter_map(|p| try_focus(p, source)) .filter_map(|p| try_focus(p, source))
.next() .next()
}) { },
) {
i i
} else { } else {
return EventResult::Ignored; return EventResult::Ignored;
@ -281,7 +291,9 @@ impl LinearLayout {
let child_size = item.child.size.get(self.orientation); let child_size = item.child.size.get(self.orientation);
if (item.offset + child_size > position) if (item.offset + child_size > position)
&& item.child.view.take_focus(direction::Direction::none()) && item.child
.view
.take_focus(direction::Direction::none())
{ {
// eprintln!("It's a match!"); // eprintln!("It's a match!");
self.focus = i; self.focus = i;
@ -348,7 +360,9 @@ impl View for LinearLayout {
// Every item has the same size orthogonal to the layout // Every item has the same size orthogonal to the layout
item.child.size.set_axis_from(o.swap(), &size); item.child.size.set_axis_from(o.swap(), &size);
item.child.view.layout(size.with_axis(o, item.length)); item.child
.view
.layout(size.with_axis(o, item.length));
} }
} }
@ -425,7 +439,11 @@ impl View for LinearLayout {
let mut overweight: Vec<(usize, usize)> = ideal_sizes let mut overweight: Vec<(usize, usize)> = ideal_sizes
.iter() .iter()
.map(|v| self.orientation.get(v)) .map(|v| self.orientation.get(v))
.zip(min_sizes.iter().map(|v| self.orientation.get(v))) .zip(
min_sizes
.iter()
.map(|v| self.orientation.get(v)),
)
.map(|(a, b)| a.saturating_sub(b)) .map(|(a, b)| a.saturating_sub(b))
.enumerate() .enumerate()
.collect(); .collect();
@ -512,7 +530,9 @@ impl View for LinearLayout {
); );
let item = iterator.nth(self.focus).unwrap(); let item = iterator.nth(self.focus).unwrap();
let offset = self.orientation.make_vec(item.offset, 0); let offset = self.orientation.make_vec(item.offset, 0);
item.child.view.on_event(event.relativized(offset)) item.child
.view
.on_event(event.relativized(offset))
}; };
match result { match result {
EventResult::Ignored => match event { EventResult::Ignored => match event {
@ -577,7 +597,11 @@ impl View for LinearLayout {
} }
fn important_area(&self, _: Vec2) -> Rect { fn important_area(&self, _: Vec2) -> Rect {
let mut iterator = ChildIterator::new(self.children.iter(), self.orientation, usize::max_value()); let mut iterator = ChildIterator::new(
self.children.iter(),
self.orientation,
usize::max_value(),
);
let item = iterator.nth(self.focus).unwrap(); let item = iterator.nth(self.focus).unwrap();
let rect = item.child.view.important_area(item.child.size); let rect = item.child.view.important_area(item.child.size);

View File

@ -93,8 +93,10 @@ impl ListView {
/// Adds a view to the end of the list. /// Adds a view to the end of the list.
pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) { pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) {
view.take_focus(direction::Direction::none()); view.take_focus(direction::Direction::none());
self.children self.children.push(ListChild::Row(
.push(ListChild::Row(label.to_string(), Box::new(view))); label.to_string(),
Box::new(view),
));
} }
/// Removes all children from this view. /// Removes all children from this view.
@ -166,7 +168,12 @@ impl ListView {
} else { } else {
self.children.len() self.children.len()
}; };
Box::new(self.children[..end].iter_mut().enumerate().rev()) Box::new(
self.children[..end]
.iter_mut()
.enumerate()
.rev(),
)
} }
} }
} }
@ -303,7 +310,8 @@ impl View for ListView {
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
self.last_size = size; self.last_size = size;
self.scrollbase.set_heights(size.y, self.children.len()); self.scrollbase
.set_heights(size.y, self.children.len());
// We'll show 2 columns: the labels, and the views. // We'll show 2 columns: the labels, and the views.
let label_width = self.children let label_width = self.children
@ -314,14 +322,21 @@ impl View for ListView {
.unwrap_or(0); .unwrap_or(0);
let spacing = 1; let spacing = 1;
let scrollbar_width = if self.children.len() > size.y { 2 } else { 0 }; let scrollbar_width = if self.children.len() > size.y {
2
} else {
0
};
let available = size.x let available = size.x
.saturating_sub(label_width + spacing + scrollbar_width); .saturating_sub(label_width + spacing + scrollbar_width);
debug!("Available: {}", available); debug!("Available: {}", available);
for child in self.children.iter_mut().filter_map(ListChild::view) { for child in self.children
.iter_mut()
.filter_map(ListChild::view)
{
child.layout(Vec2::new(available, 1)); child.layout(Vec2::new(available, 1));
} }
} }
@ -340,7 +355,8 @@ impl View for ListView {
} if position } if position
.checked_sub(offset) .checked_sub(offset)
.map(|position| { .map(|position| {
self.scrollbase.start_drag(position, self.last_size.x) self.scrollbase
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {
@ -375,7 +391,8 @@ impl View for ListView {
if let ListChild::Row(_, ref mut view) = self.children[self.focus] { if let ListChild::Row(_, ref mut view) = self.children[self.focus] {
// If self.focus < self.scrollbase.start_line, it means the focus is not // If self.focus < self.scrollbase.start_line, it means the focus is not
// in view. Something's fishy, so don't send the event. // in view. Something's fishy, so don't send the event.
if let Some(y) = self.focus.checked_sub(self.scrollbase.start_line) if let Some(y) = self.focus
.checked_sub(self.scrollbase.start_line)
{ {
let offset = (labels_width + 1, y); let offset = (labels_width + 1, y);
let result = view.on_event(event.relativized(offset)); let result = view.on_event(event.relativized(offset));
@ -399,12 +416,10 @@ impl View for ListView {
Event::Key(Key::PageDown) => { Event::Key(Key::PageDown) => {
self.move_focus(10, direction::Direction::up()) self.move_focus(10, direction::Direction::up())
} }
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => { Event::Key(Key::Home) | Event::Ctrl(Key::Home) => self.move_focus(
self.move_focus( usize::max_value(),
usize::max_value(), direction::Direction::back(),
direction::Direction::back(), ),
)
}
Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus( Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus(
usize::max_value(), usize::max_value(),
direction::Direction::front(), direction::Direction::front(),
@ -457,7 +472,10 @@ impl View for ListView {
&mut self, selector: &Selector, &mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>, mut callback: Box<FnMut(&mut Any) + 'a>,
) { ) {
for view in self.children.iter_mut().filter_map(ListChild::view) { for view in self.children
.iter_mut()
.filter_map(ListChild::view)
{
view.call_on_any(selector, Box::new(|any| callback(any))); view.call_on_any(selector, Box::new(|any| callback(any)));
} }
} }

View File

@ -28,7 +28,9 @@ impl MenuPopup {
MenuPopup { MenuPopup {
menu: menu, menu: menu,
focus: 0, focus: 0,
scrollbase: ScrollBase::new().scrollbar_offset(1).right_padding(0), scrollbase: ScrollBase::new()
.scrollbar_offset(1)
.right_padding(0),
align: Align::top_left(), align: Align::top_left(),
on_dismiss: None, on_dismiss: None,
on_action: None, on_action: None,
@ -137,13 +139,12 @@ impl MenuPopup {
fn make_subtree_cb(&self, tree: &Rc<MenuTree>) -> EventResult { fn make_subtree_cb(&self, tree: &Rc<MenuTree>) -> EventResult {
let tree = Rc::clone(tree); let tree = Rc::clone(tree);
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();
@ -250,13 +251,12 @@ impl View for MenuPopup {
fn required_size(&mut self, req: Vec2) -> Vec2 { fn required_size(&mut self, req: Vec2) -> Vec2 {
// 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();
let scrolling = req.y < h; let scrolling = req.y < h;
@ -318,7 +318,8 @@ impl View for MenuPopup {
&& position && position
.checked_sub(offset + (0, 1)) .checked_sub(offset + (0, 1))
.map(|position| { .map(|position| {
self.scrollbase.start_drag(position, self.last_size.x) self.scrollbase
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {
@ -397,7 +398,9 @@ impl View for MenuPopup {
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
self.last_size = size; self.last_size = size;
self.scrollbase self.scrollbase.set_heights(
.set_heights(size.y.saturating_sub(2), self.menu.children.len()); size.y.saturating_sub(2),
self.menu.children.len(),
);
} }
} }

View File

@ -237,7 +237,9 @@ fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc<MenuTree>) {
s.pop_layer(); s.pop_layer();
s.select_menubar(); s.select_menubar();
// Act as if we sent "Right" then "Down" // Act as if we sent "Right" then "Down"
s.menubar().on_event(Event::Key(Key::Right)).process(s); s.menubar()
.on_event(Event::Key(Key::Right))
.process(s);
if let EventResult::Consumed(Some(cb)) = if let EventResult::Consumed(Some(cb)) =
s.menubar().on_event(Event::Key(Key::Down)) s.menubar().on_event(Event::Key(Key::Down))
{ {
@ -248,7 +250,9 @@ fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc<MenuTree>) {
s.pop_layer(); s.pop_layer();
s.select_menubar(); s.select_menubar();
// Act as if we sent "Left" then "Down" // Act as if we sent "Left" then "Down"
s.menubar().on_event(Event::Key(Key::Left)).process(s); s.menubar()
.on_event(Event::Key(Key::Left))
.process(s);
if let EventResult::Consumed(Some(cb)) = if let EventResult::Consumed(Some(cb)) =
s.menubar().on_event(Event::Key(Key::Down)) s.menubar().on_event(Event::Key(Key::Down))
{ {

View File

@ -55,7 +55,10 @@ impl<T> RadioGroup<T> {
&mut self, value: T, label: S &mut self, value: T, label: S
) -> RadioButton<T> { ) -> RadioButton<T> {
let count = self.state.borrow().values.len(); let count = self.state.borrow().values.len();
self.state.borrow_mut().values.push(Rc::new(value)); self.state
.borrow_mut()
.values
.push(Rc::new(value));
RadioButton::new(Rc::clone(&self.state), count, label.into()) RadioButton::new(Rc::clone(&self.state), count, label.into())
} }

View File

@ -257,7 +257,8 @@ impl<T: 'static> SelectView<T> {
self.focus.set(focus - 1); self.focus.set(focus - 1);
} }
self.make_select_cb().unwrap_or_else(Callback::dummy) self.make_select_cb()
.unwrap_or_else(Callback::dummy)
} }
/// Chainable variant of add_item /// Chainable variant of add_item
@ -340,7 +341,8 @@ impl<T: 'static> SelectView<T> {
self.focus.set(i); self.focus.set(i);
self.scrollbase.scroll_to(i); self.scrollbase.scroll_to(i);
self.make_select_cb().unwrap_or_else(Callback::dummy) self.make_select_cb()
.unwrap_or_else(Callback::dummy)
} }
/// Sets the selection to the given position. /// Sets the selection to the given position.
@ -374,7 +376,8 @@ impl<T: 'static> SelectView<T> {
let focus = self.focus(); let focus = self.focus();
self.scrollbase.scroll_to(focus); self.scrollbase.scroll_to(focus);
self.make_select_cb().unwrap_or_else(Callback::dummy) self.make_select_cb()
.unwrap_or_else(Callback::dummy)
} }
/// Moves the selection down by the given number of rows. /// Moves the selection down by the given number of rows.
@ -387,7 +390,8 @@ impl<T: 'static> SelectView<T> {
let focus = self.focus(); let focus = self.focus();
self.scrollbase.scroll_to(focus); self.scrollbase.scroll_to(focus);
self.make_select_cb().unwrap_or_else(Callback::dummy) self.make_select_cb()
.unwrap_or_else(Callback::dummy)
} }
// Low-level focus change. Does not fix scrollbase. // Low-level focus change. Does not fix scrollbase.
@ -398,7 +402,10 @@ impl<T: 'static> SelectView<T> {
// Low-level focus change. Does not fix scrollbase. // Low-level focus change. Does not fix scrollbase.
fn focus_down(&mut self, n: usize) { fn focus_down(&mut self, n: usize) {
let focus = min(self.focus() + n, self.items.len().saturating_sub(1)); let focus = min(
self.focus() + n,
self.items.len().saturating_sub(1),
);
self.focus.set(focus); self.focus.set(focus);
} }
@ -419,9 +426,8 @@ impl<T: 'static> SelectView<T> {
Event::Key(Key::PageUp) => self.focus_up(10), Event::Key(Key::PageUp) => self.focus_up(10),
Event::Key(Key::PageDown) => self.focus_down(10), Event::Key(Key::PageDown) => self.focus_down(10),
Event::Key(Key::Home) => self.focus.set(0), Event::Key(Key::Home) => self.focus.set(0),
Event::Key(Key::End) => { Event::Key(Key::End) => self.focus
self.focus.set(self.items.len().saturating_sub(1)) .set(self.items.len().saturating_sub(1)),
}
Event::Mouse { Event::Mouse {
event: MouseEvent::WheelDown, event: MouseEvent::WheelDown,
.. ..
@ -445,7 +451,8 @@ impl<T: 'static> SelectView<T> {
} if position } if position
.checked_sub(offset) .checked_sub(offset)
.map(|position| { .map(|position| {
self.scrollbase.start_drag(position, self.last_size.x) self.scrollbase
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {
@ -754,7 +761,8 @@ impl<T: 'static> View for SelectView<T> {
self.last_size = size; self.last_size = size;
if !self.popup { if !self.popup {
self.scrollbase.set_heights(size.y, self.items.len()); self.scrollbase
.set_heights(size.y, self.items.len());
} }
} }
} }

View File

@ -28,7 +28,10 @@ impl<T: View> ShadowView<T> {
} }
fn top_left_padding(&self) -> Vec2 { fn top_left_padding(&self) -> Vec2 {
Vec2::new(self.left_padding as usize, self.top_padding as usize) Vec2::new(
self.left_padding as usize,
self.top_padding as usize,
)
} }
/// If set, adds an empty column to the left of the view. /// If set, adds an empty column to the left of the view.
@ -56,7 +59,8 @@ impl<T: View> ViewWrapper for ShadowView<T> {
fn wrap_required_size(&mut self, req: Vec2) -> Vec2 { fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
// Make sure req >= offset // Make sure req >= offset
let offset = self.padding(); let offset = self.padding();
self.view.required_size(req.saturating_sub(offset)) + offset self.view
.required_size(req.saturating_sub(offset)) + offset
} }
fn wrap_layout(&mut self, size: Vec2) { fn wrap_layout(&mut self, size: Vec2) {
@ -78,8 +82,10 @@ impl<T: View> ViewWrapper for ShadowView<T> {
} }
// Skip the first row/column // Skip the first row/column
let offset = let offset = Vec2::new(
Vec2::new(self.left_padding as usize, self.top_padding as usize); self.left_padding as usize,
self.top_padding as usize,
);
let printer = &printer.offset(offset, true); let printer = &printer.offset(offset, true);
if printer.theme.shadow { if printer.theme.shadow {
let h = printer.size.y; let h = printer.size.y;

View File

@ -65,9 +65,13 @@ impl<T: View> ChildWrapper<T> {
fn unwrap(self) -> T { fn unwrap(self) -> T {
match self { match self {
// ShadowView::into_inner and Layer::into_inner can never fail. // ShadowView::into_inner and Layer::into_inner can never fail.
ChildWrapper::Shadow(shadow) => { ChildWrapper::Shadow(shadow) => shadow
shadow.into_inner().ok().unwrap().into_inner().ok().unwrap() .into_inner()
} .ok()
.unwrap()
.into_inner()
.ok()
.unwrap(),
ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(), ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(),
} }
} }
@ -212,7 +216,9 @@ impl StackView {
/// Returns a reference to the layer at the given position. /// Returns a reference to the layer at the given position.
pub fn get(&self, pos: LayerPosition) -> Option<&View> { pub fn get(&self, pos: LayerPosition) -> Option<&View> {
let i = self.get_index(pos); let i = self.get_index(pos);
self.layers.get(i).map(|child| child.view.get_inner()) self.layers
.get(i)
.map(|child| child.view.get_inner())
} }
/// Returns a mutable reference to the layer at the given position. /// Returns a mutable reference to the layer at the given position.
@ -325,7 +331,10 @@ impl StackView {
/// Returns the size for each layer in this view. /// Returns the size for each layer in this view.
pub fn layer_sizes(&self) -> Vec<Vec2> { pub fn layer_sizes(&self) -> Vec<Vec2> {
self.layers.iter().map(|layer| layer.size).collect() self.layers
.iter()
.map(|layer| layer.size)
.collect()
} }
fn get_index(&self, pos: LayerPosition) -> usize { fn get_index(&self, pos: LayerPosition) -> usize {

View File

@ -35,7 +35,9 @@ pub struct TextArea {
} }
fn make_rows(text: &str, width: usize) -> Vec<Row> { fn make_rows(text: &str, width: usize) -> Vec<Row> {
LinesIterator::new(text, width).show_spaces().collect() LinesIterator::new(text, width)
.show_spaces()
.collect()
} }
new_default!(TextArea); new_default!(TextArea);
@ -252,7 +254,8 @@ impl TextArea {
fn compute_rows(&mut self, size: Vec2) { fn compute_rows(&mut self, size: Vec2) {
self.soft_compute_rows(size); self.soft_compute_rows(size);
self.scrollbase.set_heights(size.y, self.rows.len()); self.scrollbase
.set_heights(size.y, self.rows.len());
} }
fn backspace(&mut self) { fn backspace(&mut self) {
@ -349,11 +352,16 @@ impl TextArea {
let last_byte = self.content[self.cursor..] let last_byte = self.content[self.cursor..]
.find('\n') .find('\n')
.map(|i| 1 + i + self.cursor); .map(|i| 1 + i + self.cursor);
let last_row = last_byte let last_row = last_byte.map_or(self.rows.len(), |last_byte| {
.map_or(self.rows.len(), |last_byte| self.row_at(last_byte)); self.row_at(last_byte)
});
let last_byte = last_byte.unwrap_or_else(|| self.content.len()); let last_byte = last_byte.unwrap_or_else(|| self.content.len());
debug!("Content: `{}` (len={})", self.content, self.content.len()); debug!(
"Content: `{}` (len={})",
self.content,
self.content.len()
);
debug!("start/end: {}/{}", first_byte, last_byte); debug!("start/end: {}/{}", first_byte, last_byte);
debug!("start/end rows: {}/{}", first_row, last_row); debug!("start/end rows: {}/{}", first_row, last_row);
@ -387,11 +395,14 @@ impl TextArea {
// Otherwise, replace stuff. // Otherwise, replace stuff.
let affected_rows = first_row..last_row; let affected_rows = first_row..last_row;
let replacement_rows = let replacement_rows = new_rows
new_rows.into_iter().map(|row| row.shifted(first_byte)); .into_iter()
self.rows.splice(affected_rows, replacement_rows); .map(|row| row.shifted(first_byte));
self.rows
.splice(affected_rows, replacement_rows);
self.fix_ghost_row(); self.fix_ghost_row();
self.scrollbase.set_heights(size.y, self.rows.len()); self.scrollbase
.set_heights(size.y, self.rows.len());
} }
} }
@ -404,10 +415,18 @@ impl View for TextArea {
// (we always keep a space at the end) // (we always keep a space at the end)
// And y = number of rows // And y = number of rows
debug!("{:?}", self.rows); debug!("{:?}", self.rows);
let scroll_width = if self.rows.len() > constraint.y { 1 } else { 0 }; let scroll_width = if self.rows.len() > constraint.y {
1
} else {
0
};
Vec2::new( Vec2::new(
scroll_width + 1 scroll_width + 1
+ self.rows.iter().map(|r| r.width).max().unwrap_or(1), + self.rows
.iter()
.map(|r| r.width)
.max()
.unwrap_or(1),
self.rows.len(), self.rows.len(),
) )
} }
@ -518,7 +537,8 @@ impl View for TextArea {
} if position } if position
.checked_sub(offset) .checked_sub(offset)
.map(|position| { .map(|position| {
self.scrollbase.start_drag(position, self.last_size.x) self.scrollbase
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {

View File

@ -305,7 +305,11 @@ impl TextView {
where where
S: Into<StyledString>, S: Into<StyledString>,
{ {
self.content.lock().unwrap().content.append(content.into()); self.content
.lock()
.unwrap()
.content
.append(content.into());
self.invalidate(); self.invalidate();
} }
@ -509,7 +513,8 @@ impl View for TextView {
} if position } if position
.checked_sub(offset) .checked_sub(offset)
.map(|position| { .map(|position| {
self.scrollbase.start_drag(position, self.last_size.x) self.scrollbase
.start_drag(position, self.last_size.x)
}) })
.unwrap_or(false) => .unwrap_or(false) =>
{ {