mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 19:26:09 +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;
|
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`.
|
||||||
pub trait AnyView: View {
|
pub trait AnyView: View {
|
||||||
/// Downcast self to a `Any`.
|
/// Downcast self to a `Any`.
|
||||||
fn as_any(&self) -> &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.
|
/// Main trait defining a view behaviour.
|
||||||
|
///
|
||||||
|
/// This is what you should implement to define a custom View.
|
||||||
pub trait View: Any {
|
pub trait View: Any {
|
||||||
/// Called when a key was pressed.
|
/// 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.
|
// The main point of implementing ViewWrapper is to have View for free.
|
||||||
impl<T: ViewWrapper> View for T {
|
impl<T: ViewWrapper> View for T {
|
||||||
fn draw(&self, printer: &Printer) {
|
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 unicode_width::UnicodeWidthStr;
|
||||||
use vec::{Vec2, Vec4};
|
use vec::{Vec2, Vec4};
|
||||||
use view::{AnyView, Selector, View};
|
use view::{AnyView, Selector, View};
|
||||||
use views::{Button, DummyView, SizedView, TextView};
|
use views::{AnyBox, 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<Box<AnyView>>,
|
content: SizedView<AnyBox>,
|
||||||
|
|
||||||
// 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(Box::new(view)),
|
content: SizedView::new(AnyBox::boxed(view)),
|
||||||
buttons: Vec::new(),
|
buttons: Vec::new(),
|
||||||
title: String::new(),
|
title: String::new(),
|
||||||
title_position: HAlign::Center,
|
title_position: HAlign::Center,
|
||||||
@ -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(Box::new(view));
|
self.content = SizedView::new(AnyBox::boxed(view));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenient method to create a dialog with a simple text content.
|
/// 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 box_view;
|
||||||
mod button;
|
mod button;
|
||||||
mod canvas;
|
mod canvas;
|
||||||
@ -61,6 +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::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;
|
||||||
|
@ -8,7 +8,7 @@ use std::ops::Deref;
|
|||||||
use theme::ColorStyle;
|
use theme::ColorStyle;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{AnyView, Offset, Position, Selector, View, ViewWrapper};
|
use view::{AnyView, Offset, Position, Selector, View, ViewWrapper};
|
||||||
use views::{Layer, ShadowView};
|
use views::{AnyBox, 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.
|
||||||
@ -152,7 +152,7 @@ impl<T: View> View for ChildWrapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Child {
|
struct Child {
|
||||||
view: ChildWrapper<Box<AnyView>>,
|
view: ChildWrapper<AnyBox>,
|
||||||
size: Vec2,
|
size: Vec2,
|
||||||
placement: Placement,
|
placement: Placement,
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ impl StackView {
|
|||||||
where
|
where
|
||||||
T: 'static + View,
|
T: 'static + View,
|
||||||
{
|
{
|
||||||
let boxed: Box<AnyView> = Box::new(view);
|
let boxed = AnyBox::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(),
|
||||||
@ -275,7 +275,7 @@ impl StackView {
|
|||||||
where
|
where
|
||||||
T: 'static + View,
|
T: 'static + View,
|
||||||
{
|
{
|
||||||
let boxed: Box<AnyView> = Box::new(view);
|
let boxed = AnyBox::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(
|
||||||
@ -302,7 +302,11 @@ 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<AnyView>> {
|
||||||
self.bg_dirty.set(true);
|
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.
|
/// Computes the offset of the current top view.
|
||||||
|
Loading…
Reference in New Issue
Block a user