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
//! Mouse and touch capture properties.
use zng_ext_input::{
mouse::MOUSE_INPUT_EVENT,
pointer_capture::{PointerCaptureArgs, POINTER_CAPTURE, POINTER_CAPTURE_EVENT},
touch::TOUCH_INPUT_EVENT,
};
use zng_wgt::prelude::*;
pub use zng_ext_input::pointer_capture::CaptureMode;
event_property! {
/// Widget acquired mouse and touch capture.
pub fn got_pointer_capture {
event: POINTER_CAPTURE_EVENT,
args: PointerCaptureArgs,
filter: |args| args.is_got(WIDGET.id()),
}
/// Widget lost mouse and touch capture.
pub fn lost_pointer_capture {
event: POINTER_CAPTURE_EVENT,
args: PointerCaptureArgs,
filter: |args| args.is_lost(WIDGET.id()),
}
/// Widget acquired or lost mouse and touch capture.
pub fn pointer_capture_changed {
event: POINTER_CAPTURE_EVENT,
args: PointerCaptureArgs,
}
}
/// Capture mouse and touch for the widget on press.
///
/// The capture happens only if any mouse button or touch is pressed on the window and the `mode` is [`Widget`] or [`Subtree`].
///
/// Captures are released when all mouse buttons and touch contacts stop being pressed on the window.
/// The capture is also released back to window if the `mode` changes to [`Window`].
///
/// [`Widget`]: CaptureMode::Widget
/// [`Subtree`]: CaptureMode::Subtree
/// [`Window`]: CaptureMode::Window
#[property(CONTEXT, default(false))]
pub fn capture_pointer(child: impl UiNode, mode: impl IntoVar<CaptureMode>) -> impl UiNode {
let mode = mode.into_var();
match_node(child, move |_, op| match op {
UiNodeOp::Init => {
WIDGET.sub_event(&MOUSE_INPUT_EVENT).sub_event(&TOUCH_INPUT_EVENT).sub_var(&mode);
}
UiNodeOp::Event { update } => {
let mut capture = false;
if let Some(args) = MOUSE_INPUT_EVENT.on(update) {
capture = args.is_mouse_down();
} else if let Some(args) = TOUCH_INPUT_EVENT.on(update) {
capture = args.is_touch_start();
}
if capture {
let widget_id = WIDGET.id();
match mode.get() {
CaptureMode::Widget => {
POINTER_CAPTURE.capture_widget(widget_id);
}
CaptureMode::Subtree => {
POINTER_CAPTURE.capture_subtree(widget_id);
}
CaptureMode::Window => (),
}
}
}
UiNodeOp::Update { .. } => {
if let Some(new_mode) = mode.get_new() {
let tree = WINDOW.info();
let widget_id = WIDGET.id();
if tree.get(widget_id).map(|w| w.interactivity().is_enabled()).unwrap_or(false) {
if let Some(current) = POINTER_CAPTURE.current_capture().get() {
if current.target.widget_id() == widget_id {
// If mode updated and we are capturing the mouse:
match new_mode {
CaptureMode::Widget => POINTER_CAPTURE.capture_widget(widget_id),
CaptureMode::Subtree => POINTER_CAPTURE.capture_subtree(widget_id),
CaptureMode::Window => POINTER_CAPTURE.release_capture(),
}
}
}
}
}
}
_ => {}
})
}
/// Capture mouse and touch for the widget on init.
///
/// The capture happens only if any mouse button or touch is pressed on the window and the `mode` is [`Widget`] or [`Subtree`].
///
/// Pointer captures are released when all mouse buttons stop being pressed on the window.
/// The capture is also released back to window if the `mode` changes to [`Window`] when the mouse is captured for the widget.
///
/// [`Widget`]: CaptureMode::Widget
/// [`Subtree`]: CaptureMode::Subtree
/// [`Window`]: CaptureMode::Window
#[property(CONTEXT, default(false))]
pub fn capture_pointer_on_init(child: impl UiNode, mode: impl IntoVar<CaptureMode>) -> impl UiNode {
let mode = mode.into_var();
let mut capture = true;
match_node(child, move |_, op| match op {
UiNodeOp::Init => {
WIDGET.sub_var(&mode);
capture = true; // wait for info
}
UiNodeOp::Info { .. } => {
if std::mem::take(&mut capture) {
let widget_id = WIDGET.id();
match mode.get() {
CaptureMode::Widget => {
POINTER_CAPTURE.capture_widget(widget_id);
}
CaptureMode::Subtree => {
POINTER_CAPTURE.capture_subtree(widget_id);
}
CaptureMode::Window => (),
}
}
}
UiNodeOp::Update { .. } => {
if let Some(new_mode) = mode.get_new() {
let tree = WINDOW.info();
let widget_id = WIDGET.id();
if tree.get(widget_id).map(|w| w.interactivity().is_enabled()).unwrap_or(false) {
if let Some(current) = POINTER_CAPTURE.current_capture().get() {
if current.target.widget_id() == widget_id {
// If mode updated and we are capturing the mouse:
match new_mode {
CaptureMode::Widget => POINTER_CAPTURE.capture_widget(widget_id),
CaptureMode::Subtree => POINTER_CAPTURE.capture_subtree(widget_id),
CaptureMode::Window => POINTER_CAPTURE.release_capture(),
}
}
}
}
}
}
_ => {}
})
}