Merge IdView and RefCellView

And remove `with_id_mut`
This commit is contained in:
Alexandre Bury 2017-03-25 21:56:31 -07:00
parent 146ebd8931
commit c3c69e7892
7 changed files with 66 additions and 91 deletions

View File

@ -10,9 +10,9 @@ fn main() {
// Create a dialog with 2 edit fields, and a text view. // Create a dialog with 2 edit fields, and a text view.
// The text view indicates when the 2 fields content match. // The text view indicates when the 2 fields content match.
siv.add_layer(Dialog::around(LinearLayout::vertical() siv.add_layer(Dialog::around(LinearLayout::vertical()
.child(EditView::new().on_edit(on_edit).with_id_mut("1")) .child(EditView::new().on_edit(on_edit).with_id("1"))
.child(EditView::new().on_edit(on_edit).with_id_mut("2")) .child(EditView::new().on_edit(on_edit).with_id("2"))
.child(TextView::new("match").with_id_mut("match")) .child(TextView::new("match").with_id("match"))
.fixed_width(10)) .fixed_width(10))
.button("Quit", Cursive::quit)); .button("Quit", Cursive::quit));

View File

@ -430,16 +430,16 @@ impl Cursive {
self.find(&view::Selector::Id(id), callback) self.find(&view::Selector::Id(id), callback)
} }
/// Convenient method to find a view wrapped in [`RefCellView`]. /// Convenient method to find a view wrapped in [`IdView`].
/// ///
/// This looks for a `RefCellView<V>` with the given ID, and return /// This looks for a `IdView<V>` with the given ID, and return
/// a mutable reference to the wrapped view. /// a mutable reference to the wrapped view.
/// ///
/// [`RefCellView`]: views/struct.RefCellView.html /// [`IdView`]: views/struct.IdView.html
pub fn find_id<V>(&mut self, id: &str) -> Option<views::ViewRef<V>> pub fn find_id<V>(&mut self, id: &str) -> Option<views::ViewRef<V>>
where V: View + Any where V: View + Any
{ {
self.call_on_id(id, views::RefCellView::<V>::get_mut) self.call_on_id(id, views::IdView::<V>::get_mut)
} }
/// Moves the focus to the view identified by `id`. /// Moves the focus to the view identified by `id`.

View File

@ -1,5 +1,5 @@
use view::View; use view::View;
use views::{IdView, RefCellView}; use views::IdView;
/// Makes a view wrappable in an [`IdView`]. /// Makes a view wrappable in an [`IdView`].
/// ///
@ -8,19 +8,9 @@ pub trait Identifiable: View + Sized {
/// Wraps this view into an `IdView` with the given id. /// Wraps this view into an `IdView` with the given id.
/// ///
/// This is just a shortcut for `IdView::new(id, self)` /// This is just a shortcut for `IdView::new(id, self)`
fn with_id(self, id: &str) -> IdView<Self> { fn with_id<S: Into<String>>(self, id: S) -> IdView<Self> {
IdView::new(id, self) IdView::new(id, self)
} }
/// Wraps this view into both a [`RefCellView`] and an `IdView`.
///
/// This allows to call [`Cursive::find_id_mut`].
///
/// [`RefCellView`]: ../views/struct.RefCellView.html
/// [`Cursive::find_id_mut`]: ../struct.Cursive.html#method.find_id_mut
fn with_id_mut(self, id: &str) -> IdView<RefCellView<Self>> {
RefCellView::new(self).with_id(id)
}
} }
/// Any `View` implements this trait. /// Any `View` implements this trait.

View File

