Reverse View and AnyView

We now have `View: AnyView`
This commit is contained in:
Alexandre Bury 2018-03-14 14:59:41 -07:00
parent f27f7792df
commit 7db1ee7335
10 changed files with 114 additions and 108 deletions

View File

@ -9,7 +9,7 @@ use std::path::Path;
use std::sync::mpsc; use std::sync::mpsc;
use theme; use theme;
use vec::Vec2; use vec::Vec2;
use view::{self, AnyView, IntoBoxedView, Finder, Position, View}; use view::{self, Finder, IntoBoxedView, Position, View};
use views::{self, LayerPosition}; use views::{self, LayerPosition};
/// Identifies a screen in the cursive root. /// Identifies a screen in the cursive root.
@ -472,7 +472,7 @@ impl Cursive {
} }
/// Convenient method to remove a layer from the current screen. /// Convenient method to remove a layer from the current screen.
pub fn pop_layer(&mut self) -> Option<Box<AnyView>> { pub fn pop_layer(&mut self) -> Option<Box<View>> {
self.screen_mut().pop_layer() self.screen_mut().pop_layer()
} }

View File

@ -1,28 +1,22 @@
use view::{AnyView, View}; use view::{View};
/// Represents a type that can be made into a `Box<AnyView>`. /// Represents a type that can be made into a `Box<AnyView>`.
pub trait IntoBoxedView { pub trait IntoBoxedView {
/// Returns a `Box<AnyView>`. /// Returns a `Box<AnyView>`.
fn as_boxed_view(self) -> Box<AnyView>; fn as_boxed_view(self) -> Box<View>;
} }
impl<T> IntoBoxedView for T impl<T> IntoBoxedView for T
where where
T: View, T: View,
{ {
fn as_boxed_view(self) -> Box<AnyView> { fn as_boxed_view(self) -> Box<View> {
Box::new(self) Box::new(self)
} }
} }
impl IntoBoxedView for Box<AnyView> { impl IntoBoxedView for Box<View> {
fn as_boxed_view(self) -> Box<AnyView> { fn as_boxed_view(self) -> Box<View> {
self self
} }
} }
impl IntoBoxedView for Box<View> {
fn as_boxed_view(self) -> Box<AnyView> {
self.to_any()
}
}

View File

