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() {
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());

View File

@ -9,7 +9,11 @@ use cursive::traits::*;
fn main() {
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();
}

View File

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

View File

@ -12,7 +12,10 @@ fn main() {
let mut siv = Cursive::new();
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(
"cool?",
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> {
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> {

View File

@ -189,7 +189,9 @@ impl cursive::view::View for BoardView {
Cell::Unknown => "[]",
Cell::Flag => "()",
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 mut linear = LinearLayout::vertical();
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();

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();
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!
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| {
// When Ctrl-F is pressed, show the Find popup.

View File

@ -6,7 +6,8 @@ use cursive::views::{Dialog, TextView};
fn main() {
let mut siv = Cursive::new();
// 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.
// siv.load_theme(include_str!("../assets/style.toml")).unwrap();

View File

@ -8,7 +8,9 @@ fn main() {
let mut siv = Cursive::new();
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(
ColorStyle::new(
Color::Rgb(200, 150, 150),

View File

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

View File

@ -13,7 +13,9 @@ mod pan;
pub use self::pan::*;
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)

View File

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

View File

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

View File

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

View File

@ -119,7 +119,8 @@ impl Cursive {
/// Selects the menubar.
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.
@ -480,7 +481,8 @@ impl Cursive {
pub fn reposition_layer(
&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
@ -507,7 +509,11 @@ impl Cursive {
fn layout(&mut self) {
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));
self.screen_mut().layout(size);
}
@ -525,7 +531,11 @@ impl Cursive {
let selected = self.menubar.receive_events();
// 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 sv_printer = printer.offset((0, offset), !selected);
@ -609,7 +619,9 @@ impl Cursive {
}
if let Event::Mouse {
event, position, ..
event,
position,
..
} = event
{
if event.grabs_focus() && !self.menubar.autohide
@ -628,8 +640,14 @@ impl Cursive {
if self.menubar.receive_events() {
self.menubar.on_event(event).process(self);
} else {
let offset = if self.menubar.autohide { 0 } else { 1 };
match self.screen_mut().on_event(event.relativized((0, offset))) {
let offset = if self.menubar.autohide {
0
} else {
1
};
match self.screen_mut()
.on_event(event.relativized((0, offset)))
{
// If the event was ignored,
// it is our turn to play with it.
EventResult::Ignored => self.on_event(event),

View File

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

View File

@ -224,8 +224,16 @@ impl<'a> Printer<'a> {
self.with_low_border(invert, |s| {
s.print(start + size.keep_x(), "");
s.print(start + size, "");
s.print_hline(start + (1, 0) + size.keep_y(), size.x - 1, "");
s.print_vline(start + (0, 1) + size.keep_x(), size.y - 1, "");
s.print_hline(
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.
use std::ops::Add;
use vec::Vec2;
/// A non-empty rectangle on the 2D grid.
@ -22,8 +21,10 @@ where
}
}
impl <T> Add<T> for Rect
where T: Into<Vec2> {
impl<T> Add<T> for Rect
where
T: Into<Vec2>,
{
type Output = Rect;
fn add(mut self, rhs: T) -> Self {
@ -91,7 +92,10 @@ impl Rect {
}
/// 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();
self.top_left = self.top_left + 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))
} else if value.len() == 3 {
// 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) {
Some(Color::RgbLowRes(
rgb[0] as u8,

View File

@ -33,7 +33,10 @@ impl ColorStyle {
/// Application background, where no view is present.
pub fn background() -> Self {
Self::new(PaletteColor::Background, PaletteColor::Background)
Self::new(
PaletteColor::Background,
PaletteColor::Background,
)
}
/// Color used by view shadows. Only background matters.
@ -73,7 +76,10 @@ impl ColorStyle {
/// Highlight color for inactive views (not in focus).
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.

View File

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

View File

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

View File

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

View File

@ -76,8 +76,11 @@ where
self.width
};
let mut chunks =
prefix(&mut self.iter, allowed_width, &mut self.chunk_offset);
let mut chunks = prefix(
&mut self.iter,
allowed_width,
&mut self.chunk_offset,
);
// println!("Chunks..: {:?}", chunks);
@ -162,6 +165,9 @@ where
// 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::plain(" say "));
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(" - A. Einstein"));

View File

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

View File

@ -1,5 +1,5 @@
use vec::Vec2;
use std::ops::{Add, Div, Mul, Sub};
use vec::Vec2;
/// Four values representing each direction.
#[derive(Clone, Copy)]
@ -52,19 +52,28 @@ impl 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)
}
}
impl From<(i32, i32, i32, i32)> for 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 {
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()
}
}
@ -131,5 +140,3 @@ impl Mul<usize> for Margins {
}
}
}

View File

@ -14,13 +14,19 @@ impl Position {
/// Returns a position absolute on both axis.
pub fn absolute<T: Into<Vec2>>(offset: T) -> Self {
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.
pub fn parent<T: Into<XY<isize>>>(offset: T) -> Self {
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.
@ -42,8 +48,10 @@ impl Position {
let parent = parent.into();
Vec2::new(
self.x.compute_offset(size.x, available.x, parent.x),
self.y.compute_offset(size.y, available.y, parent.y),
self.x
.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 {
Offset::Center => (available - size) / 2,
Offset::Absolute(offset) => min(offset, available - size),
Offset::Parent(offset) => {
min((parent as isize + offset) as usize, available - size)
}
Offset::Parent(offset) => min(
(parent as isize + offset) as usize,
available - size,
),
}
}
}
@ -90,11 +99,29 @@ mod tests {
#[test]
fn test_center() {
let c = Position::center();
assert_eq!(Vec2::new(2, 1), c.compute_offset((1, 1), (5, 3), (0, 0)));
assert_eq!(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)));
assert_eq!(
Vec2::new(2, 1),
c.compute_offset((1, 1), (5, 3), (0, 0))
);
assert_eq!(
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);
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 {
self.start_line = 0;
}
@ -249,11 +251,16 @@ impl ScrollBase {
return;
}
// 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() {
// 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 {
printer.size.x
};
@ -305,7 +312,10 @@ impl ScrollBase {
/// Returns the height of the scrollbar thumb.
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.

View File

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

View File

@ -91,7 +91,8 @@ pub trait ViewWrapper: 'static {
/// Wraps the `needs_relayout` method.
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.
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.
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.
@ -192,7 +200,8 @@ impl<T: View> ViewWrapper for BoxView<T> {
wrap_impl!(self.view: T);
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 result = self.size
@ -234,58 +243,142 @@ mod tests {
fn min_size() {
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!(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)));
assert_eq!(
Vec2::new(5, 1),
min_w.required_size(Vec2::new(1, 1))
);
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);
assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1)));
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)));
assert_eq!(
Vec2::new(1, 5),
min_h.required_size(Vec2::new(1, 1))
);
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));
assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1)));
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)));
assert_eq!(
Vec2::new(5, 5),
min_s.required_size(Vec2::new(1, 1))
);
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]
fn max_size() {
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!(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)));
assert_eq!(
Vec2::new(1, 1),
max_w.required_size(Vec2::new(1, 1))
);
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);
assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1)));
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)));
assert_eq!(
Vec2::new(1, 1),
max_h.required_size(Vec2::new(1, 1))
);
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));
assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1)));
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)));
assert_eq!(
Vec2::new(1, 1),
max_s.required_size(Vec2::new(1, 1))
);
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]
fn full_screen() {
let mut full = DummyView.full_screen();
assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1)));
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)));
assert_eq!(
Vec2::new(1, 1),
full.required_size(Vec2::new(1, 1))
);
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]

