1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//! Gesture events and control, [`on_click`](fn@on_click), [`click_shortcut`](fn@click_shortcut) and more.
//!
//! These events aggregate multiple lower-level events to represent a user interaction.
//! Prefer using these events over the events directly tied to an input device.
use zng_app::shortcut::Shortcuts;
use zng_ext_input::gesture::{ShortcutClick, CLICK_EVENT, GESTURES};
use zng_view_api::access::AccessCmdName;
use zng_wgt::prelude::*;
pub use zng_ext_input::gesture::ClickArgs;
event_property! {
/// On widget click from any source and of any click count and the widget is enabled.
///
/// This is the most general click handler, it raises for all possible sources of the [`CLICK_EVENT`] and any number
/// of consecutive clicks. Use [`on_click`](fn@on_click) to handle only primary button clicks or [`on_any_single_click`](fn@on_any_single_click)
/// to not include double/triple clicks.
///
/// [`CLICK_EVENT`]: zng_ext_input::gesture::CLICK_EVENT
pub fn any_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_enabled(WIDGET.id()),
with: access_click,
}
/// On widget click from any source and of any click count and the widget is disabled.
pub fn disabled_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_disabled(WIDGET.id()),
with: access_click,
}
/// On widget click from any source but excluding double/triple clicks and the widget is enabled.
///
/// This raises for all possible sources of [`CLICK_EVENT`], but only when the click count is one. Use
/// [`on_single_click`](fn@on_single_click) to handle only primary button clicks.
///
/// [`CLICK_EVENT`]: zng_ext_input::gesture::CLICK_EVENT
pub fn any_single_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_single() && args.is_enabled(WIDGET.id()),
with: access_click,
}
/// On widget double click from any source and the widget is enabled.
///
/// This raises for all possible sources of [`CLICK_EVENT`], but only when the click count is two. Use
/// [`on_double_click`](fn@on_double_click) to handle only primary button clicks.
///
/// [`CLICK_EVENT`]: zng_ext_input::gesture::CLICK_EVENT
pub fn any_double_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_double() && args.is_enabled(WIDGET.id()),
}
/// On widget triple click from any source and the widget is enabled.
///
/// This raises for all possible sources of [`CLICK_EVENT`], but only when the click count is three. Use
/// [`on_triple_click`](fn@on_triple_click) to handle only primary button clicks.
///
/// [`CLICK_EVENT`]: zng_ext_input::gesture::CLICK_EVENT
pub fn any_triple_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_triple() && args.is_enabled(WIDGET.id()),
}
/// On widget click with the primary button and any click count and the widget is enabled.
///
/// This raises only if the click [is primary](ClickArgs::is_primary), but raises for any click count (double/triple clicks).
/// Use [`on_any_click`](fn@on_any_click) to handle clicks from any button or [`on_single_click`](fn@on_single_click) to not include
/// double/triple clicks.
pub fn click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_primary() && args.is_enabled(WIDGET.id()),
with: access_click,
}
/// On widget click with the primary button, excluding double/triple clicks and the widget is enabled.
///
/// This raises only if the click [is primary](ClickArgs::is_primary) and the click count is one. Use
/// [`on_any_single_click`](fn@on_any_single_click) to handle single clicks from any button.
pub fn single_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_primary() && args.is_single() && args.is_enabled(WIDGET.id()),
with: access_click,
}
/// On widget double click with the primary button and the widget is enabled.
///
/// This raises only if the click [is primary](ClickArgs::is_primary) and the click count is two. Use
/// [`on_any_double_click`](fn@on_any_double_click) to handle double clicks from any button.
pub fn double_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_primary() && args.is_double() && args.is_enabled(WIDGET.id()),
}
/// On widget triple click with the primary button and the widget is enabled.
///
/// This raises only if the click [is primary](ClickArgs::is_primary) and the click count is three. Use
/// [`on_any_double_click`](fn@on_any_double_click) to handle double clicks from any button.
pub fn triple_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_primary() && args.is_triple() && args.is_enabled(WIDGET.id()),
}
/// On widget click with the secondary/context button and the widget is enabled.
///
/// This raises only if the click [is context](ClickArgs::is_context).
pub fn context_click {
event: CLICK_EVENT,
args: ClickArgs,
filter: |args| args.is_context() && args.is_enabled(WIDGET.id()),
with: access_click,
}
}
/// Keyboard shortcuts that focus and clicks this widget.
///
/// When any of the `shortcuts` is pressed, focus and click this widget.
#[property(CONTEXT)]
pub fn click_shortcut(child: impl UiNode, shortcuts: impl IntoVar<Shortcuts>) -> impl UiNode {
click_shortcut_node(child, shortcuts, ShortcutClick::Primary)
}
/// Keyboard shortcuts that focus and [context clicks](fn@on_context_click) this widget.
///
/// When any of the `shortcuts` is pressed, focus and context clicks this widget.
#[property(CONTEXT)]
pub fn context_click_shortcut(child: impl UiNode, shortcuts: impl IntoVar<Shortcuts>) -> impl UiNode {
click_shortcut_node(child, shortcuts, ShortcutClick::Context)
}
fn click_shortcut_node(child: impl UiNode, shortcuts: impl IntoVar<Shortcuts>, kind: ShortcutClick) -> impl UiNode {
let shortcuts = shortcuts.into_var();
let mut _handle = None;
match_node(child, move |_, op| {
let new = match op {
UiNodeOp::Init => {
WIDGET.sub_var(&shortcuts);
Some(shortcuts.get())
}
UiNodeOp::Deinit => {
_handle = None;
None
}
UiNodeOp::Update { .. } => shortcuts.get_new(),
_ => None,
};
if let Some(s) = new {
_handle = Some(GESTURES.click_shortcut(s, kind, WIDGET.id()));
}
})
}
pub(crate) fn access_click(child: impl UiNode, _: bool) -> impl UiNode {
access_capable(child, AccessCmdName::Click)
}
fn access_capable(child: impl UiNode, cmd: AccessCmdName) -> impl UiNode {
match_node(child, move |_, op| {
if let UiNodeOp::Info { info } = op {
if let Some(mut access) = info.access() {
access.push_command(cmd)
}
}
})
}