Continued implementing command (init_name and init_info) and started adding some commands.

Fixed visibility/privacy errors when using command! from another file.
This commit is contained in:
Well 2021-06-22 01:24:09 -03:00
parent 992dc6d182
commit 2090aae21c
5 changed files with 115 additions and 17 deletions

View File

@ -33,12 +33,17 @@ mod declare_stuff{
command! { command! {
/// Command docs. /// Command docs.
pub CopyCommand; pub CopyCommand
.init_name("Copy")
.init_gesture(shortcuts![CTRL+C]);
/// Other command docs. /// Other command docs.
pub PasteCommand; pub PasteCommand;
} }
fn app_run(ctx: _) {
CopyCommand.name().set(ctx, "Copiar")
}
} }
// //
@ -145,7 +150,11 @@ button!{
content = text(CopyCommand::label()); content = text(CopyCommand::label());
enabled = CopyCommand::enabled(); enabled = CopyCommand::enabled();
visible = CopyCommand::has_handlers(); visible = CopyCommand::has_handlers();
//this
command = CopyCommand; command = CopyCommand;
//or this
on_click = hn!(|_, _| CopyCommand.notify(None));
} }
command_button!{ command_button!{

View File

@ -23,15 +23,23 @@ use crate::{
macro_rules! command { macro_rules! command {
($( ($(
$(#[$outer:meta])* $(#[$outer:meta])*
$vis:vis $Command:ident $(: $Args:path)? $vis:vis $Command:ident $(
);+$(;)?) => {$( .$init:ident( $($args:tt)* )
)*;
)+) => {$(
$(#[$outer])* $(#[$outer])*
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
$vis struct $Command; $vis struct $Command;
impl $Command { impl $Command {
std::thread_local! { std::thread_local! {
static COMMAND: $crate::command::CommandValue = $crate::command::CommandValue::init::<$Command>(); static COMMAND: $crate::command::CommandValue = $crate::command::CommandValue::init::<$Command, _>(||{
#[allow(path_statements)] {
$Command $(
.$init( $($args)* )
)*;
}
});
} }
/// Gets the event arguments if the update is for this event. /// Gets the event arguments if the update is for this event.
@ -42,10 +50,11 @@ macro_rules! command {
} }
/// Schedule an event update if the command is enabled. /// Schedule an event update if the command is enabled.
/// `parameter` is an optional value for the command handler.
#[inline] #[inline]
#[allow(unused)] #[allow(unused)]
pub fn notify(self, events: &mut $crate::event::Events, args: $crate::command::CommandArgs) { pub fn notify(self, events: &mut $crate::event::Events, parameter: Option<std::rc::Rc<dyn std::any::Any>>) {
<Self as $crate::event::Event>::notify(self, events, args); <Self as $crate::event::Event>::notify(self, events, $crate::command::CommandArgs::now(parameter));
} }
} }
impl $crate::event::Event for $Command { impl $crate::event::Event for $Command {
@ -53,7 +62,7 @@ macro_rules! command {
#[inline(always)] #[inline(always)]
fn notify<Evs: $crate::event::WithEvents>(self, events: &mut Evs, args: Self::Args) { fn notify<Evs: $crate::event::WithEvents>(self, events: &mut Evs, args: Self::Args) {
if Self::COMMAND.with(|c| c.handle.enabled.get() > 0) { if Self::COMMAND.with(|c| c.enabled_value()) {
events.with_events(|evs| evs.notify::<Self>(args)); events.with_events(|evs| evs.notify::<Self>(args));
} }
} }
@ -72,11 +81,21 @@ macro_rules! command {
Self::COMMAND.with(|c| c.enabled()) Self::COMMAND.with(|c| c.enabled())
} }
#[inline]
fn enabled_value(self) -> bool {
Self::COMMAND.with(|c| c.enabled_value())
}
#[inline] #[inline]
fn has_handlers(self) -> $crate::var::ReadOnlyVar<bool, $crate::var::RcVar<bool>> { fn has_handlers(self) -> $crate::var::ReadOnlyVar<bool, $crate::var::RcVar<bool>> {
Self::COMMAND.with(|c| c.has_handlers()) Self::COMMAND.with(|c| c.has_handlers())
} }
#[inline]
fn has_handlers_value(self) -> bool {
Self::COMMAND.with(|c| c.has_handlers_value())
}
#[inline] #[inline]
fn new_handle(self, events: &mut $crate::event::Events) -> $crate::command::CommandHandle { fn new_handle(self, events: &mut $crate::event::Events) -> $crate::command::CommandHandle {
Self::COMMAND.with(|c| c.new_handle(events, &Self::COMMAND)) Self::COMMAND.with(|c| c.new_handle(events, &Self::COMMAND))
@ -108,12 +127,18 @@ pub trait Command: Event<Args = CommandArgs> {
/// visible but disabled. /// visible but disabled.
fn enabled(self) -> ReadOnlyVar<bool, RcVar<bool>>; fn enabled(self) -> ReadOnlyVar<bool, RcVar<bool>>;
/// Gets if the command has at least one enabled handler.
fn enabled_value(self) -> bool;
/// Gets a read-only variable that indicates if the command has at least one handler. /// Gets a read-only variable that indicates if the command has at least one handler.
/// ///
/// When this is `false` the command can be considered *not relevant* in the current app state /// When this is `false` the command can be considered *not relevant* in the current app state
/// and associated command trigger widgets can be hidden. /// and associated command trigger widgets can be hidden.
fn has_handlers(self) -> ReadOnlyVar<bool, RcVar<bool>>; fn has_handlers(self) -> ReadOnlyVar<bool, RcVar<bool>>;
/// Gets if the command has at least one handler.
fn has_handlers_value(self) -> bool;
/// Create a new handle to this command. /// Create a new handle to this command.
/// ///
/// A handle indicates that there is an active *handler* for the event, the handle can also /// A handle indicates that there is an active *handler* for the event, the handle can also
@ -171,7 +196,11 @@ impl Event for AnyCommand {
type Args = CommandArgs; type Args = CommandArgs;
fn notify<Evs: WithEvents>(self, events: &mut Evs, args: Self::Args) { fn notify<Evs: WithEvents>(self, events: &mut Evs, args: Self::Args) {
events.with_events(|events| self.0.with(move |c| (c.notify)(events, args))); self.0.with(|c| {
if c.enabled_value() {
events.with_events(|e| (c.notify)(e, args))
}
});
} }
fn update<U: crate::event::EventUpdateArgs>(self, _: &U) -> Option<&crate::event::EventUpdate<Self>> { fn update<U: crate::event::EventUpdateArgs>(self, _: &U) -> Option<&crate::event::EventUpdate<Self>> {
panic!("`AnyCommand` does not support `Event::update`"); panic!("`AnyCommand` does not support `Event::update`");
@ -190,10 +219,18 @@ impl Command for AnyCommand {
self.0.with(|c| c.enabled()) self.0.with(|c| c.enabled())
} }
fn enabled_value(self) -> bool {
self.0.with(|c| c.enabled_value())
}
fn has_handlers(self) -> ReadOnlyVar<bool, RcVar<bool>> { fn has_handlers(self) -> ReadOnlyVar<bool, RcVar<bool>> {
self.0.with(|c| c.has_handlers()) self.0.with(|c| c.has_handlers())
} }
fn has_handlers_value(self) -> bool {
self.0.with(|c| c.has_handlers_value())
}
fn new_handle(self, events: &mut Events) -> CommandHandle { fn new_handle(self, events: &mut Events) -> CommandHandle {
self.0.with(|c| c.new_handle(events, self.0)) self.0.with(|c| c.new_handle(events, self.0))
} }
@ -207,6 +244,9 @@ impl Command for AnyCommand {
pub trait CommandNameExt: Command { pub trait CommandNameExt: Command {
/// Gets a read-write variable that is the display name for the command. /// Gets a read-write variable that is the display name for the command.
fn name(self) -> RcVar<Text>; fn name(self) -> RcVar<Text>;
/// Sets the initial name if it is not set.
fn init_name(self, name: impl Into<Text>) -> Self;
} }
state_key! { state_key! {
struct CommandNameKey: RcVar<Text>; struct CommandNameKey: RcVar<Text>;
@ -219,12 +259,23 @@ impl<C: Command> CommandNameExt for C {
var.clone() var.clone()
}) })
} }
fn init_name(self, name: impl Into<Text>) -> Self {
self.with_meta(|m| {
let entry = m.entry::<CommandNameKey>();
entry.or_insert_with(|| var(name.into()));
});
self
}
} }
/// Adds the [`info`](CommandInfoExt) metadata. /// Adds the [`info`](CommandInfoExt) metadata.
pub trait CommandInfoExt: Command { pub trait CommandInfoExt: Command {
/// Gets a read-write variable that is a short informational string about the command. /// Gets a read-write variable that is a short informational string about the command.
fn info(self) -> RcVar<Text>; fn info(self) -> RcVar<Text>;
/// Sets the initial info if it is not set.
fn init_info(self, info: impl Into<Text>) -> Self;
} }
state_key! { state_key! {
struct CommandInfoKey: RcVar<Text>; struct CommandInfoKey: RcVar<Text>;
@ -237,6 +288,14 @@ impl<C: Command> CommandInfoExt for C {
var.clone() var.clone()
}) })
} }
fn init_info(self, info: impl Into<Text>) -> Self {
self.with_meta(|m| {
let entry = m.entry::<CommandInfoKey>();
entry.or_insert_with(|| var(info.into()));
});
self
}
} }
/// A handle to a [`Command`]. /// A handle to a [`Command`].
@ -282,12 +341,13 @@ pub struct CommandValue {
enabled: RcVar<bool>, enabled: RcVar<bool>,
has_handlers: RcVar<bool>, has_handlers: RcVar<bool>,
meta: RefCell<OwnedStateMap>, meta: RefCell<OwnedStateMap>,
meta_init: Cell<Option<Box<dyn FnOnce()>>>,
registered: Cell<bool>, registered: Cell<bool>,
notify: Box<dyn Fn(&mut Events, CommandArgs)>, notify: Box<dyn Fn(&mut Events, CommandArgs)>,
} }
#[allow(missing_docs)] // this is all hidden #[allow(missing_docs)] // this is all hidden
impl CommandValue { impl CommandValue {
pub fn init<C: Command>() -> Self { pub fn init<C: Command, I: FnOnce() + 'static>(meta_init: I) -> Self {
CommandValue { CommandValue {
command_type_id: TypeId::of::<C>(), command_type_id: TypeId::of::<C>(),
command_type_name: type_name::<C>(), command_type_name: type_name::<C>(),
@ -295,17 +355,15 @@ impl CommandValue {
enabled: var(false), enabled: var(false),
has_handlers: var(false), has_handlers: var(false),
meta: RefCell::default(), meta: RefCell::default(),
meta_init: Cell::new(Some(Box::new(meta_init))),
registered: Cell::new(false), registered: Cell::new(false),
notify: Box::new(|events, args| events.notify::<C>(args)), notify: Box::new(|events, args| events.notify::<C>(args)),
} }
} }
fn update_state(&self, vars: &Vars) { fn update_state(&self, vars: &Vars) {
let has_handlers = Rc::strong_count(&self.handle) > 1; self.has_handlers.set_ne(vars, self.has_handlers_value());
let enabled = self.handle.enabled.get() > 0; self.enabled.set_ne(vars, self.enabled_value());
self.has_handlers.set_ne(vars, has_handlers);
self.enabled.set_ne(vars, enabled);
} }
pub fn new_handle(&self, events: &mut Events, key: &'static LocalKey<CommandValue>) -> CommandHandle { pub fn new_handle(&self, events: &mut Events, key: &'static LocalKey<CommandValue>) -> CommandHandle {
@ -323,14 +381,25 @@ impl CommandValue {
ReadOnlyVar::new(self.enabled.clone()) ReadOnlyVar::new(self.enabled.clone())
} }
pub fn enabled_value(&self) -> bool {
self.handle.enabled.get() > 0
}
pub fn has_handlers(&self) -> ReadOnlyVar<bool, RcVar<bool>> { pub fn has_handlers(&self) -> ReadOnlyVar<bool, RcVar<bool>> {
ReadOnlyVar::new(self.has_handlers.clone()) ReadOnlyVar::new(self.has_handlers.clone())
} }
pub fn has_handlers_value(&self) -> bool {
Rc::strong_count(&self.handle) > 1
}
pub fn with_meta<F, R>(&self, f: F) -> R pub fn with_meta<F, R>(&self, f: F) -> R
where where
F: FnOnce(&mut StateMap) -> R, F: FnOnce(&mut StateMap) -> R,
{ {
if let Some(init) = self.meta_init.take() {
init()
}
f(&mut self.meta.borrow_mut().0) f(&mut self.meta.borrow_mut().0)
} }
} }
@ -362,7 +431,7 @@ mod tests {
command! { command! {
FooCommand; FooCommand;
BarCommand: crate::command::CommandArgs; BarCommand;
} }
#[test] #[test]

View File

@ -61,7 +61,6 @@ pub trait Event: Debug + Clone + Copy + 'static {
type Args: EventArgs; type Args: EventArgs;
/// Schedule an event update. /// Schedule an event update.
#[doc(hidden)]
#[inline(always)] #[inline(always)]
fn notify<Evs: WithEvents>(self, events: &mut Evs, args: Self::Args) { fn notify<Evs: WithEvents>(self, events: &mut Evs, args: Self::Args) {
events.with_events(|events| events.notify::<Self>(args)); events.with_events(|events| events.notify::<Self>(args));
@ -672,7 +671,8 @@ impl Events {
} }
} }
pub(crate) fn notify<E: Event>(&mut self, args: E::Args) { /// Called by [`Event::notify`] to schedule a notification.
pub fn notify<E: Event>(&mut self, args: E::Args) {
let update = EventUpdate::<E>(args); let update = EventUpdate::<E>(args);
self.updates.push(update.boxed()); self.updates.push(update.boxed());
} }

View File

@ -13,6 +13,7 @@ mod border_;
pub use border_::*; pub use border_::*;
mod capture_mouse_; mod capture_mouse_;
pub mod commands;
mod cursor_; mod cursor_;
pub mod drag_move; pub mod drag_move;
pub mod events; pub mod events;

View File

@ -0,0 +1,19 @@
//! Common commands
use crate::core::command::*;
command! {
/// Represents the clipboard **cut** action.
pub CutCommand
.init_name("Cut")
.init_info("Remove the selection and place it in the clipboard.");
/// Represents the clipboard **copy** action.
pub CopyCommand
.init_name("Copy")
.init_info("Place a copy of the selection in the clipboard.");
/// Represents the clipboard **paste** action.
pub PasteCommand
.init_name("Paste")
.init_info("Insert content from the clipboard.");
}