mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Make AnyCb
take a &mut dyn View
and add Cursive::debug_name
This commit is contained in:
parent
5423a9a003
commit
4c5e4abe49
@ -545,7 +545,7 @@ impl Cursive {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Option<R>
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
self.root.call_on(sel, callback)
|
self.root.call_on(sel, callback)
|
||||||
@ -577,7 +577,7 @@ impl Cursive {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Option<R>
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
self.call_on(&view::Selector::Name(name), callback)
|
self.call_on(&view::Selector::Name(name), callback)
|
||||||
@ -587,7 +587,7 @@ impl Cursive {
|
|||||||
#[deprecated(note = "`call_on_id` is being renamed to `call_on_name`")]
|
#[deprecated(note = "`call_on_id` is being renamed to `call_on_name`")]
|
||||||
pub fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
pub fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
self.call_on_name(id, callback)
|
self.call_on_name(id, callback)
|
||||||
@ -640,7 +640,7 @@ impl Cursive {
|
|||||||
/// [`ViewRef`]: views::ViewRef
|
/// [`ViewRef`]: views::ViewRef
|
||||||
pub fn find_name<V>(&mut self, id: &str) -> Option<views::ViewRef<V>>
|
pub fn find_name<V>(&mut self, id: &str) -> Option<views::ViewRef<V>>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
{
|
{
|
||||||
self.call_on_name(id, views::NamedView::<V>::get_mut)
|
self.call_on_name(id, views::NamedView::<V>::get_mut)
|
||||||
}
|
}
|
||||||
@ -649,7 +649,7 @@ impl Cursive {
|
|||||||
#[deprecated(note = "`find_id` is being renamed to `find_name`")]
|
#[deprecated(note = "`find_id` is being renamed to `find_name`")]
|
||||||
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
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
{
|
{
|
||||||
self.find_name(id)
|
self.find_name(id)
|
||||||
}
|
}
|
||||||
@ -706,6 +706,9 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// If an event matches the given trigger, it will not be sent to the view
|
/// If an event matches the given trigger, it will not be sent to the view
|
||||||
/// tree and will go to the given callback instead.
|
/// tree and will go to the given callback instead.
|
||||||
|
///
|
||||||
|
/// Note that regular "post-event" callbacks will also be skipped for
|
||||||
|
/// these events.
|
||||||
pub fn set_on_pre_event<F, E>(&mut self, trigger: E, cb: F)
|
pub fn set_on_pre_event<F, E>(&mut self, trigger: E, cb: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Cursive) + 'static,
|
F: FnMut(&mut Cursive) + 'static,
|
||||||
@ -714,6 +717,34 @@ impl Cursive {
|
|||||||
self.root.set_on_pre_event(trigger, crate::immut1!(cb));
|
self.root.set_on_pre_event(trigger, crate::immut1!(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers an inner priority callback.
|
||||||
|
///
|
||||||
|
/// See [`OnEventView`] for more information.
|
||||||
|
///
|
||||||
|
/// [`OnEventView`]: crate::views::OnEventView::set_on_pre_event_inner()
|
||||||
|
pub fn set_on_pre_event_inner<E, F>(&mut self, trigger: E, cb: F)
|
||||||
|
where
|
||||||
|
E: Into<crate::event::EventTrigger>,
|
||||||
|
F: Fn(&Event) -> Option<EventResult> + 'static,
|
||||||
|
{
|
||||||
|
self.root
|
||||||
|
.set_on_pre_event_inner(trigger, move |_, event| cb(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers an inner callback.
|
||||||
|
///
|
||||||
|
/// See [`OnEventView`] for more information.
|
||||||
|
///
|
||||||
|
/// [`OnEventView`]: crate::views::OnEventView::set_on_event_inner()
|
||||||
|
pub fn set_on_event_inner<E, F>(&mut self, trigger: E, cb: F)
|
||||||
|
where
|
||||||
|
E: Into<crate::event::EventTrigger>,
|
||||||
|
F: Fn(&Event) -> Option<EventResult> + 'static,
|
||||||
|
{
|
||||||
|
self.root
|
||||||
|
.set_on_event_inner(trigger, move |_, event| cb(event));
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the only global callback for the given event.
|
/// Sets the only global callback for the given event.
|
||||||
///
|
///
|
||||||
/// Any other callback for this event will be removed.
|
/// Any other callback for this event will be removed.
|
||||||
@ -728,6 +759,17 @@ impl Cursive {
|
|||||||
self.add_global_callback(event, cb);
|
self.add_global_callback(event, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches the type name of a view in the tree.
|
||||||
|
pub fn debug_name(&mut self, name: &str) -> Option<&'static str> {
|
||||||
|
let mut result = None;
|
||||||
|
|
||||||
|
self.root.call_on_any(
|
||||||
|
&view::Selector::Name(name),
|
||||||
|
&mut |v: &mut dyn crate::View| result = Some(v.type_name()),
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes any callback tied to the given event.
|
/// Removes any callback tied to the given event.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -26,10 +26,10 @@ use std::rc::Rc;
|
|||||||
pub struct Callback(Rc<Box<dyn Fn(&mut Cursive)>>);
|
pub struct Callback(Rc<Box<dyn Fn(&mut Cursive)>>);
|
||||||
// TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible
|
// TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible
|
||||||
|
|
||||||
/// A callback that can be run on `&mut Any`.
|
/// A callback that can be run on `&mut dyn View`.
|
||||||
///
|
///
|
||||||
/// It is meant to be used as parameter in `View::call_on_any`, and not much else.
|
/// It is meant to be used as parameter in `View::call_on_any`, and not much else.
|
||||||
pub type AnyCb<'a> = &'a mut dyn FnMut(&mut dyn Any);
|
pub type AnyCb<'a> = &'a mut dyn FnMut(&mut dyn crate::view::View);
|
||||||
|
|
||||||
/// A trigger that only selects some types of events.
|
/// A trigger that only selects some types of events.
|
||||||
///
|
///
|
||||||
|
@ -63,4 +63,9 @@ impl dyn AnyView {
|
|||||||
Err(self)
|
Err(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if this view is of type `T`.
|
||||||
|
pub fn is<T: Any>(&mut self) -> bool {
|
||||||
|
self.as_any().is::<T>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::view::{View, ViewPath, ViewWrapper};
|
use crate::view::{View, ViewPath, ViewWrapper};
|
||||||
use crate::views::{NamedView, ViewRef};
|
use crate::views::{NamedView, ViewRef};
|
||||||
use std::any::Any;
|
|
||||||
|
|
||||||
/// Provides `call_on<V: View>` to views.
|
/// Provides `call_on<V: View>` to views.
|
||||||
///
|
///
|
||||||
@ -20,13 +19,13 @@ pub trait Finder {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Option<R>
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R;
|
F: FnOnce(&mut V) -> R;
|
||||||
|
|
||||||
/// Convenient method to use `call_on` with a `view::Selector::Name`.
|
/// Convenient method to use `call_on` with a `view::Selector::Name`.
|
||||||
fn call_on_name<V, F, R>(&mut self, name: &str, callback: F) -> Option<R>
|
fn call_on_name<V, F, R>(&mut self, name: &str, callback: F) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
self.call_on(&Selector::Name(name), callback)
|
self.call_on(&Selector::Name(name), callback)
|
||||||
@ -36,7 +35,7 @@ pub trait Finder {
|
|||||||
#[deprecated(note = "`call_on_id` is being renamed to `call_on_name`")]
|
#[deprecated(note = "`call_on_id` is being renamed to `call_on_name`")]
|
||||||
fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
self.call_on_name(id, callback)
|
self.call_on_name(id, callback)
|
||||||
@ -45,7 +44,7 @@ pub trait Finder {
|
|||||||
/// Convenient method to find a view wrapped in an [`NamedView`].
|
/// Convenient method to find a view wrapped in an [`NamedView`].
|
||||||
fn find_name<V>(&mut self, name: &str) -> Option<ViewRef<V>>
|
fn find_name<V>(&mut self, name: &str) -> Option<ViewRef<V>>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
{
|
{
|
||||||
self.call_on_name(name, NamedView::<V>::get_mut)
|
self.call_on_name(name, NamedView::<V>::get_mut)
|
||||||
}
|
}
|
||||||
@ -54,7 +53,7 @@ pub trait Finder {
|
|||||||
#[deprecated(note = "`find_id` is being renamed to `find_name`")]
|
#[deprecated(note = "`find_id` is being renamed to `find_name`")]
|
||||||
fn find_id<V>(&mut self, id: &str) -> Option<ViewRef<V>>
|
fn find_id<V>(&mut self, id: &str) -> Option<ViewRef<V>>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
{
|
{
|
||||||
self.find_name(id)
|
self.find_name(id)
|
||||||
}
|
}
|
||||||
@ -67,7 +66,7 @@ impl<T: View> Finder for T {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Option<R>
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View,
|
||||||
F: FnOnce(&mut V) -> R,
|
F: FnOnce(&mut V) -> R,
|
||||||
{
|
{
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
@ -75,12 +74,13 @@ impl<T: View> Finder for T {
|
|||||||
let result_ref = &mut result;
|
let result_ref = &mut result;
|
||||||
|
|
||||||
let mut callback = Some(callback);
|
let mut callback = Some(callback);
|
||||||
let mut callback = |v: &mut dyn Any| {
|
let mut callback = |v: &mut dyn View| {
|
||||||
if let Some(callback) = callback.take() {
|
if let Some(callback) = callback.take() {
|
||||||
if v.is::<V>() {
|
if v.is::<V>() {
|
||||||
*result_ref =
|
*result_ref =
|
||||||
v.downcast_mut::<V>().map(|v| callback(v));
|
v.downcast_mut::<V>().map(|v| callback(v));
|
||||||
} else if v.is::<NamedView<V>>() {
|
} else if v.is::<NamedView<V>>() {
|
||||||
|
// Special case
|
||||||
*result_ref = v
|
*result_ref = v
|
||||||
.downcast_mut::<NamedView<V>>()
|
.downcast_mut::<NamedView<V>>()
|
||||||
.and_then(|v| v.with_view_mut(callback));
|
.and_then(|v| v.with_view_mut(callback));
|
||||||
|
@ -118,4 +118,39 @@ pub trait View: Any + AnyView {
|
|||||||
fn important_area(&self, view_size: Vec2) -> Rect {
|
fn important_area(&self, view_size: Vec2) -> Rect {
|
||||||
Rect::from_size((0, 0), view_size)
|
Rect::from_size((0, 0), view_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the type of this view.
|
||||||
|
///
|
||||||
|
/// Useful when you have a `&dyn View`.
|
||||||
|
fn type_name(&self) -> &'static str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn View {
|
||||||
|
/// Attempts to downcast `self` to a concrete type.
|
||||||
|
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.as_any().downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to downcast `self` to a concrete type.
|
||||||
|
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
self.as_any_mut().downcast_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to downcast `Box<Self>` to a concrete type.
|
||||||
|
pub fn downcast<T: Any>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
|
||||||
|
// Do the check here + unwrap, so the error
|
||||||
|
// value is `Self` and not `dyn Any`.
|
||||||
|
if self.as_any().is::<T>() {
|
||||||
|
Ok(self.as_boxed_any().downcast().unwrap())
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if this view is of type `T`.
|
||||||
|
pub fn is<T: Any>(&self) -> bool {
|
||||||
|
self.as_any().is::<T>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,6 @@ impl Dialog {
|
|||||||
/// let dialog = Dialog::around(TextView::new("Hello!"));
|
/// let dialog = Dialog::around(TextView::new("Hello!"));
|
||||||
/// let text_view: &TextView = dialog
|
/// let text_view: &TextView = dialog
|
||||||
/// .get_content()
|
/// .get_content()
|
||||||
/// .as_any()
|
|
||||||
/// .downcast_ref::<TextView>()
|
/// .downcast_ref::<TextView>()
|
||||||
/// .unwrap();
|
/// .unwrap();
|
||||||
/// assert_eq!(text_view.get_content().source(), "Hello!");
|
/// assert_eq!(text_view.get_content().source(), "Hello!");
|
||||||
|
@ -76,7 +76,6 @@ impl<T: View + 'static> ViewWrapper for NamedView<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some for<'b> weirdness here to please the borrow checker gods...
|
|
||||||
fn wrap_call_on_any<'a>(
|
fn wrap_call_on_any<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
selector: &Selector<'_>,
|
selector: &Selector<'_>,
|
||||||
|
@ -769,22 +769,18 @@ mod tests {
|
|||||||
assert!(stack
|
assert!(stack
|
||||||
.get(LayerPosition::FromFront(0))
|
.get(LayerPosition::FromFront(0))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_any()
|
|
||||||
.is::<TextView>());
|
.is::<TextView>());
|
||||||
assert!(stack
|
assert!(stack
|
||||||
.get(LayerPosition::FromBack(0))
|
.get(LayerPosition::FromBack(0))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_any()
|
|
||||||
.is::<TextView>());
|
.is::<TextView>());
|
||||||
assert!(stack
|
assert!(stack
|
||||||
.get_mut(LayerPosition::FromFront(0))
|
.get_mut(LayerPosition::FromFront(0))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_any_mut()
|
|
||||||
.is::<TextView>());
|
.is::<TextView>());
|
||||||
assert!(stack
|
assert!(stack
|
||||||
.get_mut(LayerPosition::FromBack(0))
|
.get_mut(LayerPosition::FromBack(0))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_any_mut()
|
|
||||||
.is::<TextView>());
|
.is::<TextView>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ impl TextView {
|
|||||||
Self::new_with_content(TextContent::new(content))
|
Self::new_with_content(TextContent::new(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new TextView using the given `Arc<Mutex<String>>`.
|
/// Creates a new TextView using the given `TextContent`.
|
||||||
///
|
///
|
||||||
/// If you kept a clone of the given content, you'll be able to update it
|
/// If you kept a clone of the given content, you'll be able to update it
|
||||||
/// remotely.
|
/// remotely.
|
||||||
|
Loading…
Reference in New Issue
Block a user