From b63762d44166ad87d449bc2feee957c3702e8964 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Mon, 6 Feb 2017 18:18:17 -0800 Subject: [PATCH] View::find_any now takes a closure instead of returning reference Also updated Finder::find and find_id. --- doc/tutorial_2.md | 2 +- doc/tutorial_3.md | 50 +++++++++++++++++++++++--------------- examples/edit.rs | 8 +++--- examples/list_view.rs | 21 ++++++++-------- examples/mutation.rs | 7 +++--- examples/slider.rs | 4 +-- src/backend/blt.rs | 6 ++--- src/backend/curses/n.rs | 4 +-- src/backend/curses/pan.rs | 14 +++++++---- src/backend/mod.rs | 4 +-- src/backend/termion.rs | 8 +++--- src/direction.rs | 2 +- src/lib.rs | 34 +++++++++++++++++--------- src/menu.rs | 9 +++---- src/printer.rs | 4 ++- src/theme.rs | 2 +- src/utils/mod.rs | 7 +++--- src/vec.rs | 8 +++--- src/view/mod.rs | 44 ++++++++++++++++++++++++--------- src/view/view_wrapper.rs | 43 +++++++++++++++++--------------- src/views/checkbox.rs | 8 ++---- src/views/dialog.rs | 5 ++-- src/views/edit_view.rs | 24 ++++++++---------- src/views/id_view.rs | 7 +++--- src/views/layer.rs | 6 ++--- src/views/linear_layout.rs | 10 ++++---- src/views/list_view.rs | 43 ++++++++++++++++---------------- src/views/menu_popup.rs | 10 +++----- src/views/menubar.rs | 2 +- src/views/progress_bar.rs | 4 +-- src/views/slider_view.rs | 12 +++------ src/views/stack_view.rs | 10 ++++---- src/views/text_area.rs | 9 +++---- src/xy.rs | 2 +- 34 files changed, 233 insertions(+), 200 deletions(-) diff --git a/doc/tutorial_2.md b/doc/tutorial_2.md index 6c3d846..5bc0ade 100644 --- a/doc/tutorial_2.md +++ b/doc/tutorial_2.md @@ -144,7 +144,7 @@ fn main() { siv.run(); } -fn show_next(s: &mut Cursive) { +fn show_next(_: &mut Cursive) { // Empty for now } ``` diff --git a/doc/tutorial_3.md b/doc/tutorial_3.md index 816f5b3..0065df2 100644 --- a/doc/tutorial_3.md +++ b/doc/tutorial_3.md @@ -40,7 +40,9 @@ fn main() { fn add_name(s: &mut Cursive) { fn ok(s: &mut Cursive, name: &str) { - s.find_id::>("select").unwrap().add_item_str(name); + s.find_id("select", |view: &mut SelectView| { + view.add_item_str(name) + }); s.pop_layer(); } @@ -51,19 +53,25 @@ fn add_name(s: &mut Cursive) { .title("Enter a new name") .button("Ok", |s| { let name = - s.find_id::("name").unwrap().get_content().clone(); + s.find_id("name", |view: &mut EditView| { + view.get_content().clone() + }).unwrap(); ok(s, &name); }) .button("Cancel", |s| s.pop_layer())); } fn delete_name(s: &mut Cursive) { - match s.find_id::>("select").unwrap().selected_id() { + let selection = s.find_id("select", |view: &mut SelectView| { + view.selected_id() + }).unwrap(); + + match selection { None => s.add_layer(Dialog::info("No name to remove")), Some(focus) => { - s.find_id::>("select") - .unwrap() - .remove_item(focus) + s.find_id("select", |view: &mut SelectView| { + view.remove_item(focus) + }); } } } @@ -224,8 +232,8 @@ Later, you can ask the Cursive root for this ID and get access to the view. Just what we need! Like `BoxView`, `IdView` can be used directly with [`IdView::new`], or through -the [`Identifiable`] trait. [`Cursive::find_id`] can then give you a mutable -reference to the view. +the [`Identifiable`] trait. [`Cursive::find_id`] allows you to run a closure +on the view. Here's what it looks like in action: @@ -236,8 +244,9 @@ fn add_name(s: &mut Cursive) { .fixed_width(10)) .title("Enter a new name") .button("Ok", |s| { - let name = - s.find_id::("name").unwrap().get_content().clone(); + let name = s.find_id("name", |view: &mut EditView| { + view.get_content().clone() + }).unwrap(); }) .button("Cancel", |s| s.pop_layer())); } @@ -263,7 +272,9 @@ That way, we can update it with a new item: ```rust,ignore fn add_name(s: &mut Cursive) { fn ok(s: &mut Cursive, name: &str) { - s.find_id::>("select").unwrap().add_item_str(name); + s.find_id("select", |view: &mut SelectView| { + view.add_item_str(name); + }); s.pop_layer(); } @@ -273,8 +284,9 @@ fn add_name(s: &mut Cursive) { .fixed_width(10)) .title("Enter a new name") .button("Ok", |s| { - let name = - s.find_id::("name").unwrap().get_content().clone(); + let name = s.find_id("name", |v: &mut EditView| { + v.get_content().clone() + }).unwrap(); ok(s, &name); }) .button("Cancel", |s| s.pop_layer())); @@ -286,13 +298,13 @@ complicated: ```rust,ignore fn delete_name(s: &mut Cursive) { - match s.find_id::>("select").unwrap().selected_id() { + match s.find_id("select", |v: &mut SelectView| { + v.selected_id() + }).unwrap() { None => s.add_layer(Dialog::info("No name to remove")), - Some(focus) => { - s.find_id::>("select") - .unwrap() - .remove_item(focus) - } + Some(focus) => s.find_id("select", |v: &mut SelectView| { + v.remove_item(focus) + }), } } ``` diff --git a/examples/edit.rs b/examples/edit.rs index d74d92b..ed36057 100644 --- a/examples/edit.rs +++ b/examples/edit.rs @@ -1,8 +1,8 @@ extern crate cursive; use cursive::Cursive; -use cursive::views::{Dialog, EditView, TextView}; use cursive::traits::*; +use cursive::views::{Dialog, EditView, TextView}; fn main() { let mut siv = Cursive::new(); @@ -18,9 +18,9 @@ fn main() { .with_id("name") .fixed_width(20)) .button("Ok", |s| { - let name = s.find_id::("name") - .unwrap() - .get_content(); + let name = + s.find_id("name", |view: &mut EditView| view.get_content()) + .unwrap(); show_popup(s, &name); })); diff --git a/examples/list_view.rs b/examples/list_view.rs index c18d985..e2a4ddf 100644 --- a/examples/list_view.rs +++ b/examples/list_view.rs @@ -1,9 +1,9 @@ extern crate cursive; use cursive::Cursive; +use cursive::traits::*; use cursive::views::{Checkbox, Dialog, EditView, LinearLayout, ListView, SelectView, TextView}; -use cursive::traits::*; fn main() { let mut siv = Cursive::new(); @@ -25,12 +25,13 @@ fn main() { .with_id("email2") .fixed_width(10))) .child("Receive spam?", - Checkbox::new().on_change(|s, checked| { - for name in &["email1", "email2"] { - let view: &mut EditView = s.find_id(name).unwrap(); - view.set_enabled(checked); - } - })) + Checkbox::new() + .on_change(|s, checked| for name in &["email1", + "email2"] { + s.find_id(name, |view: &mut EditView| { + view.set_enabled(checked) + }); + })) .delimiter() .child("Age", SelectView::new() @@ -39,10 +40,8 @@ fn main() { .item_str("19-30") .item_str("31-40") .item_str("41+")) - .with(|list| { - for i in 0..50 { - list.add_child(&format!("Item {}", i), EditView::new()); - } + .with(|list| for i in 0..50 { + list.add_child(&format!("Item {}", i), EditView::new()); }))); siv.run(); diff --git a/examples/mutation.rs b/examples/mutation.rs index 31f8348..52ae466 100644 --- a/examples/mutation.rs +++ b/examples/mutation.rs @@ -13,9 +13,10 @@ fn show_popup(siv: &mut Cursive) { Dialog::around(TextView::new("Tak!")) .button("Change", |s| { // Look for a view tagged "text". We _know_ it's there, so unwrap it. - let view = s.find_id::("text").unwrap(); - let content: String = view.get_content().chars().rev().collect(); - view.set_content(content); + s.find_id("text", |view: &mut TextView| { + let content: String = view.get_content().chars().rev().collect(); + view.set_content(content); + }); }) .dismiss_button("Ok")); diff --git a/examples/slider.rs b/examples/slider.rs index 700bac2..dada9db 100644 --- a/examples/slider.rs +++ b/examples/slider.rs @@ -1,8 +1,8 @@ extern crate cursive; use cursive::Cursive; -use cursive::views::{Dialog, SliderView}; use cursive::traits::*; +use cursive::views::{Dialog, SliderView}; fn main() { let mut siv = Cursive::new(); @@ -14,7 +14,7 @@ fn main() { .value(7) .on_change(|s, v| { let title = format!("[ {} ]", v); - s.find_id::("dialog").unwrap().set_title(title); + s.find_id("dialog", |view: &mut Dialog| view.set_title(title)); }) .on_enter(|s, v| { s.pop_layer(); diff --git a/src/backend/blt.rs b/src/backend/blt.rs index 0eead9f..d8c021c 100644 --- a/src/backend/blt.rs +++ b/src/backend/blt.rs @@ -1,12 +1,12 @@ extern crate bear_lib_terminal; -use ::backend; -use ::event::{Event, Key}; use self::bear_lib_terminal::Color as BltColor; use self::bear_lib_terminal::geometry::Size; use self::bear_lib_terminal::terminal::{self, Event as BltEvent, KeyCode}; +use backend; +use event::{Event, Key}; use std::collections::BTreeMap; -use ::theme::{BaseColor, Color, ColorStyle, Effect}; +use theme::{BaseColor, Color, ColorStyle, Effect}; pub struct Concrete { colours: BTreeMap, diff --git a/src/backend/curses/n.rs b/src/backend/curses/n.rs index 8e568ce..256fc3d 100644 --- a/src/backend/curses/n.rs +++ b/src/backend/curses/n.rs @@ -1,9 +1,9 @@ extern crate ncurses; -use backend; -use event::{Event, Key}; use self::super::find_closest; +use backend; +use event::{Event, Key}; use theme::{Color, ColorStyle, Effect}; use utf8; diff --git a/src/backend/curses/pan.rs b/src/backend/curses/pan.rs index 25a8ba4..65d0d55 100644 --- a/src/backend/curses/pan.rs +++ b/src/backend/curses/pan.rs @@ -1,10 +1,10 @@ extern crate pancurses; -use backend; -use event::{Event, Key}; use self::super::find_closest; +use backend; +use event::{Event, Key}; use std::cell::Cell; use theme::{Color, ColorStyle, Effect}; use utf8; @@ -23,7 +23,8 @@ impl backend::Backend for Concrete { pancurses::cbreak(); pancurses::start_color(); pancurses::curs_set(0); - window.bkgd(pancurses::COLOR_PAIR(ColorStyle::Background.id() as pancurses::chtype)); + window.bkgd(pancurses::COLOR_PAIR(ColorStyle::Background.id() as + pancurses::chtype)); Concrete { window: window, @@ -66,7 +67,8 @@ impl backend::Backend for Concrete { self.current_style.set(current_style); // self.window.attroff(style); - self.window.attron(pancurses::COLOR_PAIR(current_style.id() as pancurses::chtype)); + self.window.attron(pancurses::COLOR_PAIR(current_style.id() as + pancurses::chtype)); } fn with_effect(&self, effect: Effect, f: F) { @@ -101,7 +103,9 @@ impl backend::Backend for Concrete { // TODO: wait for a very short delay. If more keys are // pipelined, it may be an escape sequence. pancurses::Input::Character('\u{7f}') | - pancurses::Input::Character('\u{8}') => Event::Key(Key::Backspace), + pancurses::Input::Character('\u{8}') => { + Event::Key(Key::Backspace) + } pancurses::Input::Character('\u{9}') => Event::Key(Key::Tab), pancurses::Input::Character('\u{1b}') => Event::Key(Key::Esc), pancurses::Input::Character(c) if 32 <= (c as u32) && diff --git a/src/backend/mod.rs b/src/backend/mod.rs index d427591..f8289e1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -8,12 +8,12 @@ mod blt; #[cfg(any(feature = "ncurses", feature = "pancurses"))] mod curses; +#[cfg(feature = "bear-lib-terminal")] +pub use self::blt::*; #[cfg(any(feature = "ncurses", feature = "pancurses"))] pub use self::curses::*; #[cfg(feature = "termion")] pub use self::termion::*; -#[cfg(feature = "bear-lib-terminal")] -pub use self::blt::*; pub trait Backend { fn init() -> Self; diff --git a/src/backend/termion.rs b/src/backend/termion.rs index f77c0f7..bb15999 100644 --- a/src/backend/termion.rs +++ b/src/backend/termion.rs @@ -2,14 +2,14 @@ extern crate termion; extern crate chan_signal; -use ::backend; -use chan; -use ::event::{Event, Key}; use self::termion::color as tcolor; use self::termion::event::Key as TKey; use self::termion::input::TermRead; use self::termion::raw::IntoRawMode; use self::termion::style as tstyle; +use backend; +use chan; +use event::{Event, Key}; use std::cell::Cell; use std::collections::BTreeMap; use std::fmt; @@ -17,7 +17,7 @@ use std::io::Write; use std::thread; use std::time; -use ::theme; +use theme; pub struct Concrete { terminal: termion::raw::RawTerminal<::std::io::Stdout>, diff --git a/src/direction.rs b/src/direction.rs index 258674a..d882d54 100644 --- a/src/direction.rs +++ b/src/direction.rs @@ -15,8 +15,8 @@ //! * Relative direction: front or back. //! Its actual direction depends on the orientation. -use vec::Vec2; use XY; +use vec::Vec2; /// Describes a vertical or horizontal orientation for a view. #[derive(Clone,Copy,Debug,PartialEq)] diff --git a/src/lib.rs b/src/lib.rs index e6cefe4..3c868ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,7 @@ extern crate num; #[macro_use] extern crate chan; + macro_rules! println_stderr( ($($arg:tt)*) => { { use ::std::io::Write; @@ -364,8 +365,11 @@ impl Cursive { /// Tries to find the view pointed to by the given selector. /// + /// Runs a closure on the view once it's found, and return the + /// result. + /// /// If the view is not found, or if it is not of the asked type, - /// it returns None. + /// returns None. /// /// # Examples /// @@ -380,15 +384,18 @@ impl Cursive { /// .with_id("text")); /// /// siv.add_global_callback('p', |s| { - /// s.find::(&view::Selector::Id("text")) - /// .unwrap() - /// .set_content("Text #2"); + /// s.find(&view::Selector::Id("text"), |view: &mut views::TextView| { + /// view.set_content("Text #2"); + /// }); /// }); /// # } /// ``` - pub fn find(&mut self, sel: &view::Selector) - -> Option<&mut V> { - self.screen_mut().find(sel) + pub fn find(&mut self, sel: &view::Selector, callback: F) + -> Option + where V: View + Any, + F: FnOnce(&mut V) -> R + { + self.screen_mut().find(sel, callback) } /// Convenient method to use `find` with a `view::Selector::Id`. @@ -406,14 +413,17 @@ impl Cursive { /// .with_id("text")); /// /// siv.add_global_callback('p', |s| { - /// s.find_id::("text") - /// .unwrap() - /// .set_content("Text #2"); + /// s.find_id("text", |view: &mut views::TextView| { + /// view.set_content("Text #2"); + /// }); /// }); /// # } /// ``` - pub fn find_id(&mut self, id: &str) -> Option<&mut V> { - self.find(&view::Selector::Id(id)) + pub fn find_id(&mut self, id: &str, callback: F) -> Option + where V: View + Any, + F: FnOnce(&mut V) -> R + { + self.find(&view::Selector::Id(id), callback) } /// Adds a global callback. diff --git a/src/menu.rs b/src/menu.rs index 37425af..a9fc00d 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -165,13 +165,13 @@ impl MenuTree { /// Returns `None` if the given title was not found, /// or if it wasn't a subtree. pub fn find_subtree(&mut self, title: &str) -> Option<&mut MenuTree> { - self.find_item(title).and_then(|item| { - if let MenuItem::Subtree(_, ref mut tree) = *item { + self.find_item(title) + .and_then(|item| if let MenuItem::Subtree(_, ref mut tree) = + *item { Some(Rc::make_mut(tree)) } else { None - } - }) + }) } /// Removes the item at the given position. @@ -191,5 +191,4 @@ impl MenuTree { pub fn is_empty(&self) -> bool { self.children.is_empty() } - } diff --git a/src/printer.rs b/src/printer.rs index d9d63e4..d8e5f55 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -34,7 +34,9 @@ impl<'a> Printer<'a> { /// /// But nobody needs to know that. #[doc(hidden)] - pub fn new>(size: T, theme: Theme, backend: &'a backend::Concrete) -> Self { + pub fn new>(size: T, theme: Theme, + backend: &'a backend::Concrete) + -> Self { Printer { offset: Vec2::zero(), size: size.into(), diff --git a/src/theme.rs b/src/theme.rs index 36c41de..44a6943 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -129,7 +129,7 @@ pub enum Effect { /// No effect Simple, /// Reverses foreground and background colors - Reverse, + Reverse, // TODO: bold, italic, underline } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c7f4f47..527b991 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -14,7 +14,7 @@ pub struct Prefix { /// The length (in bytes) of the string. pub length: usize, /// The unicode-width of the string. - pub width: usize + pub width: usize, } /// Computes the length (number of bytes) and width of a prefix that fits in the given `width`. @@ -42,7 +42,8 @@ pub struct Prefix { /// prefix(my_text.graphemes(true), 5, ""); /// # } /// ``` -pub fn prefix<'a, I>(iter: I, available_width: usize, delimiter: &str) -> Prefix +pub fn prefix<'a, I>(iter: I, available_width: usize, delimiter: &str) + -> Prefix where I: Iterator { let delimiter_width = delimiter.width(); @@ -70,7 +71,7 @@ pub fn prefix<'a, I>(iter: I, available_width: usize, delimiter: &str) -> Prefix Prefix { length: length, - width: current_width + width: current_width, } } diff --git a/src/vec.rs b/src/vec.rs index be4c894..4a8c316 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -95,7 +95,7 @@ impl XY { } } -impl >> From for XY { +impl>> From for XY { fn from(t: T) -> Self { let other = t.into(); Self::new(other.x as isize, other.y as isize) @@ -115,7 +115,7 @@ impl From<(u32, u32)> for XY { } -impl, O: Into>> Add for XY { +impl, O: Into>> Add for XY { type Output = Self; fn add(self, other: O) -> Self { @@ -123,7 +123,7 @@ impl, O: Into>> Add for XY { } } -impl, O: Into>> Sub for XY { +impl, O: Into>> Sub for XY { type Output = Self; fn sub(self, other: O) -> Self { @@ -131,7 +131,7 @@ impl, O: Into>> Sub for XY { } } -impl > Div for XY { +impl> Div for XY { type Output = Self; fn div(self, other: T) -> Self { diff --git a/src/view/mod.rs b/src/view/mod.rs index 5614c0d..51481ab 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -50,10 +50,6 @@ mod identifiable; mod boxable; -use Printer; - -use direction::Direction; -use event::{Event, EventResult}; pub use self::boxable::Boxable; pub use self::identifiable::Identifiable; @@ -65,6 +61,10 @@ pub use self::size_cache::SizeCache; pub use self::size_constraint::SizeConstraint; pub use self::view_path::ViewPath; pub use self::view_wrapper::ViewWrapper; +use Printer; + +use direction::Direction; +use event::{Event, EventResult}; use std::any::Any; use vec::Vec2; @@ -122,8 +122,9 @@ pub trait View { /// Returns None if the path doesn't lead to a view. /// /// Default implementation always return `None`. - fn find_any(&mut self, &Selector) -> Option<&mut Any> { - None + fn find_any<'a>(&mut self, _: &Selector, + _: Box) { + // TODO: FnMut -> FnOnce once it works } /// This view is offered focus. Will it take it? @@ -150,17 +151,38 @@ pub trait Finder { /// /// If the view is not found, or if it is not of the asked type, /// it returns None. - fn find(&mut self, sel: &Selector) -> Option<&mut V>; + fn find(&mut self, sel: &Selector, callback: F) -> Option + where V: View + Any, + F: FnOnce(&mut V) -> R; /// Convenient method to use `find` with a `view::Selector::Id`. - fn find_id(&mut self, id: &str) -> Option<&mut V> { - self.find(&Selector::Id(id)) + fn find_id(&mut self, id: &str, callback: F) -> Option + where V: View + Any, + F: FnOnce(&mut V) -> R + { + self.find(&Selector::Id(id), callback) } } impl Finder for T { - fn find(&mut self, sel: &Selector) -> Option<&mut V> { - self.find_any(sel).and_then(|b| b.downcast_mut::()) + fn find(&mut self, sel: &Selector, callback: F) -> Option + where V: View + Any, + F: FnOnce(&mut V) -> R + { + let mut result = None; + { + let result_ref = &mut result; + + let mut callback = Some(callback); + let callback = |v: &mut Any| if let Some(callback) = + callback.take() { + if let Some(v) = v.downcast_mut::() { + *result_ref = Some(callback(v)); + } + }; + self.find_any(sel, Box::new(callback)); + } + result } } diff --git a/src/view/view_wrapper.rs b/src/view/view_wrapper.rs index b981bbe..457f03a 100644 --- a/src/view/view_wrapper.rs +++ b/src/view/view_wrapper.rs @@ -11,8 +11,8 @@ use view::{Selector, View}; /// Default implementation forwards all calls to the child view. /// Overrides some methods as desired. /// -/// You can use the [`wrap_impl!`] macro to define `get_view` and -/// `get_view_mut` for you. +/// You can use the [`wrap_impl!`] macro to define `with_view` and +/// `with_view_mut` for you. /// /// [`wrap_impl!`]: ../macro.wrap_impl.html pub trait ViewWrapper { @@ -20,44 +20,46 @@ pub trait ViewWrapper { type V: View; /// Get an immutable reference to the wrapped view. - fn get_view(&self) -> &Self::V; + fn with_view(&self, f: F) -> R where F: FnOnce(&Self::V) -> R; /// Get a mutable reference to the wrapped view. - fn get_view_mut(&mut self) -> &mut Self::V; + fn with_view_mut(&mut self, f: F) -> R + where F: FnOnce(&mut Self::V) -> R; /// Wraps the `draw` method. fn wrap_draw(&self, printer: &Printer) { - self.get_view().draw(printer); + self.with_view(|v| v.draw(printer)); } /// Wraps the `required_size` method. fn wrap_required_size(&mut self, req: Vec2) -> Vec2 { - self.get_view_mut().required_size(req) + self.with_view_mut(|v| v.required_size(req)) } /// Wraps the `on_event` method. fn wrap_on_event(&mut self, ch: Event) -> EventResult { - self.get_view_mut().on_event(ch) + self.with_view_mut(|v| v.on_event(ch)) } /// Wraps the `layout` method. fn wrap_layout(&mut self, size: Vec2) { - self.get_view_mut().layout(size); + self.with_view_mut(|v| v.layout(size)); } /// Wraps the `take_focus` method. fn wrap_take_focus(&mut self, source: Direction) -> bool { - self.get_view_mut().take_focus(source) + self.with_view_mut(|v| v.take_focus(source)) } /// Wraps the `find` method. - fn wrap_find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.get_view_mut().find_any(selector) + fn wrap_find_any<'a>(&mut self, selector: &Selector, + callback: Box) { + self.with_view_mut(|v| v.find_any(selector, callback)); } /// Wraps the `needs_relayout` method. fn wrap_needs_relayout(&self) -> bool { - self.get_view().needs_relayout() + self.with_view(|v| v.needs_relayout()) } } @@ -82,8 +84,9 @@ impl View for T { self.wrap_take_focus(source) } - fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.wrap_find_any(selector) + fn find_any<'a>(&mut self, selector: &Selector, + callback: Box) { + self.wrap_find_any(selector, callback) } fn needs_relayout(&self) -> bool { @@ -93,7 +96,7 @@ impl View for T { /// Convenient macro to implement the [`ViewWrapper`] trait. /// -/// It defines the `get_view` and `get_view_mut` implementations, +/// It defines the `with_view` and `with_view_mut` implementations, /// as well as the `type V` declaration. /// /// [`ViewWrapper`]: view/trait.ViewWrapper.html @@ -117,12 +120,14 @@ macro_rules! wrap_impl { (self.$v:ident: $t:ty) => { type V = $t; - fn get_view(&self) -> &Self::V { - &self.$v + fn with_view(&self, f: F) -> R where F: FnOnce(&Self::V) -> R { + f(&self.$v) } - fn get_view_mut(&mut self) -> &mut Self::V { - &mut self.$v + fn with_view_mut(&mut self, f: F) -> R + where F: FnOnce(&mut Self::V) -> R + { + f(&mut self.$v) } }; } diff --git a/src/views/checkbox.rs b/src/views/checkbox.rs index 2100946..7924e24 100644 --- a/src/views/checkbox.rs +++ b/src/views/checkbox.rs @@ -61,9 +61,7 @@ impl Checkbox { /// /// Chainable variant. pub fn checked(self) -> Self { - self.with(|s| { - s.check(); - }) + self.with(|s| { s.check(); }) } /// Returns `true` if the checkbox is checked. @@ -80,9 +78,7 @@ impl Checkbox { /// /// Chainable variant. pub fn unchecked(self) -> Self { - self.with(|s| { - s.uncheck(); - }) + self.with(|s| { s.uncheck(); }) } /// Sets the checkbox state. diff --git a/src/views/dialog.rs b/src/views/dialog.rs index 8f3a04c..325657f 100644 --- a/src/views/dialog.rs +++ b/src/views/dialog.rs @@ -399,7 +399,8 @@ impl View for Dialog { } } - fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.content.find_any(selector) + fn find_any<'a>(&mut self, selector: &Selector, + callback: Box) { + self.content.find_any(selector, callback); } } diff --git a/src/views/edit_view.rs b/src/views/edit_view.rs index 734ef28..80a9b73 100644 --- a/src/views/edit_view.rs +++ b/src/views/edit_view.rs @@ -40,9 +40,8 @@ use view::View; /// .with_id("name") /// .fixed_width(20)) /// .button("Ok", |s| { -/// let name = s.find_id::("name") -/// .unwrap() -/// .get_content(); +/// let name = s.find_id("name", |view: &mut EditView| view.get_content()) +/// .unwrap(); /// show_popup(s, &name); /// })); /// @@ -239,9 +238,10 @@ impl EditView { // Look at the content before the cursor (we will print its tail). // From the end, count the length until we reach `available`. // Then sum the byte lengths. - let suffix_length = - simple_suffix(&self.content[self.offset..self.cursor], - available).length; + let suffix_length = simple_suffix(&self.content[self.offset.. + self.cursor], + available) + .length; self.offset = self.cursor - suffix_length; // Make sure the cursor is in view assert!(self.cursor >= self.offset); @@ -250,8 +250,8 @@ impl EditView { // If we have too much space if self.content[self.offset..].width() < self.last_length { - let suffix_length = simple_suffix(&self.content, - self.last_length - 1).length; + let suffix_length = + simple_suffix(&self.content, self.last_length - 1).length; self.offset = self.content.len() - suffix_length; } } @@ -392,9 +392,7 @@ impl View for EditView { Event::Key(Key::Enter) if self.on_submit.is_some() => { let cb = self.on_submit.clone().unwrap(); let content = self.content.clone(); - return EventResult::with_cb(move |s| { - cb(s, &content); - }); + return EventResult::with_cb(move |s| { cb(s, &content); }); } _ => return EventResult::Ignored, } @@ -407,9 +405,7 @@ impl View for EditView { let content = self.content.clone(); let cursor = self.cursor; - Callback::from_fn(move |s| { - cb(s, &content, cursor); - }) + Callback::from_fn(move |s| { cb(s, &content, cursor); }) }); EventResult::Consumed(cb) } diff --git a/src/views/id_view.rs b/src/views/id_view.rs index 73ae6c2..7784335 100644 --- a/src/views/id_view.rs +++ b/src/views/id_view.rs @@ -21,10 +21,11 @@ impl IdView { impl ViewWrapper for IdView { wrap_impl!(self.view: T); - fn wrap_find_any(&mut self, selector: &Selector) -> Option<&mut Any> { + fn wrap_find_any<'a>(&mut self, selector: &Selector, + mut callback: Box) { match selector { - &Selector::Id(id) if id == self.id => Some(&mut self.view), - s => self.view.find_any(s), + &Selector::Id(id) if id == self.id => callback(&mut self.view), + s => self.view.find_any(s, callback), } } } diff --git a/src/views/layer.rs b/src/views/layer.rs index 8370cb6..542d7ef 100644 --- a/src/views/layer.rs +++ b/src/views/layer.rs @@ -10,12 +10,10 @@ pub struct Layer { view: T, } -impl Layer { +impl Layer { /// Wraps the given view. pub fn new(view: T) -> Self { - Layer { - view: view, - } + Layer { view: view } } } diff --git a/src/views/linear_layout.rs b/src/views/linear_layout.rs index 9c6a750..cc0ddad 100644 --- a/src/views/linear_layout.rs +++ b/src/views/linear_layout.rs @@ -375,10 +375,10 @@ impl View for LinearLayout { } } - fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.children - .iter_mut() - .filter_map(|c| c.view.find_any(selector)) - .next() + fn find_any<'a>(&mut self, selector: &Selector, + mut callback: Box) { + for child in &mut self.children { + child.view.find_any(selector, Box::new(|any| callback(any))); + } } } diff --git a/src/views/list_view.rs b/src/views/list_view.rs index 77a84df..7f3490c 100644 --- a/src/views/list_view.rs +++ b/src/views/list_view.rs @@ -132,16 +132,16 @@ impl ListView { fn move_focus(&mut self, n: usize, source: direction::Direction) -> EventResult { let i = if let Some(i) = - source.relative(direction::Orientation::Vertical) - .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)) - .take(n) - .last() - }) { + source.relative(direction::Orientation::Vertical) + .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)) + .take(n) + .last() + }) { i } else { return EventResult::Ignored; @@ -185,14 +185,12 @@ impl View for ListView { .max() .unwrap_or(0) + 1; - self.scrollbase.draw(printer, |printer, i| { - match self.children[i] { - Child::Row(ref label, ref view) => { - printer.print((0, 0), label); - view.draw(&printer.offset((offset, 0), i == self.focus)); - } - Child::Delimiter => (), + self.scrollbase.draw(printer, |printer, i| match self.children[i] { + Child::Row(ref label, ref view) => { + printer.print((0, 0), label); + view.draw(&printer.offset((offset, 0), i == self.focus)); } + Child::Delimiter => (), }); } @@ -298,11 +296,12 @@ impl View for ListView { true } - fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.children + fn find_any<'a>(&mut self, selector: &Selector, + mut callback: Box) { + for view in self.children .iter_mut() - .filter_map(Child::view) - .filter_map(|v| v.find_any(selector)) - .next() + .filter_map(Child::view) { + view.find_any(selector, Box::new(|any| callback(any))); + } } } diff --git a/src/views/menu_popup.rs b/src/views/menu_popup.rs index 6beb6ca..3412cf9 100644 --- a/src/views/menu_popup.rs +++ b/src/views/menu_popup.rs @@ -228,12 +228,9 @@ impl View for MenuPopup { Event::Key(Key::PageDown) => self.scroll_down(5, false), Event::Key(Key::Home) => self.focus = 0, - Event::Key(Key::End) => { - self.focus = self.menu.children.len() - 1 - } + Event::Key(Key::End) => self.focus = self.menu.children.len() - 1, - Event::Key(Key::Right) if self.menu.children - [self.focus] + Event::Key(Key::Right) if self.menu.children[self.focus] .is_subtree() => { return match self.menu.children[self.focus] { MenuItem::Subtree(_, ref tree) => { @@ -243,8 +240,7 @@ impl View for MenuPopup { }; } - Event::Key(Key::Enter) if !self.menu.children - [self.focus] + Event::Key(Key::Enter) if !self.menu.children[self.focus] .is_delimiter() => { return match self.menu.children[self.focus] { MenuItem::Leaf(_, ref cb) => { diff --git a/src/views/menubar.rs b/src/views/menubar.rs index afe1469..c3fdb40 100644 --- a/src/views/menubar.rs +++ b/src/views/menubar.rs @@ -83,7 +83,7 @@ impl Menubar { /// Insert a new item at the given position. pub fn insert_subtree(&mut self, i: usize, title: &str, menu: MenuTree) - -> &mut Self { + -> &mut Self { self.menus.insert(i, (title.to_string(), Rc::new(menu))); self } diff --git a/src/views/progress_bar.rs b/src/views/progress_bar.rs index fb53cf4..82e9fd3 100644 --- a/src/views/progress_bar.rs +++ b/src/views/progress_bar.rs @@ -118,9 +118,7 @@ impl ProgressBar { pub fn start(&mut self, f: F) { let counter: Counter = self.value.clone(); - thread::spawn(move || { - f(counter); - }); + thread::spawn(move || { f(counter); }); } /// Starts a function in a separate thread, and monitor the progress. diff --git a/src/views/slider_view.rs b/src/views/slider_view.rs index 235f7b6..3225e45 100644 --- a/src/views/slider_view.rs +++ b/src/views/slider_view.rs @@ -55,9 +55,7 @@ impl SliderView { /// /// Chainable variant. pub fn value(self, value: usize) -> Self { - self.with(|s| { - s.set_value(value); - }) + self.with(|s| { s.set_value(value); }) } /// Sets a callback to be called when the slider is moved. @@ -79,9 +77,7 @@ impl SliderView { fn get_change_result(&self) -> EventResult { EventResult::Consumed(self.on_change.clone().map(|cb| { let value = self.value; - Callback::from_fn(move |s| { - cb(s, value); - }) + Callback::from_fn(move |s| { cb(s, value); }) })) } @@ -148,9 +144,7 @@ impl View for SliderView { Event::Key(Key::Enter) if self.on_enter.is_some() => { let value = self.value; let cb = self.on_enter.clone().unwrap(); - EventResult::with_cb(move |s| { - cb(s, value); - }) + EventResult::with_cb(move |s| { cb(s, value); }) } _ => EventResult::Ignored, } diff --git a/src/views/stack_view.rs b/src/views/stack_view.rs index e48c01a..7c0feb6 100644 --- a/src/views/stack_view.rs +++ b/src/views/stack_view.rs @@ -180,10 +180,10 @@ impl View for StackView { } } - fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { - self.layers - .iter_mut() - .filter_map(|l| l.view.find_any(selector)) - .next() + fn find_any<'a>(&mut self, selector: &Selector, + mut callback: Box) { + for layer in &mut self.layers { + layer.view.find_any(selector, Box::new(|any| callback(any))); + } } } diff --git a/src/views/text_area.rs b/src/views/text_area.rs index 5536e86..633a9cb 100644 --- a/src/views/text_area.rs +++ b/src/views/text_area.rs @@ -375,11 +375,10 @@ impl View for TextArea { } else { printer.size.x }; - printer.with_effect(effect, |printer| { - for y in 0..printer.size.y { - printer.print_hline((0, y), w, " "); - } - }); + printer.with_effect(effect, + |printer| for y in 0..printer.size.y { + printer.print_hline((0, y), w, " "); + }); // println_stderr!("Content: `{}`", &self.content); self.scrollbase.draw(printer, |printer, i| { diff --git a/src/xy.rs b/src/xy.rs index 4f30323..4416dbf 100644 --- a/src/xy.rs +++ b/src/xy.rs @@ -56,7 +56,7 @@ impl XY { } } -impl XY { +impl XY { /// Returns a new `XY` with the axis `o` set to `value`. pub fn with_axis(&self, o: Orientation, value: T) -> Self { let mut new = self.clone();