Rename find -> call_on

And update tutorials
This commit is contained in:
Alexandre Bury 2017-03-26 20:50:50 -07:00
parent c3c69e7892
commit c300e0628d
9 changed files with 58 additions and 54 deletions

View File

@ -40,7 +40,7 @@ fn main() {
fn add_name(s: &mut Cursive) { fn add_name(s: &mut Cursive) {
fn ok(s: &mut Cursive, name: &str) { fn ok(s: &mut Cursive, name: &str) {
s.find_id("select", |view: &mut SelectView<String>| { s.call_on_id("select", |view: &mut SelectView<String>| {
view.add_item_str(name) view.add_item_str(name)
}); });
s.pop_layer(); s.pop_layer();
@ -53,7 +53,7 @@ fn add_name(s: &mut Cursive) {
.title("Enter a new name") .title("Enter a new name")
.button("Ok", |s| { .button("Ok", |s| {
let name = let name =
s.find_id("name", |view: &mut EditView| { s.call_on_id("name", |view: &mut EditView| {
view.get_content().clone() view.get_content().clone()
}).unwrap(); }).unwrap();
ok(s, &name); ok(s, &name);
@ -62,16 +62,11 @@ fn add_name(s: &mut Cursive) {
} }
fn delete_name(s: &mut Cursive) { fn delete_name(s: &mut Cursive) {
let selection = s.find_id("select", |view: &mut SelectView<String>| { let mut select = s.find_id::<SelectView<String>>("select").unwrap();
view.selected_id() match select.selected_id() {
}).unwrap();
match selection {
None => s.add_layer(Dialog::info("No name to remove")), None => s.add_layer(Dialog::info("No name to remove")),
Some(focus) => { Some(focus) => {
s.find_id("select", |view: &mut SelectView<String>| { select.remove_item(focus);
view.remove_item(focus)
});
} }
} }
} }
@ -232,7 +227,7 @@ Later, you can ask the Cursive root for this ID and get access to the view.
Just what we need! Just what we need!
Like `BoxView`, `IdView` can be used directly with [`IdView::new`], or through Like `BoxView`, `IdView` can be used directly with [`IdView::new`], or through
the [`Identifiable`] trait. [`Cursive::find_id`] allows you to run a closure the [`Identifiable`] trait. [`Cursive::call_on_id`] allows you to run a closure
on the view. on the view.
Here's what it looks like in action: Here's what it looks like in action:
@ -244,7 +239,7 @@ fn add_name(s: &mut Cursive) {
.fixed_width(10)) .fixed_width(10))
.title("Enter a new name") .title("Enter a new name")
.button("Ok", |s| { .button("Ok", |s| {
let name = s.find_id("name", |view: &mut EditView| { let name = s.call_on_id("name", |view: &mut EditView| {
view.get_content().clone() view.get_content().clone()
}).unwrap(); }).unwrap();
}) })
@ -253,7 +248,7 @@ fn add_name(s: &mut Cursive) {
``` ```
We create the `EditView` with the id `"name"`, and we use `"name"` again when We create the `EditView` with the id `"name"`, and we use `"name"` again when
calling `find_id`. calling `call_on_id`.
Now we just need to do something with this name: add it to the list! Now we just need to do something with this name: add it to the list!
Remember the `SelectView` we created? Let's give it an ID too: Remember the `SelectView` we created? Let's give it an ID too:
@ -272,7 +267,7 @@ That way, we can update it with a new item:
```rust,ignore ```rust,ignore
fn add_name(s: &mut Cursive) { fn add_name(s: &mut Cursive) {
fn ok(s: &mut Cursive, name: &str) { fn ok(s: &mut Cursive, name: &str) {
s.find_id("select", |view: &mut SelectView<String>| { s.call_on_id("select", |view: &mut SelectView<String>| {
view.add_item_str(name); view.add_item_str(name);
}); });
s.pop_layer(); s.pop_layer();
@ -284,7 +279,7 @@ fn add_name(s: &mut Cursive) {
.fixed_width(10)) .fixed_width(10))
.title("Enter a new name") .title("Enter a new name")
.button("Ok", |s| { .button("Ok", |s| {
let name = s.find_id("name", |v: &mut EditView| { let name = s.call_on_id("name", |v: &mut EditView| {
v.get_content().clone() v.get_content().clone()
}).unwrap(); }).unwrap();
ok(s, &name); ok(s, &name);
@ -298,27 +293,30 @@ complicated:
```rust,ignore ```rust,ignore
fn delete_name(s: &mut Cursive) { fn delete_name(s: &mut Cursive) {
match s.find_id("select", |v: &mut SelectView<String>| { let mut select = s.find_id::<SelectView<String>>("select").unwrap();
v.selected_id() match select.selected_id() {
}).unwrap() {
None => s.add_layer(Dialog::info("No name to remove")), None => s.add_layer(Dialog::info("No name to remove")),
Some(focus) => s.find_id("select", |v: &mut SelectView<String>| { Some(focus) => {
v.remove_item(focus) select.remove_item(focus);
}), }
} }
} }
``` ```
We use [`SelectView::selected_id`] and [`SelectView::remove_item`] to remove We use [`SelectView::selected_id`] and [`SelectView::remove_item`] to remove
the item currently selected, nothing too surprising. the item currently selected, nothing too surprising.
We have to find the `SelectView` twice, otherwise we're still borrowing `s`
when we try to add a new layer - one of the quirks of the borrow checker. But this time, instead of using `call_on_id`, we use `Cursive::find_id`:
this method returns a handle, through which we can mutate the view.
It uses `Rc` and `RefCell` under the hood to provide mutable access to the
view without borrowing the `Cursive` root, leaving us free to pop layers.
[`EditView`]: http://gyscos.github.io/Cursive/cursive/views/struct.EditView.html [`EditView`]: http://gyscos.github.io/Cursive/cursive/views/struct.EditView.html
[`IdView`]: http://gyscos.github.io/Cursive/cursive/views/struct.IdView.html [`IdView`]: http://gyscos.github.io/Cursive/cursive/views/struct.IdView.html
[`IdView::new`]: http://gyscos.github.io/Cursive/cursive/prelude/struct.IdView.html#method.around [`IdView::new`]: http://gyscos.github.io/Cursive/cursive/prelude/struct.IdView.html#method.around
[`Identifiable`]: http://gyscos.github.io/Cursive/cursive/view/trait.Identifiable.html [`Identifiable`]: http://gyscos.github.io/Cursive/cursive/view/trait.Identifiable.html
[`Cursive::find_id`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.find_id [`Cursive::find_id`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.find_id
[`Cursive::call_on_id`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.call_on_id
[`SelectView::selected_id`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.selected_id [`SelectView::selected_id`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.selected_id
[`SelectView::remove_item`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.remove_item [`SelectView::remove_item`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.remove_item

View File

@ -386,23 +386,23 @@ impl Cursive {
/// .with_id("text")); /// .with_id("text"));
/// ///
/// siv.add_global_callback('p', |s| { /// siv.add_global_callback('p', |s| {
/// s.find(&view::Selector::Id("text"), |view: &mut views::TextView| { /// s.call_on(&view::Selector::Id("text"), |view: &mut views::TextView| {
/// view.set_content("Text #2"); /// view.set_content("Text #2");
/// }); /// });
/// }); /// });
/// # } /// # }
/// ``` /// ```
pub fn find<V, F, R>(&mut self, sel: &view::Selector, callback: F) pub fn call_on<V, F, R>(&mut self, sel: &view::Selector, callback: F)
-> Option<R> -> Option<R>
where V: View + Any, where V: View + Any,
F: FnOnce(&mut V) -> R F: FnOnce(&mut V) -> R
{ {
self.screen_mut().find(sel, callback) self.screen_mut().call_on(sel, callback)
} }
/// Tries to find the view identified by the given id. /// Tries to find the view identified by the given id.
/// ///
/// Convenient method to use `find` with a `view::Selector::Id`. /// Convenient method to use `call_on` with a `view::Selector::Id`.
/// ///
/// # Examples /// # Examples
/// ///
@ -427,7 +427,7 @@ impl Cursive {
where V: View + Any, where V: View + Any,
F: FnOnce(&mut V) -> R F: FnOnce(&mut V) -> R
{ {
self.find(&view::Selector::Id(id), callback) self.call_on(&view::Selector::Id(id), callback)
} }
/// Convenient method to find a view wrapped in [`IdView`]. /// Convenient method to find a view wrapped in [`IdView`].

View File

@ -116,14 +116,14 @@ pub trait View {
/// Finds the view identified by the given selector. /// Finds the view identified by the given selector.
/// ///
/// See [`Finder::find`] for a nicer interface, implemented for all views. /// See [`Finder::call_on`] for a nicer interface, implemented for all views.
/// ///
/// [`Finder::find`]: trait.Finder.html#method.find /// [`Finder::call_on`]: trait.Finder.html#method.call_on
/// ///
/// Returns None if the path doesn't lead to a view. /// Returns None if the path doesn't lead to a view.
/// ///
/// Default implementation always return `None`. /// Default implementation always return `None`.
fn find_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) { fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
// TODO: FnMut -> FnOnce once it works // TODO: FnMut -> FnOnce once it works
} }
@ -146,33 +146,33 @@ pub trait View {
} }
} }
/// Provides `find<V: View>` to views. /// Provides `call_on<V: View>` to views.
/// ///
/// This trait is mostly a wrapper around [`View::find_any`]. /// This trait is mostly a wrapper around [`View::call_on_any`].
/// ///
/// It provides a nicer interface to find a view when you know its type. /// It provides a nicer interface to find a view when you know its type.
/// ///
/// [`View::find_any`]: ./trait.View.html#method.find_any /// [`View::call_on_any`]: ./trait.View.html#method.call_on_any
pub trait Finder { pub trait Finder {
/// Tries to find the view pointed to by the given selector. /// Tries to find the view pointed to by the given selector.
/// ///
/// If the view is not found, or if it is not of the asked type, /// If the view is not found, or if it is not of the asked type,
/// it returns None. /// it returns None.
fn find<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R> fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
where V: View + Any, where V: View + Any,
F: FnOnce(&mut V) -> R; F: FnOnce(&mut V) -> R;
/// Convenient method to use `find` with a `view::Selector::Id`. /// Convenient method to use `call_on` with a `view::Selector::Id`.
fn find_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R> fn find_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
where V: View + Any, where V: View + Any,
F: FnOnce(&mut V) -> R F: FnOnce(&mut V) -> R
{ {
self.find(&Selector::Id(id), callback) self.call_on(&Selector::Id(id), callback)
} }
} }
impl<T: View> Finder for T { impl<T: View> Finder for T {
fn find<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R> fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
where V: View + Any, where V: View + Any,
F: FnOnce(&mut V) -> R F: FnOnce(&mut V) -> R
{ {
@ -190,7 +190,7 @@ impl<T: View> Finder for T {
.and_then(|v| v.with_view_mut(callback)); .and_then(|v| v.with_view_mut(callback));
} }
}; };
self.find_any(sel, Box::new(callback)); self.call_on_any(sel, Box::new(callback));
} }
result result
} }

View File

@ -52,9 +52,9 @@ pub trait ViewWrapper {
} }
/// Wraps the `find` method. /// Wraps the `find` method.
fn wrap_find_any<'a>(&mut self, selector: &Selector, fn wrap_call_on_any<'a>(&mut self, selector: &Selector,
callback: Box<FnMut(&mut Any) + 'a>) { callback: Box<FnMut(&mut Any) + 'a>) {
self.with_view_mut(|v| v.find_any(selector, callback)); self.with_view_mut(|v| v.call_on_any(selector, callback));
} }
/// Wraps the `focus_view` method. /// Wraps the `focus_view` method.
@ -89,9 +89,9 @@ impl<T: ViewWrapper> View for T {
self.wrap_take_focus(source) self.wrap_take_focus(source)
} }
fn find_any<'a>(&mut self, selector: &Selector, fn call_on_any<'a>(&mut self, selector: &Selector,
callback: Box<FnMut(&mut Any) + 'a>) { callback: Box<FnMut(&mut Any) + 'a>) {
self.wrap_find_any(selector, callback) self.wrap_call_on_any(selector, callback)
} }
fn needs_relayout(&self) -> bool { fn needs_relayout(&self) -> bool {

View File

@ -399,9 +399,9 @@ impl View for Dialog {
} }
} }
fn find_any<'a>(&mut self, selector: &Selector, fn call_on_any<'a>(&mut self, selector: &Selector,
callback: Box<FnMut(&mut Any) + 'a>) { callback: Box<FnMut(&mut Any) + 'a>) {
self.content.find_any(selector, callback); self.content.call_on_any(selector, callback);
} }
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> { fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {

View File

@ -1,7 +1,7 @@
use owning_ref::{RcRef, OwningHandle}; use owning_ref::{RcRef, OwningHandle};
use std::any::Any;
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::any::Any;
use std::rc::Rc; use std::rc::Rc;
use view::{Selector, View, ViewWrapper}; use view::{Selector, View, ViewWrapper};
@ -12,6 +12,10 @@ pub struct IdView<V: View> {
} }
/// Mutable reference to a view. /// Mutable reference to a view.
///
/// This behaves like a [`RefMut`], but without being tied to a lifetime.
///
/// [`RefMut`]: https://doc.rust-lang.org/std/cell/struct.RefMut.html
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>; pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
impl<V: View> IdView<V> { impl<V: View> IdView<V> {
@ -24,6 +28,8 @@ impl<V: View> IdView<V> {
} }
/// Gets mutable access to the inner view. /// Gets mutable access to the inner view.
///
/// This returns a `ViewRef<V>`, which implement `DerefMut<Target = V>`.
pub fn get_mut(&mut self) -> ViewRef<V> { pub fn get_mut(&mut self) -> ViewRef<V> {
// TODO: return a standalone item (not tied to our lifetime) // TODO: return a standalone item (not tied to our lifetime)
// that bundles `self.view.clone()` and allow mutable reference to // that bundles `self.view.clone()` and allow mutable reference to
@ -56,11 +62,11 @@ impl<T: View + 'static> ViewWrapper for IdView<T> {
.map(|mut v| f(&mut *v)) .map(|mut v| f(&mut *v))
} }
fn wrap_find_any<'a>(&mut self, selector: &Selector, fn wrap_call_on_any<'a>(&mut self, selector: &Selector,
mut callback: Box<for<'b> FnMut(&'b mut Any) + 'a>) { mut callback: Box<for<'b> FnMut(&'b mut Any) + 'a>) {
let result = match selector { let result = match selector {
&Selector::Id(id) if id == self.id => callback(self), &Selector::Id(id) if id == self.id => callback(self),
s => self.view.borrow_mut().find_any(s, callback), s => self.view.borrow_mut().call_on_any(s, callback),
}; };
result result
} }

View File

@ -395,10 +395,10 @@ impl View for LinearLayout {
} }
} }
fn find_any<'a>(&mut self, selector: &Selector, fn call_on_any<'a>(&mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>) { mut callback: Box<FnMut(&mut Any) + 'a>) {
for child in &mut self.children { for child in &mut self.children {
child.view.find_any(selector, Box::new(|any| callback(any))); child.view.call_on_any(selector, Box::new(|any| callback(any)));
} }
} }

View File

@ -313,12 +313,12 @@ impl View for ListView {
true true
} }
fn find_any<'a>(&mut self, selector: &Selector, fn call_on_any<'a>(&mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>) { mut callback: Box<FnMut(&mut Any) + 'a>) {
for view in self.children for view in self.children
.iter_mut() .iter_mut()
.filter_map(Child::view) { .filter_map(Child::view) {
view.find_any(selector, Box::new(|any| callback(any))); view.call_on_any(selector, Box::new(|any| callback(any)));
} }
} }

View File

@ -180,10 +180,10 @@ impl View for StackView {
} }
} }
fn find_any<'a>(&mut self, selector: &Selector, fn call_on_any<'a>(&mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>) { mut callback: Box<FnMut(&mut Any) + 'a>) {
for layer in &mut self.layers { for layer in &mut self.layers {
layer.view.find_any(selector, Box::new(|any| callback(any))); layer.view.call_on_any(selector, Box::new(|any| callback(any)));
} }
} }