mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Add BoxableView
and AnyBox
And remove `impl ViewWrapper for T: Deref<View>` This means `Box<View>` doesn't implement `View` anymore.
This commit is contained in:
parent
dea226a095
commit
e4bf9accc3
@ -65,6 +65,8 @@ use vec::Vec2;
|
||||
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 {
|
||||
/// Downcast self to a `Any`.
|
||||
fn as_any(&self) -> &Any;
|
||||
@ -105,7 +107,30 @@ impl<T: View> AnyView for T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a type that can be made into a `Box<AnyView>`.
|
||||
pub trait BoxableView {
|
||||
/// Returns a `Box<AnyView>`.
|
||||
fn as_boxed_view(self) -> Box<AnyView>;
|
||||
}
|
||||
|
||||
impl<T> BoxableView for T
|
||||
where
|
||||
T: View,
|
||||
{
|
||||
fn as_boxed_view(self) -> Box<AnyView> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxableView for Box<AnyView> {
|
||||
fn as_boxed_view(self) -> Box<AnyView> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Main trait defining a view behaviour.
|
||||
///
|
||||
/// This is what you should implement to define a custom View.
|
||||
pub trait View: Any {
|
||||
/// Called when a key was pressed.
|
||||
///
|
||||
|
@ -95,32 +95,6 @@ pub trait ViewWrapper: 'static {
|
||||
}
|
||||
}
|
||||
|
||||
// Some types easily implement ViewWrapper.
|
||||
// This includes Box<T: View>
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
impl<U, T> ViewWrapper for T
|
||||
where
|
||||
U: View + ?Sized,
|
||||
T: Deref<Target = U> + DerefMut + 'static,
|
||||
{
|
||||
type V = U;
|
||||
|
||||
fn with_view<F, R>(&self, f: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(&Self::V) -> R,
|
||||
{
|
||||
Some(f(self.deref()))
|
||||
}
|
||||
|
||||
fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(&mut Self::V) -> R,
|
||||
{
|
||||
Some(f(self.deref_mut()))
|
||||
}
|
||||
}
|
||||
|
||||
// The main point of implementing ViewWrapper is to have View for free.
|
||||
impl<T: ViewWrapper> View for T {
|
||||
fn draw(&self, printer: &Printer) {
|
||||
|
56
src/views/any_box.rs
Normal file
56
src/views/any_box.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use view::{AnyView, View, ViewWrapper};
|
||||
|
||||
/// A boxed `AnyView`.
|
||||
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: View>(view: T) -> Self {
|
||||
AnyBox::new(Box::new(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))
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ use theme::ColorStyle;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use vec::{Vec2, Vec4};
|
||||
use view::{AnyView, Selector, View};
|
||||
use views::{Button, DummyView, SizedView, TextView};
|
||||
use views::{AnyBox, 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<Box<AnyView>>,
|
||||
content: SizedView<AnyBox>,
|
||||
|
||||
// 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(Box::new(view)),
|
||||
content: SizedView::new(AnyBox::boxed(view)),
|
||||
buttons: Vec::new(),
|
||||
title: String::new(),
|
||||
title_position: HAlign::Center,
|
||||
@ -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(Box::new(view));
|
||||
self.content = SizedView::new(AnyBox::boxed(view));
|
||||
}
|
||||
|
||||
/// Convenient method to create a dialog with a simple text content.
|
||||
|
@ -35,6 +35,7 @@ macro_rules! impl_enabled {
|
||||
}
|
||||
}
|
||||
|
||||
mod any_box;
|
||||
mod box_view;
|
||||
mod button;
|
||||
mod canvas;
|
||||
@ -61,6 +62,7 @@ mod text_area;
|
||||
mod text_view;
|
||||
mod tracked_view;
|
||||
|
||||
pub use self::any_box::AnyBox;
|
||||
pub use self::box_view::BoxView;
|
||||
pub use self::button::Button;
|
||||
pub use self::canvas::Canvas;
|
||||
|
@ -8,7 +8,7 @@ use std::ops::Deref;
|
||||
use theme::ColorStyle;
|
||||
use vec::Vec2;
|
||||
use view::{AnyView, Offset, Position, Selector, View, ViewWrapper};
|
||||
use views::{Layer, ShadowView};
|
||||
use views::{AnyBox, Layer, ShadowView};
|
||||
|
||||
/// Simple stack of views.
|
||||
/// Only the top-most view is active and can receive input.
|
||||
@ -152,7 +152,7 @@ impl<T: View> View for ChildWrapper<T> {
|
||||
}
|
||||
|
||||
struct Child {
|
||||
view: ChildWrapper<Box<AnyView>>,
|
||||
view: ChildWrapper<AnyBox>,
|
||||
size: Vec2,
|
||||
placement: Placement,
|
||||
|
||||
@ -182,7 +182,7 @@ impl StackView {
|
||||
where
|
||||
T: 'static + View,
|
||||
{
|
||||
let boxed: Box<AnyView> = Box::new(view);
|
||||
let boxed = AnyBox::boxed(view);
|
||||
self.layers.push(Child {
|
||||
view: ChildWrapper::Plain(Layer::new(boxed)),
|
||||
size: Vec2::zero(),
|
||||
@ -275,7 +275,7 @@ impl StackView {
|
||||
where
|
||||
T: 'static + View,
|
||||
{
|
||||
let boxed: Box<AnyView> = Box::new(view);
|
||||
let boxed = AnyBox::boxed(view);
|
||||
self.layers.push(Child {
|
||||
// Skip padding for absolute/parent-placed views
|
||||
view: ChildWrapper::Shadow(
|
||||
@ -302,7 +302,11 @@ impl StackView {
|
||||
/// Remove the top-most layer.
|
||||
pub fn pop_layer(&mut self) -> Option<Box<AnyView>> {
|
||||
self.bg_dirty.set(true);
|
||||
self.layers.pop().map(|child| child.view.unwrap())
|
||||
self.layers
|
||||
.pop()
|
||||
.map(|child| child.view)
|
||||
.map(ChildWrapper::unwrap)
|
||||
.map(AnyBox::unwrap)
|
||||
}
|
||||
|
||||
/// Computes the offset of the current top view.
|
||||
|
Loading…
Reference in New Issue
Block a user