View File

@ -248,7 +248,11 @@ impl Dialog {
pub fn buttons_mut<'a>(
&'a mut self
) -> 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

View File

@ -367,7 +367,8 @@ impl EditView {
self.offset = 0;
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.
@ -419,7 +420,8 @@ impl EditView {
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.
@ -434,7 +436,8 @@ impl EditView {
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> {

View File

@ -58,7 +58,10 @@ impl<T: View + 'static> ViewWrapper for IdView<T> {
where
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>

View File

@ -81,8 +81,10 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
// eprintln!("Available: {}", self.available);
let length =
min(self.available, *child.size.get(self.orientation));
let length = min(
self.available,
*child.size.get(self.orientation),
);
// Allocated width
self.available = self.available.saturating_sub(length);
@ -173,7 +175,9 @@ impl LinearLayout {
/// Returns a mutable reference to a child.
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.
@ -222,21 +226,27 @@ impl LinearLayout {
} else {
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 {
let i = if let Some(i) =
source.relative(self.orientation).and_then(|rel| {
let i = if let Some(i) = source.relative(self.orientation).and_then(
|rel| {
// The iterator starts at the focused element.
// We don't want that one.
self.iter_mut(true, rel)
.skip(1)
.filter_map(|p| try_focus(p, source))
.next()
}) {
},
) {
i
} else {
return EventResult::Ignored;
@ -281,7 +291,9 @@ impl LinearLayout {
let child_size = item.child.size.get(self.orientation);
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!");
self.focus = i;
@ -348,7 +360,9 @@ impl View for LinearLayout {
// Every item has the same size orthogonal to the layout
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
.iter()
.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))
.enumerate()
.collect();
@ -512,7 +530,9 @@ impl View for LinearLayout {
);
let item = iterator.nth(self.focus).unwrap();
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 {
EventResult::Ignored => match event {
@ -577,7 +597,11 @@ impl View for LinearLayout {
}
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 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.
pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) {
view.take_focus(direction::Direction::none());
self.children
.push(ListChild::Row(label.to_string(), Box::new(view)));
self.children.push(ListChild::Row(
label.to_string(),
Box::new(view),
));
}
/// Removes all children from this view.
@ -166,7 +168,12 @@ impl ListView {
} else {
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) {
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.
let label_width = self.children
@ -314,14 +322,21 @@ impl View for ListView {
.unwrap_or(0);
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
.saturating_sub(label_width + spacing + scrollbar_width);
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));
}
}
@ -340,7 +355,8 @@ impl View for ListView {
} if position
.checked_sub(offset)
.map(|position| {
self.scrollbase.start_drag(position, self.last_size.x)
self.scrollbase
.start_drag(position, self.last_size.x)
})
.unwrap_or(false) =>
{
@ -375,7 +391,8 @@ impl View for ListView {
if let ListChild::Row(_, ref mut view) = self.children[self.focus] {
// If self.focus < self.scrollbase.start_line, it means the focus is not
// 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 result = view.on_event(event.relativized(offset));
@ -399,12 +416,10 @@ impl View for ListView {
Event::Key(Key::PageDown) => {
self.move_focus(10, direction::Direction::up())
}
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => {
self.move_focus(
usize::max_value(),
direction::Direction::back(),
)
}
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => self.move_focus(
usize::max_value(),
direction::Direction::back(),
),
Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus(
usize::max_value(),
direction::Direction::front(),
@ -457,7 +472,10 @@ impl View for ListView {
&mut self, selector: &Selector,
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 File

@ -28,7 +28,9 @@ impl MenuPopup {
MenuPopup {
menu: menu,
focus: 0,
scrollbase: ScrollBase::new().scrollbar_offset(1).right_padding(0),
scrollbase: ScrollBase::new()
.scrollbar_offset(1)
.right_padding(0),
align: Align::top_left(),
on_dismiss: None,
on_action: None,
@ -137,13 +139,12 @@ impl MenuPopup {
fn make_subtree_cb(&self, tree: &Rc<MenuTree>) -> EventResult {
let tree = Rc::clone(tree);
let max_width = 4
+ self.menu
.children
.iter()
.map(Self::item_width)
.max()
.unwrap_or(1);
let max_width = 4 + self.menu
.children
.iter()
.map(Self::item_width)
.max()
.unwrap_or(1);
let offset = Vec2::new(max_width, self.focus);
let action_cb = self.on_action.clone();
@ -250,13 +251,12 @@ impl View for MenuPopup {
fn required_size(&mut self, req: Vec2) -> Vec2 {
// We can't really shrink our items here, so it's not flexible.
let w = 4
+ self.menu
.children
.iter()
.map(Self::item_width)
.max()
.unwrap_or(1);
let w = 4 + self.menu
.children
.iter()
.map(Self::item_width)
.max()
.unwrap_or(1);
let h = 2 + self.menu.children.len();
let scrolling = req.y < h;
@ -318,7 +318,8 @@ impl View for MenuPopup {
&& position
.checked_sub(offset + (0, 1))
.map(|position| {
self.scrollbase.start_drag(position, self.last_size.x)
self.scrollbase
.start_drag(position, self.last_size.x)
})
.unwrap_or(false) =>
{
@ -397,7 +398,9 @@ impl View for MenuPopup {
fn layout(&mut self, size: Vec2) {
self.last_size = size;
self.scrollbase
.set_heights(size.y.saturating_sub(2), self.menu.children.len());
self.scrollbase.set_heights(
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.select_menubar();
// 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)) =
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.select_menubar();
// 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)) =
s.menubar().on_event(Event::Key(Key::Down))
{

View File

@ -55,7 +55,10 @@ impl<T> RadioGroup<T> {
&mut self, value: T, label: S
) -> RadioButton<T> {
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())
}

View File

@ -257,7 +257,8 @@ impl<T: 'static> SelectView<T> {
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
@ -340,7 +341,8 @@ impl<T: 'static> SelectView<T> {
self.focus.set(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.
@ -374,7 +376,8 @@ impl<T: 'static> SelectView<T> {
let focus = self.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.
@ -387,7 +390,8 @@ impl<T: 'static> SelectView<T> {
let focus = self.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.
@ -398,7 +402,10 @@ impl<T: 'static> SelectView<T> {
// Low-level focus change. Does not fix scrollbase.
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);
}
@ -419,9 +426,8 @@ impl<T: 'static> SelectView<T> {
Event::Key(Key::PageUp) => self.focus_up(10),
Event::Key(Key::PageDown) => self.focus_down(10),
Event::Key(Key::Home) => self.focus.set(0),
Event::Key(Key::End) => {
self.focus.set(self.items.len().saturating_sub(1))
}
Event::Key(Key::End) => self.focus
.set(self.items.len().saturating_sub(1)),
Event::Mouse {
event: MouseEvent::WheelDown,
..
@ -445,7 +451,8 @@ impl<T: 'static> SelectView<T> {
} if position
.checked_sub(offset)
.map(|position| {
self.scrollbase.start_drag(position, self.last_size.x)
self.scrollbase
.start_drag(position, self.last_size.x)
})
.unwrap_or(false) =>
{
@ -754,7 +761,8 @@ impl<T: 'static> View for SelectView<T> {
self.last_size = size;
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 {
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.
@ -56,7 +59,8 @@ impl<T: View> ViewWrapper for ShadowView<T> {
fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
// Make sure req >= offset
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) {
@ -78,8 +82,10 @@ impl<T: View> ViewWrapper for ShadowView<T> {
}
// Skip the first row/column
let offset =
Vec2::new(self.left_padding as usize, self.top_padding as usize);
let offset = Vec2::new(
self.left_padding as usize,
self.top_padding as usize,
);
let printer = &printer.offset(offset, true);
if printer.theme.shadow {
let h = printer.size.y;

View File

@ -65,9 +65,13 @@ impl<T: View> ChildWrapper<T> {
fn unwrap(self) -> T {
match self {
// ShadowView::into_inner and Layer::into_inner can never fail.
ChildWrapper::Shadow(shadow) => {
shadow.into_inner().ok().unwrap().into_inner().ok().unwrap()
}
ChildWrapper::Shadow(shadow) => shadow
.into_inner()
.ok()
.unwrap()
.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.
pub fn get(&self, pos: LayerPosition) -> Option<&View> {
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.
@ -325,7 +331,10 @@ impl StackView {
/// Returns the size for each layer in this view.
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 {

View File

@ -35,7 +35,9 @@ pub struct TextArea {
}
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);
@ -252,7 +254,8 @@ impl TextArea {
fn compute_rows(&mut self, size: Vec2) {
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) {
@ -349,11 +352,16 @@ impl TextArea {
let last_byte = self.content[self.cursor..]
.find('\n')
.map(|i| 1 + i + self.cursor);
let last_row = last_byte
.map_or(self.rows.len(), |last_byte| self.row_at(last_byte));
let last_row = last_byte.map_or(self.rows.len(), |last_byte| {
self.row_at(last_byte)
});
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 rows: {}/{}", first_row, last_row);
@ -387,11 +395,14 @@ impl TextArea {
// Otherwise, replace stuff.
let affected_rows = first_row..last_row;
let replacement_rows =
new_rows.into_iter().map(|row| row.shifted(first_byte));
self.rows.splice(affected_rows, replacement_rows);
let replacement_rows = new_rows
.into_iter()
.map(|row| row.shifted(first_byte));
self.rows
.splice(affected_rows, replacement_rows);
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)
// And y = number of 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(
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(),
)
}
@ -518,7 +537,8 @@ impl View for TextArea {
} if position
.checked_sub(offset)
.map(|position| {
self.scrollbase.start_drag(position, self.last_size.x)
self.scrollbase
.start_drag(position, self.last_size.x)
})
.unwrap_or(false) =>
{

View File

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