mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Reverse View and AnyView
We now have `View: AnyView`
This commit is contained in:
parent
f27f7792df
commit
7db1ee7335
@ -9,7 +9,7 @@ use std::path::Path;
|
||||
use std::sync::mpsc;
|
||||
use theme;
|
||||
use vec::Vec2;
|
||||
use view::{self, AnyView, IntoBoxedView, Finder, Position, View};
|
||||
use view::{self, Finder, IntoBoxedView, Position, View};
|
||||
use views::{self, LayerPosition};
|
||||
|
||||
/// Identifies a screen in the cursive root.
|
||||
@ -472,7 +472,7 @@ impl Cursive {
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,22 @@
|
||||
use view::{AnyView, View};
|
||||
use view::{View};
|
||||
|
||||
/// Represents a type that can be made into a `Box<AnyView>`.
|
||||
pub trait IntoBoxedView {
|
||||
/// Returns a `Box<AnyView>`.
|
||||
fn as_boxed_view(self) -> Box<AnyView>;
|
||||
fn as_boxed_view(self) -> Box<View>;
|
||||
}
|
||||
|
||||
impl<T> IntoBoxedView for T
|
||||
where
|
||||
T: View,
|
||||
{
|
||||
fn as_boxed_view(self) -> Box<AnyView> {
|
||||
fn as_boxed_view(self) -> Box<View> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBoxedView for Box<AnyView> {
|
||||
fn as_boxed_view(self) -> Box<AnyView> {
|
||||
impl IntoBoxedView for Box<View> {
|
||||
fn as_boxed_view(self) -> Box<View> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBoxedView for Box<View> {
|
||||
fn as_boxed_view(self) -> Box<AnyView> {
|
||||
self.to_any()
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +51,6 @@ mod boxable;
|
||||
|
||||
mod into_boxed_view;
|
||||
|
||||
pub mod internal;
|
||||
|
||||
pub use self::into_boxed_view::IntoBoxedView;
|
||||
pub use self::boxable::Boxable;
|
||||
pub use self::identifiable::Identifiable;
|
||||
@ -72,7 +70,7 @@ use views::IdView;
|
||||
/// A view that can be downcasted to its concrete type.
|
||||
///
|
||||
/// This trait is automatically implemented for any `T: View`.
|
||||
pub trait AnyView: View {
|
||||
pub trait AnyView {
|
||||
/// Downcast self to a `Any`.
|
||||
fn as_any(&self) -> &Any;
|
||||
|
||||
@ -115,10 +113,7 @@ impl<T: View> AnyView for T {
|
||||
/// Main trait defining a view behaviour.
|
||||
///
|
||||
/// This is what you should implement to define a custom View.
|
||||
///
|
||||
/// You can ignore the `Any` and `ToAny` trait bound;
|
||||
/// they are implementation details, and will be implemented automatically.
|
||||
pub trait View: Any + internal::ToAny {
|
||||
pub trait View: Any + AnyView {
|
||||
/// Called when a key was pressed.
|
||||
///
|
||||
/// Default implementation just ignores it.
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -10,8 +10,8 @@ use std::cmp::max;
|
||||
use theme::ColorStyle;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use vec::{Vec2, Vec4};
|
||||
use view::{AnyView, Selector, View};
|
||||
use views::{AnyBox, Button, DummyView, SizedView, TextView};
|
||||
use view::{View, Selector};
|
||||
use views::{ViewBox, Button, DummyView, SizedView, TextView};
|
||||
|
||||
/// Identifies currently focused element in [`Dialog`].
|
||||
///
|
||||
@ -58,7 +58,7 @@ pub struct Dialog {
|
||||
title_position: HAlign,
|
||||
|
||||
// The actual inner view.
|
||||
content: SizedView<AnyBox>,
|
||||
content: SizedView<ViewBox>,
|
||||
|
||||
// Optional list of buttons under the main view.
|
||||
// Include the top-left corner.
|
||||
@ -90,7 +90,7 @@ impl Dialog {
|
||||
/// Creates a new `Dialog` with the given content.
|
||||
pub fn around<V: View + 'static>(view: V) -> Self {
|
||||
Dialog {
|
||||
content: SizedView::new(AnyBox::boxed(view)),
|
||||
content: SizedView::new(ViewBox::boxed(view)),
|
||||
buttons: Vec::new(),
|
||||
title: String::new(),
|
||||
title_position: HAlign::Center,
|
||||
@ -120,12 +120,12 @@ impl Dialog {
|
||||
/// .unwrap();
|
||||
/// assert_eq!(text_view.get_content().source(), "Hello!");
|
||||
/// ```
|
||||
pub fn get_content(&self) -> &AnyView {
|
||||
pub fn get_content(&self) -> &View {
|
||||
&*self.content.view
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@ impl Dialog {
|
||||
///
|
||||
/// Previous content will be dropped.
|
||||
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.
|
||||
|
@ -7,7 +7,7 @@ use std::any::Any;
|
||||
use std::cmp::min;
|
||||
use std::ops::Deref;
|
||||
use vec::Vec2;
|
||||
use view::{AnyView, Selector, SizeCache, View};
|
||||
use view::{Selector, SizeCache, View};
|
||||
|
||||
/// Arranges its children linearly according to its orientation.
|
||||
pub struct LinearLayout {
|
||||
@ -19,7 +19,7 @@ pub struct LinearLayout {
|
||||
}
|
||||
|
||||
struct Child {
|
||||
view: Box<AnyView>,
|
||||
view: Box<View>,
|
||||
// The last result from the child's required_size
|
||||
// Doesn't have to be what the child actually gets.
|
||||
size: Vec2,
|
||||
@ -33,7 +33,7 @@ impl Child {
|
||||
self.size
|
||||
}
|
||||
|
||||
fn as_view(&self) -> &AnyView {
|
||||
fn as_view(&self) -> &View {
|
||||
&*self.view
|
||||
}
|
||||
}
|
||||
@ -166,12 +166,12 @@ impl LinearLayout {
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,14 @@ use std::any::Any;
|
||||
use std::rc::Rc;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use vec::Vec2;
|
||||
use view::{AnyView, ScrollBase, Selector, View};
|
||||
use view::{ScrollBase, Selector, View};
|
||||
|
||||
/// Represents a child from a [`ListView`].
|
||||
///
|
||||
/// [`ListView`]: struct.ListView.html
|
||||
pub enum ListChild {
|
||||
/// A single row, with a label and a view.
|
||||
Row(String, Box<AnyView>),
|
||||
Row(String, Box<View>),
|
||||
/// A delimiter between groups.
|
||||
Delimiter,
|
||||
}
|
||||
@ -27,7 +27,7 @@ impl ListChild {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Option<&mut AnyView> {
|
||||
fn view(&mut self) -> Option<&mut View> {
|
||||
match *self {
|
||||
ListChild::Row(_, ref mut view) => Some(view.as_mut()),
|
||||
_ => None,
|
||||
|
@ -35,7 +35,7 @@ macro_rules! impl_enabled {
|
||||
}
|
||||
}
|
||||
|
||||
mod any_box;
|
||||
mod view_box;
|
||||
mod box_view;
|
||||
mod button;
|
||||
mod canvas;
|
||||
@ -62,7 +62,7 @@ mod text_area;
|
||||
mod text_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::button::Button;
|
||||
pub use self::canvas::Canvas;
|
||||
|
@ -7,9 +7,9 @@ use std::cell;
|
||||
use std::ops::Deref;
|
||||
use theme::ColorStyle;
|
||||
use vec::Vec2;
|
||||
use view::{AnyView, IntoBoxedView, Offset, Position, Selector, View,
|
||||
ViewWrapper};
|
||||
use views::{AnyBox, Layer, ShadowView};
|
||||
use view::{View, Offset, Position, Selector,
|
||||
ViewWrapper, IntoBoxedView};
|
||||
use views::{ViewBox, Layer, ShadowView};
|
||||
|
||||
/// Simple stack of views.
|
||||
/// 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
|
||||
pub fn get_inner(&self) -> &AnyView {
|
||||
pub fn get_inner(&self) -> &View {
|
||||
match *self {
|
||||
ChildWrapper::Shadow(ref shadow) => shadow.get_inner().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
|
||||
pub fn get_inner_mut(&mut self) -> &mut AnyView {
|
||||
pub fn get_inner_mut(&mut self) -> &mut View {
|
||||
match *self {
|
||||
ChildWrapper::Shadow(ref mut shadow) => {
|
||||
shadow.get_inner_mut().get_inner_mut()
|
||||
@ -153,7 +153,7 @@ impl<T: View> View for ChildWrapper<T> {
|
||||
}
|
||||
|
||||
struct Child {
|
||||
view: ChildWrapper<AnyBox>,
|
||||
view: ChildWrapper<ViewBox>,
|
||||
size: Vec2,
|
||||
placement: Placement,
|
||||
|
||||
@ -183,7 +183,7 @@ impl StackView {
|
||||
where
|
||||
T: IntoBoxedView,
|
||||
{
|
||||
let boxed = AnyBox::boxed(view);
|
||||
let boxed = ViewBox::boxed(view);
|
||||
self.layers.push(Child {
|
||||
view: ChildWrapper::Plain(Layer::new(boxed)),
|
||||
size: Vec2::zero(),
|
||||
@ -211,13 +211,13 @@ impl StackView {
|
||||
}
|
||||
|
||||
/// 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);
|
||||
self.layers.get(i).map(|child| child.view.get_inner())
|
||||
}
|
||||
|
||||
/// 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);
|
||||
self.layers
|
||||
.get_mut(i)
|
||||
@ -276,7 +276,7 @@ impl StackView {
|
||||
where
|
||||
T: IntoBoxedView,
|
||||
{
|
||||
let boxed = AnyBox::boxed(view);
|
||||
let boxed = ViewBox::boxed(view);
|
||||
self.layers.push(Child {
|
||||
// Skip padding for absolute/parent-placed views
|
||||
view: ChildWrapper::Shadow(
|
||||
@ -301,13 +301,13 @@ impl StackView {
|
||||
}
|
||||
|
||||
/// 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.layers
|
||||
.pop()
|
||||
.map(|child| child.view)
|
||||
.map(ChildWrapper::unwrap)
|
||||
.map(AnyBox::unwrap)
|
||||
.map(ViewBox::unwrap)
|
||||
}
|
||||
|
||||
/// Computes the offset of the current top view.
|
||||
@ -554,6 +554,22 @@ mod tests {
|
||||
use super::*;
|
||||
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]
|
||||
fn move_layer_works() {
|
||||
let mut stack = StackView::new()
|
||||
|
59
src/views/view_box.rs
Normal file
59
src/views/view_box.rs
Normal 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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user