ltk/input/pointer/mod.rs
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
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Pointer → ltk dispatch.
//!
//! Each [`PointerInput`] (motion / press / release / axis) translates
//! into a call on the surface's [`GestureState`](super::gesture::GestureState)
//! plus the follow-up side-effects that can only live at the
//! [`AppData`] level (pending-message push, surface redraw, dirty-cache
//! invalidation, window move). The pointer handler adds three things
//! touch does not have:
//!
//! * **Hover tracking** — motion updates `SurfaceState::hovered_idx`
//! before delegating the motion to the gesture machine, since the
//! hovered widget drives visual state independent of whether a press
//! is active.
//! * **Title-bar interaction** — a press inside the client-side title
//! bar either closes the window (close button hit) or initiates a
//! compositor-driven window move. Neither path goes through the
//! gesture machine.
//! * **Wheel / axis scroll** — routed directly into the per-viewport
//! `scroll_offsets` map; axis events do not have a press/release
//! lifecycle so they bypass the state machine entirely.
use crate::app::App;
use crate::event_loop::AppData;
use crate::platform::Platform;
use super::event::{ PointerButton, PointerInput, PointerKind };
pub( crate ) mod enter;
pub( crate ) mod motion;
pub( crate ) mod press;
pub( crate ) mod release;
pub( crate ) mod scroll;
pub( crate ) mod helpers;
impl<A: App, P: Platform> AppData<A, P>
{
/// The entry point for a mouse or a touchpad. See [`super::event`].
pub( crate ) fn pointer_input( &mut self, input: &PointerInput )
{
self.pointer_focus = input.focus;
self.report_mouse_button( input );
match input.kind
{
PointerKind::Enter => self.on_pointer_enter( input.focus ),
PointerKind::Leave => self.app.on_pointer_hover( input.focus.target(), None ),
PointerKind::Motion => self.on_pointer_motion( input ),
PointerKind::Press( PointerButton::Left ) => self.on_pointer_left_press( input ),
PointerKind::Press( PointerButton::Right ) => self.on_pointer_right_click( input ),
PointerKind::Press( PointerButton::Middle ) => self.on_pointer_middle_press( input ),
PointerKind::Press( PointerButton::Back ) => self.handle_back( input.focus ),
PointerKind::Release( PointerButton::Left ) => self.on_pointer_release( input ),
PointerKind::Axis { horizontal, vertical, source } => self.on_pointer_axis( input, horizontal, vertical, source ),
_ => {}
}
}
/// Hand a press or release of the left, middle or right button to [`App::on_mouse_button`].
fn report_mouse_button( &mut self, input: &PointerInput )
{
let ( button, pressed ) = match input.kind
{
PointerKind::Press( button ) => ( button, true ),
PointerKind::Release( button ) => ( button, false ),
_ => return,
};
let Some( button ) = button.mouse_button() else { return };
let pos = self.surface( input.focus ).to_physical( input.position.0, input.position.1 );
self.app.on_mouse_button( &crate::app::MouseButtonEvent
{
button,
x: pos.x,
y: pos.y,
pressed,
ctrl: self.ctrl_pressed,
shift: self.shift_pressed,
alt: self.alt_pressed,
} );
}
}