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,
|
||||
) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
self.root.call_on(sel, callback)
|
||||
@ -577,7 +577,7 @@ impl Cursive {
|
||||
callback: F,
|
||||
) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
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`")]
|
||||
pub fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
self.call_on_name(id, callback)
|
||||
@ -640,7 +640,7 @@ impl Cursive {
|
||||
/// [`ViewRef`]: views::ViewRef
|
||||
pub fn find_name<V>(&mut self, id: &str) -> Option<views::ViewRef<V>>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
{
|
||||
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`")]
|
||||
pub fn find_id<V>(&mut self, id: &str) -> Option<views::ViewRef<V>>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
{
|
||||
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
|
||||
/// 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)
|
||||
where
|
||||
F: FnMut(&mut Cursive) + 'static,
|
||||
@ -714,6 +717,34 @@ impl Cursive {
|
||||
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.
|
||||
///
|
||||
/// Any other callback for this event will be removed.
|
||||
@ -728,6 +759,17 @@ impl Cursive {
|
||||
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.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -26,10 +26,10 @@ use std::rc::Rc;
|
||||
pub struct Callback(Rc<Box<dyn Fn(&mut Cursive)>>);
|
||||
// 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.
|
||||
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.
|
||||
///
|
||||
|
@ -63,4 +63,9 @@ impl dyn AnyView {
|
||||
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::views::{NamedView, ViewRef};
|
||||
use std::any::Any;
|
||||
|
||||
/// Provides `call_on<V: View>` to views.
|
||||
///
|
||||
@ -20,13 +19,13 @@ pub trait Finder {
|
||||
callback: F,
|
||||
) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R;
|
||||
|
||||
/// 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>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
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`")]
|
||||
fn call_on_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
self.call_on_name(id, callback)
|
||||
@ -45,7 +44,7 @@ pub trait Finder {
|
||||
/// Convenient method to find a view wrapped in an [`NamedView`].
|
||||
fn find_name<V>(&mut self, name: &str) -> Option<ViewRef<V>>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
{
|
||||
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`")]
|
||||
fn find_id<V>(&mut self, id: &str) -> Option<ViewRef<V>>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
{
|
||||
self.find_name(id)
|
||||
}
|
||||
@ -67,7 +66,7 @@ impl<T: View> Finder for T {
|
||||
callback: F,
|
||||
) -> Option<R>
|
||||
where
|
||||
V: View + Any,
|
||||
V: View,
|
||||
F: FnOnce(&mut V) -> R,
|
||||
{
|
||||
let mut result = None;
|
||||
@ -75,12 +74,13 @@ impl<T: View> Finder for T {
|
||||
let result_ref = &mut result;
|
||||
|
||||
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 v.is::<V>() {
|
||||
*result_ref =
|
||||
v.downcast_mut::<V>().map(|v| callback(v));
|
||||
} else if v.is::<NamedView<V>>() {
|
||||
// Special case
|
||||
*result_ref = v
|
||||
.downcast_mut::<NamedView<V>>()
|
||||
.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 {
|
||||
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 text_view: &TextView = dialog
|
||||
/// .get_content()
|
||||
/// .as_any()
|
||||
/// .downcast_ref::<TextView>()
|
||||
/// .unwrap();
|
||||
/// 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>(
|
||||
&mut self,
|
||||
selector: &Selector<'_>,
|
||||
|
@ -769,22 +769,18 @@ mod tests {
|
||||
assert!(stack
|
||||
.get(LayerPosition::FromFront(0))
|
||||
.unwrap()
|
||||
.as_any()
|
||||
.is::<TextView>());
|
||||
assert!(stack
|
||||
.get(LayerPosition::FromBack(0))
|
||||
.unwrap()
|
||||
.as_any()
|
||||
.is::<TextView>());
|
||||
assert!(stack
|
||||
.get_mut(LayerPosition::FromFront(0))
|
||||
.unwrap()
|
||||
.as_any_mut()
|
||||
.is::<TextView>());
|
||||
assert!(stack
|
||||
.get_mut(LayerPosition::FromBack(0))
|
||||
.unwrap()
|
||||
.as_any_mut()
|
||||
.is::<TextView>());
|
||||
}
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ impl TextView {
|
||||
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
|
||||
/// remotely.
|
||||
|
Loading…
Reference in New Issue
Block a user