@ -51,8 +51,6 @@ mod boxable;
mod into_boxed_view; mod into_boxed_view;
pub mod internal;
pub use self::into_boxed_view::IntoBoxedView; pub use self::into_boxed_view::IntoBoxedView;
pub use self::boxable::Boxable; pub use self::boxable::Boxable;
pub use self::identifiable::Identifiable; pub use self::identifiable::Identifiable;
@ -72,7 +70,7 @@ use views::IdView;
/// A view that can be downcasted to its concrete type. /// A view that can be downcasted to its concrete type.
/// ///
/// This trait is automatically implemented for any `T: View`. /// This trait is automatically implemented for any `T: View`.
pub trait AnyView: View { pub trait AnyView {
/// Downcast self to a `Any`. /// Downcast self to a `Any`.
fn as_any(&self) -> &Any; fn as_any(&self) -> &Any;
@ -115,10 +113,7 @@ impl<T: View> AnyView for T {
/// Main trait defining a view behaviour. /// Main trait defining a view behaviour.
/// ///
/// This is what you should implement to define a custom View. /// This is what you should implement to define a custom View.
/// pub trait View: Any + AnyView {
/// You can ignore the `Any` and `ToAny` trait bound;
/// they are implementation details, and will be implemented automatically.
pub trait View: Any + internal::ToAny {
/// Called when a key was pressed. /// Called when a key was pressed.
/// ///
/// Default implementation just ignores it. /// Default implementation just ignores it.

View File

@ -1,58 +0,0 @@
use std::ops::{Deref, DerefMut};
use view::{AnyView, IntoBoxedView, ViewWrapper};
/// A boxed `AnyView`.
///
/// It derefs to the wrapped view.
pub struct AnyBox {
view: Box<AnyView>,
}
impl AnyBox {
/// Creates a new `AnyBox` around the given boxed view.
pub fn new(view: Box<AnyView>) -> Self {
AnyBox { view }
}
/// Box the given view
pub fn boxed<T: IntoBoxedView>(view: T) -> Self {
AnyBox::new(view.as_boxed_view())
}
/// Returns the inner boxed view.
pub fn unwrap(self) -> Box<AnyView> {
self.view
}
}
impl Deref for AnyBox {
type Target = AnyView;
fn deref(&self) -> &AnyView {
&*self.view
}
}
impl DerefMut for AnyBox {
fn deref_mut(&mut self) -> &mut AnyView {
&mut *self.view
}
}
impl ViewWrapper for AnyBox {
type V = AnyView;
fn with_view<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&Self::V) -> R,
{
Some(f(&*self.view))
}
fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where
F: FnOnce(&mut Self::V) -> R,
{
Some(f(&mut *self.view))
}
}

View File

@ -10,8 +10,8 @@ use std::cmp::max;
use theme::ColorStyle; use theme::ColorStyle;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use vec::{Vec2, Vec4}; use vec::{Vec2, Vec4};
use view::{AnyView, Selector, View}; use view::{View, Selector};
use views::{AnyBox, Button, DummyView, SizedView, TextView}; use views::{ViewBox, Button, DummyView, SizedView, TextView};
/// Identifies currently focused element in [`Dialog`]. /// Identifies currently focused element in [`Dialog`].
/// ///
@ -58,7 +58,7 @@ pub struct Dialog {
title_position: HAlign, title_position: HAlign,
// The actual inner view. // The actual inner view.
content: SizedView<AnyBox>, content: SizedView<ViewBox>,
// Optional list of buttons under the main view. // Optional list of buttons under the main view.
// Include the top-left corner. // Include the top-left corner.
@ -90,7 +90,7 @@ impl Dialog {
/// Creates a new `Dialog` with the given content. /// Creates a new `Dialog` with the given content.
pub fn around<V: View + 'static>(view: V) -> Self { pub fn around<V: View + 'static>(view: V) -> Self {
Dialog { Dialog {
content: SizedView::new(AnyBox::boxed(view)), content: SizedView::new(ViewBox::boxed(view)),
buttons: Vec::new(), buttons: Vec::new(),
title: String::new(), title: String::new(),
title_position: HAlign::Center, title_position: HAlign::Center,
@ -120,12 +120,12 @@ impl Dialog {
/// .unwrap(); /// .unwrap();
/// assert_eq!(text_view.get_content().source(), "Hello!"); /// assert_eq!(text_view.get_content().source(), "Hello!");
/// ``` /// ```
pub fn get_content(&self) -> &AnyView { pub fn get_content(&self) -> &View {
&*self.content.view &*self.content.view
} }
/// Gets mutable access to the content. /// Gets mutable access to the content.
pub fn get_content_mut(&mut self) -> &mut AnyView { pub fn get_content_mut(&mut self) -> &mut View {
&mut *self.content.view &mut *self.content.view
} }
@ -133,7 +133,7 @@ impl Dialog {
/// ///
/// Previous content will be dropped. /// Previous content will be dropped.
pub fn set_content<V: View + 'static>(&mut self, view: V) { pub fn set_content<V: View + 'static>(&mut self, view: V) {
self.content = SizedView::new(AnyBox::boxed(view)); self.content = SizedView::new(ViewBox::boxed(view));
} }
/// Convenient method to create a dialog with a simple text content. /// Convenient method to create a dialog with a simple text content.

View File

@ -7,7 +7,7 @@ use std::any::Any;
use std::cmp::min; use std::cmp::min;
use std::ops::Deref; use std::ops::Deref;
use vec::Vec2; use vec::Vec2;
use view::{AnyView, Selector, SizeCache, View}; use view::{Selector, SizeCache, View};
/// Arranges its children linearly according to its orientation. /// Arranges its children linearly according to its orientation.
pub struct LinearLayout { pub struct LinearLayout {
@ -19,7 +19,7 @@ pub struct LinearLayout {
} }
struct Child { struct Child {
view: Box<AnyView>, view: Box<View>,
// The last result from the child's required_size // The last result from the child's required_size
// Doesn't have to be what the child actually gets. // Doesn't have to be what the child actually gets.
size: Vec2, size: Vec2,
@ -33,7 +33,7 @@ impl Child {
self.size self.size
} }
fn as_view(&self) -> &AnyView { fn as_view(&self) -> &View {
&*self.view &*self.view
} }
} }
@ -166,12 +166,12 @@ impl LinearLayout {
} }
/// Returns a reference to a child. /// Returns a reference to a child.
pub fn get_child(&self, i: usize) -> Option<&AnyView> { pub fn get_child(&self, i: usize) -> Option<&View> {
self.children.get(i).map(|child| &*child.view) self.children.get(i).map(|child| &*child.view)
} }
/// Returns a mutable reference to a child. /// Returns a mutable reference to a child.
pub fn get_child_mut(&mut self, i: usize) -> Option<&mut AnyView> { 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)
} }

View File

@ -7,14 +7,14 @@ use std::any::Any;
use std::rc::Rc; use std::rc::Rc;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use vec::Vec2; use vec::Vec2;
use view::{AnyView, ScrollBase, Selector, View}; use view::{ScrollBase, Selector, View};
/// Represents a child from a [`ListView`]. /// Represents a child from a [`ListView`].
/// ///
/// [`ListView`]: struct.ListView.html /// [`ListView`]: struct.ListView.html
pub enum ListChild { pub enum ListChild {
/// A single row, with a label and a view. /// A single row, with a label and a view.
Row(String, Box<AnyView>), Row(String, Box<View>),
/// A delimiter between groups. /// A delimiter between groups.
Delimiter, Delimiter,
} }
@ -27,7 +27,7 @@ impl ListChild {
} }
} }
fn view(&mut self) -> Option<&mut AnyView> { fn view(&mut self) -> Option<&mut View> {
match *self { match *self {
ListChild::Row(_, ref mut view) => Some(view.as_mut()), ListChild::Row(_, ref mut view) => Some(view.as_mut()),
_ => None, _ => None,

View File

@ -35,7 +35,7 @@ macro_rules! impl_enabled {
} }
} }
mod any_box; mod view_box;
mod box_view; mod box_view;
mod button; mod button;
mod canvas; mod canvas;
@ -62,7 +62,7 @@ mod text_area;
mod text_view; mod text_view;
mod tracked_view; mod tracked_view;
pub use self::any_box::AnyBox; pub use self::view_box::ViewBox;
pub use self::box_view::BoxView; pub use self::box_view::BoxView;
pub use self::button::Button; pub use self::button::Button;
pub use self::canvas::Canvas; pub use self::canvas::Canvas;

View File

@ -7,9 +7,9 @@ use std::cell;
use std::ops::Deref; use std::ops::Deref;
use theme::ColorStyle; use theme::ColorStyle;
use vec::Vec2; use vec::Vec2;
use view::{AnyView, IntoBoxedView, Offset, Position, Selector, View, use view::{View, Offset, Position, Selector,
ViewWrapper}; ViewWrapper, IntoBoxedView};
use views::{AnyBox, Layer, ShadowView}; use views::{ViewBox, Layer, ShadowView};
/// Simple stack of views. /// Simple stack of views.
/// Only the top-most view is active and can receive input. /// Only the top-most view is active and can receive input.
@ -74,9 +74,9 @@ impl<T: View> ChildWrapper<T> {
} }
} }
impl<T: AnyView> ChildWrapper<T> { impl<T: View> ChildWrapper<T> {
/// Returns a reference to the inner view /// Returns a reference to the inner view
pub fn get_inner(&self) -> &AnyView { pub fn get_inner(&self) -> &View {
match *self { match *self {
ChildWrapper::Shadow(ref shadow) => shadow.get_inner().get_inner(), ChildWrapper::Shadow(ref shadow) => shadow.get_inner().get_inner(),
ChildWrapper::Plain(ref layer) => layer.get_inner(), ChildWrapper::Plain(ref layer) => layer.get_inner(),
@ -84,7 +84,7 @@ impl<T: AnyView> ChildWrapper<T> {
} }
/// Returns a mutable reference to the inner view /// Returns a mutable reference to the inner view
pub fn get_inner_mut(&mut self) -> &mut AnyView { pub fn get_inner_mut(&mut self) -> &mut View {
match *self { match *self {
ChildWrapper::Shadow(ref mut shadow) => { ChildWrapper::Shadow(ref mut shadow) => {
shadow.get_inner_mut().get_inner_mut() shadow.get_inner_mut().get_inner_mut()
@ -153,7 +153,7 @@ impl<T: View> View for ChildWrapper<T> {
} }
struct Child { struct Child {
view: ChildWrapper<AnyBox>, view: ChildWrapper<ViewBox>,
size: Vec2, size: Vec2,
placement: Placement, placement: Placement,
@ -183,7 +183,7 @@ impl StackView {
where where
T: IntoBoxedView, T: IntoBoxedView,
{ {
let boxed = AnyBox::boxed(view); let boxed = ViewBox::boxed(view);
self.layers.push(Child { self.layers.push(Child {
view: ChildWrapper::Plain(Layer::new(boxed)), view: ChildWrapper::Plain(Layer::new(boxed)),
size: Vec2::zero(), size: Vec2::zero(),
@ -211,13 +211,13 @@ impl StackView {
} }
/// Returns a reference to the layer at the given position. /// Returns a reference to the layer at the given position.
pub fn get(&self, pos: LayerPosition) -> Option<&AnyView> { pub fn get(&self, pos: LayerPosition) -> Option<&View> {
let i = self.get_index(pos); let i = self.get_index(pos);
self.layers.get(i).map(|child| child.view.get_inner()) self.layers.get(i).map(|child| child.view.get_inner())
} }
/// Returns a mutable reference to the layer at the given position. /// Returns a mutable reference to the layer at the given position.
pub fn get_mut(&mut self, pos: LayerPosition) -> Option<&mut AnyView> { pub fn get_mut(&mut self, pos: LayerPosition) -> Option<&mut View> {
let i = self.get_index(pos); let i = self.get_index(pos);
self.layers self.layers
.get_mut(i) .get_mut(i)
@ -276,7 +276,7 @@ impl StackView {
where where
T: IntoBoxedView, T: IntoBoxedView,
{ {
let boxed = AnyBox::boxed(view); let boxed = ViewBox::boxed(view);
self.layers.push(Child { self.layers.push(Child {
// Skip padding for absolute/parent-placed views // Skip padding for absolute/parent-placed views
view: ChildWrapper::Shadow( view: ChildWrapper::Shadow(
@ -301,13 +301,13 @@ impl StackView {
} }
/// Remove the top-most layer. /// Remove the top-most layer.
pub fn pop_layer(&mut self) -> Option<Box<AnyView>> { pub fn pop_layer(&mut self) -> Option<Box<View>> {
self.bg_dirty.set(true); self.bg_dirty.set(true);
self.layers self.layers
.pop() .pop()
.map(|child| child.view) .map(|child| child.view)
.map(ChildWrapper::unwrap) .map(ChildWrapper::unwrap)
.map(AnyBox::unwrap) .map(ViewBox::unwrap)
} }
/// Computes the offset of the current top view. /// Computes the offset of the current top view.
@ -554,6 +554,22 @@ mod tests {
use super::*; use super::*;
use views::TextView; use views::TextView;
#[test]
fn pop_add() {
let mut stack = StackView::new();
stack.add_layer(TextView::new("1"));
for _ in 0..20 {
let layer = stack.pop_layer().unwrap();
stack.add_layer(layer);
}
let layer = stack.pop_layer().unwrap();
let text: Box<TextView> = layer.as_boxed_any().downcast().unwrap();
assert_eq!(text.get_content().source(), "1");
}
#[test] #[test]
fn move_layer_works() { fn move_layer_works() {
let mut stack = StackView::new() let mut stack = StackView::new()

59
src/views/view_box.rs Normal file
View File

@ -0,0 +1,59 @@
use std::ops::{Deref, DerefMut};
use view::{View, ViewWrapper, IntoBoxedView};
/// A boxed `View`.
///
/// It derefs to the wrapped view.
pub struct ViewBox {
view: Box<View>,
}
impl ViewBox {
/// Creates a new `ViewBox` around the given boxed view.
pub fn new(view: Box<View>) -> Self {
ViewBox { view }
}
/// Box the given view
pub fn boxed<T>(view: T) -> Self
where T: IntoBoxedView {
ViewBox::new(view.as_boxed_view())
}
/// Returns the inner boxed view.
pub fn unwrap(self) -> Box<View> {
self.view
}
}
impl Deref for ViewBox {
type Target = View;
fn deref(&self) -> &View {
&*self.view
}
}
impl DerefMut for ViewBox {
fn deref_mut(&mut self) -> &mut View {
&mut *self.view
}
}
impl ViewWrapper for ViewBox {
type V = View;
fn with_view<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&Self::V) -> R,
{
Some(f(&*self.view))
}
fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where
F: FnOnce(&mut Self::V) -> R,
{
Some(f(&mut *self.view))
}
}