@ -66,7 +66,7 @@ use Printer;
use direction::Direction; use direction::Direction;
use event::{Event, EventResult}; use event::{Event, EventResult};
use vec::Vec2; use vec::Vec2;
use views::RefCellView; use views::IdView;
use std::any::Any; use std::any::Any;
@ -185,8 +185,8 @@ impl<T: View> Finder for T {
callback.take() { callback.take() {
if v.is::<V>() { if v.is::<V>() {
*result_ref = v.downcast_mut::<V>().map(|v| callback(v)); *result_ref = v.downcast_mut::<V>().map(|v| callback(v));
} else if v.is::<RefCellView<V>>() { } else if v.is::<IdView<V>>() {
*result_ref = v.downcast_mut::<RefCellView<V>>() *result_ref = v.downcast_mut::<IdView<V>>()
.and_then(|v| v.with_view_mut(callback)); .and_then(|v| v.with_view_mut(callback));
} }
}; };

View File

@ -1,38 +1,74 @@
use std::any::Any; use owning_ref::{RcRef, OwningHandle};
use std::cell::{RefCell, RefMut};
use std::any::Any;
use std::rc::Rc;
use view::{Selector, View, ViewWrapper}; use view::{Selector, View, ViewWrapper};
/// Wrapper view that allows to select its content with a fixed string id. /// Wrapper around a view to provide interior mutability.
pub struct IdView<T: View> { pub struct IdView<V: View> {
view: T, view: Rc<RefCell<V>>,
id: String, id: String,
} }
impl<T: View> IdView<T> { /// Mutable reference to a view.
/// Wraps the given view. It will be selectable with the given id. pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
pub fn new(id: &str, view: T) -> Self {
impl<V: View> IdView<V> {
/// Wraps `view` in a new `IdView`.
pub fn new<S: Into<String>>(id: S, view: V) -> Self {
IdView { IdView {
view: view, view: Rc::new(RefCell::new(view)),
id: id.to_string(), id: id.into(),
} }
} }
/// Gets mutable access to the inner view.
pub fn get_mut(&mut self) -> ViewRef<V> {
// TODO: return a standalone item (not tied to our lifetime)
// that bundles `self.view.clone()` and allow mutable reference to
// the inner view.
let cell_ref = RcRef::new(self.view.clone());
OwningHandle::new(cell_ref,
|x| unsafe { x.as_ref() }.unwrap().borrow_mut())
}
} }
impl<T: View + Any> ViewWrapper for IdView<T> { impl<T: View + 'static> ViewWrapper for IdView<T> {
wrap_impl!(self.view: T); type V = T;
fn with_view<F, R>(&self, f: F) -> Option<R>
where F: FnOnce(&Self::V) -> R
{
self.view
.try_borrow()
.ok()
.map(|v| f(&*v))
}
fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where F: FnOnce(&mut Self::V) -> R
{
self.view
.try_borrow_mut()
.ok()
.map(|mut v| f(&mut *v))
}
fn wrap_find_any<'a>(&mut self, selector: &Selector, fn wrap_find_any<'a>(&mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>) { mut callback: Box<for<'b> FnMut(&'b mut Any) + 'a>) {
match selector { let result = match selector {
&Selector::Id(id) if id == self.id => callback(&mut self.view), &Selector::Id(id) if id == self.id => callback(self),
s => self.view.find_any(s, callback), s => self.view.borrow_mut().find_any(s, callback),
} };
result
} }
fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> { fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
match selector { match selector {
&Selector::Id(id) if id == self.id => Ok(()), &Selector::Id(id) if id == self.id => Ok(()),
s => self.view.focus_view(s), s => self.view.borrow_mut().focus_view(s),
} }
} }
} }

View File

@ -52,7 +52,6 @@ mod menu_popup;
mod panel; mod panel;
mod progress_bar; mod progress_bar;
mod radio; mod radio;
mod refcell_view;
mod select_view; mod select_view;
mod slider_view; mod slider_view;
mod shadow_view; mod shadow_view;
@ -69,7 +68,7 @@ pub use self::checkbox::Checkbox;
pub use self::dialog::Dialog; pub use self::dialog::Dialog;
pub use self::dummy::DummyView; pub use self::dummy::DummyView;
pub use self::edit_view::EditView; pub use self::edit_view::EditView;
pub use self::id_view::IdView; pub use self::id_view::{IdView, ViewRef};
pub use self::key_event_view::KeyEventView; pub use self::key_event_view::KeyEventView;
pub use self::layer::Layer; pub use self::layer::Layer;
pub use self::linear_layout::LinearLayout; pub use self::linear_layout::LinearLayout;
@ -79,7 +78,6 @@ pub use self::menubar::Menubar;
pub use self::panel::Panel; pub use self::panel::Panel;
pub use self::progress_bar::{Counter, ProgressBar}; pub use self::progress_bar::{Counter, ProgressBar};
pub use self::radio::{RadioGroup, RadioButton}; pub use self::radio::{RadioGroup, RadioButton};
pub use self::refcell_view::{RefCellView, ViewRef};
pub use self::select_view::SelectView; pub use self::select_view::SelectView;
pub use self::shadow_view::ShadowView; pub use self::shadow_view::ShadowView;
pub use self::sized_view::SizedView; pub use self::sized_view::SizedView;

View File

@ -1,49 +0,0 @@
use owning_ref::{RcRef, OwningHandle};
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use view::{View, ViewWrapper};
/// Wrapper around a view to provide interior mutability.
pub struct RefCellView<V: View> {
view: Rc<RefCell<V>>,
}
/// Mutable reference to a view.
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
impl<V: View> RefCellView<V> {
/// Wraps `view` in a new `RefCellView`.
pub fn new(view: V) -> Self {
RefCellView { view: Rc::new(RefCell::new(view)) }
}
/// Gets mutable access to the inner view.
pub fn get_mut(&mut self) -> ViewRef<V> {
// TODO: return a standalone item (not tied to our lifetime)
// that bundles `self.view.clone()` and allow mutable reference to
// the inner view.
let cell_ref = RcRef::new(self.view.clone());
OwningHandle::new(cell_ref,
|x| unsafe { x.as_ref() }.unwrap().borrow_mut())
}
}
impl<T: View> ViewWrapper for RefCellView<T> {
type V = T;
fn with_view<F, R>(&self, f: F) -> Option<R>
where F: FnOnce(&Self::V) -> R
{
self.view.try_borrow().ok().map(|v| f(&*v))
}
fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where F: FnOnce(&mut Self::V) -> R
{
self.view.try_borrow_mut().ok().map(|mut v| f(&mut *v))
}
}