ltk: subsurface slides over overlays, axis-locked swipes, physical-space layout, touch reset on resume
Subsurfaces can now be parented to an overlay surface, not just the main surface. `SubsurfaceSpec` gains `parent: SubsurfaceParent { Main, Overlay(id) }` so a sliding panel can ride above app windows the way an overlay panel does, and an optional `gpu: bool` so content that uses the `surface-panel` backdrop-filter glass (a GLES-only pass) keeps it while sliding instead of dropping to the software rasteriser. `reconcile_subsurfaces` resolves each spec's parent independently — skipping an `Overlay` parent that is absent, unconfigured, or zero-sized — tracks the rastered size on the slot, and commits each touched parent once per frame. The ~14 GLES shader programs are compiled once into a shared `AppData::subsurface_gles_canvas` reused across every subsurface, so a lazily re-created sliding panel never recompiles them (hundreds of ms on a mobile GPU).
Vertical and horizontal swipes are now mutually exclusive: a gesture locks onto its dominant axis within the first 8 px of travel (new `SwipeAxis`) and ignores the perpendicular axis for the rest of the gesture, so a vertical swipe that drifts sideways no longer also drives the pager (and vice-versa). The upward swipe progress is no longer clamped at 1.0 — follow-the-finger panels can keep tracking the finger past the commit threshold — and a release below threshold delivers a final `progress = 0.0` cancellation pulse. A vertical swipe also no longer re-rasters the full-screen main surface on every motion event: only the overlays it drives are refreshed, while the horizontal pager (which does move the main surface) still redraws it. Re-rastering the main on every frame of a vertical drag was wasted work that stalled the loop and made the gesture feel laggy to start on a slow GPU.
Layout-affecting `Length` values (widths, paddings, gaps, widget sizes, including `Vw` / `Vh`) now resolve against the physical viewport via the new `Canvas::viewport_layout()` — the space the layout tree is actually computed in — so a `Vw(100)` fills the surface on a HiDPI (scale 2) output instead of covering half of it. Font sizes are unchanged: they still resolve against the logical viewport and are scaled at raster time. Switched column, row, spacer, wrap_grid, container, image, and vslider over to it; `img_widget` and `vslider` now document `Length::vw` / `vh` sizing and the showcase example demonstrates a viewport-relative image.
Touch gesture state is reset when the touch capability is added or removed — suspend / resume on devices that power the touchscreen down. A yanked capability never delivers the pending `up` / `cancel`, so the shared `reset_touch_state()` (also used by the `wl_touch.cancel` handler) drops the stranded `primary_touch_id` / slot state across the main surface and every overlay, keeping the first post-resume gesture clean. Also drops an accidental duplicate `on_scale_changed` call from the scale-change handler.
This commit is contained in:
40
src/app.rs
40
src/app.rs
@@ -124,6 +124,18 @@ pub struct OverlayId( pub u32 );
|
||||
#[derive( Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord )]
|
||||
pub struct SubsurfaceId( pub u32 );
|
||||
|
||||
/// Which surface a [`SubsurfaceSpec`] is composited as a child of. `Main`
|
||||
/// (the default position) parents to the app's main surface; `Overlay(id)`
|
||||
/// parents to one of the [`App::overlays`] surfaces, so a slide can ride
|
||||
/// above app windows the way an overlay panel does. An `Overlay` parent that
|
||||
/// is absent or not yet configured is skipped for that frame.
|
||||
#[derive( Debug, Clone, Copy, PartialEq, Eq )]
|
||||
pub enum SubsurfaceParent
|
||||
{
|
||||
Main,
|
||||
Overlay( OverlayId ),
|
||||
}
|
||||
|
||||
/// One of the surfaces an [`App`] can target with an invalidation. Used inside
|
||||
/// [`InvalidationScope::Only`] to name the affected surfaces.
|
||||
#[derive( Debug, Clone, Copy, PartialEq, Eq, Hash )]
|
||||
@@ -279,6 +291,10 @@ pub struct SubsurfaceSpec<Message: Clone>
|
||||
/// Stable identifier, used to diff subsurfaces between frames.
|
||||
pub id: SubsurfaceId,
|
||||
|
||||
/// Surface this subsurface is composited as a child of. Sized to that
|
||||
/// parent; [`x`](Self::x) / [`y`](Self::y) are relative to its top-left.
|
||||
pub parent: SubsurfaceParent,
|
||||
|
||||
/// Widget tree for this subsurface. Should paint its own opaque
|
||||
/// background if it must cover the main surface beneath it.
|
||||
pub view: Element<Message>,
|
||||
@@ -295,6 +311,13 @@ pub struct SubsurfaceSpec<Message: Clone>
|
||||
/// differently; leave it unchanged for position-only updates so the
|
||||
/// runtime skips the re-raster and only repositions.
|
||||
pub content_version: u64,
|
||||
|
||||
/// Render through GLES (so `backdrop-filter` glass works) rather than the
|
||||
/// software rasteriser. GLES is only worth it for content that actually
|
||||
/// uses the blur: it pays a per-surface EGL-surface creation (and a
|
||||
/// one-time shader compile) the cheap software path avoids, so a panel
|
||||
/// without glass should leave this `false`.
|
||||
pub gpu: bool,
|
||||
}
|
||||
|
||||
/// Trait that application types must implement to integrate with ltk.
|
||||
@@ -381,11 +404,18 @@ pub trait App: 'static
|
||||
/// `swipe_threshold()` × screen height and then releases.
|
||||
fn on_swipe_up( &mut self ) -> Option<Self::Message> { None }
|
||||
|
||||
/// Called during an upward swipe gesture with progress 0.0..=1.0.
|
||||
/// Called during an upward swipe gesture with progress ≥ 0.0.
|
||||
///
|
||||
/// Use this to create follow-the-finger animations. `progress` starts at 0.0
|
||||
/// when the drag begins and increases as the finger moves upward, reaching 1.0
|
||||
/// when the drag distance equals `swipe_threshold()` × screen height.
|
||||
/// when the drag distance equals `swipe_threshold()` × screen height. It is
|
||||
/// **not** clamped at 1.0 — the value keeps growing if the finger drags further
|
||||
/// so that follow-the-finger panels can continue tracking the finger all the way
|
||||
/// up the screen. Clamp inside the handler if you need a bounded `[0, 1]` range
|
||||
/// for a visual indicator.
|
||||
///
|
||||
/// When the user releases without completing the gesture, this method is called
|
||||
/// once more with `progress = 0.0` to signal cancellation.
|
||||
fn on_swipe_progress( &mut self, _progress: f32 ) {}
|
||||
|
||||
/// Called when a sufficient downward swipe gesture is detected.
|
||||
@@ -595,8 +625,10 @@ pub trait App: 'static
|
||||
fn on_resize( &mut self, _width: u32, _height: u32 ) {}
|
||||
|
||||
/// Called when the compositor reports a new integer buffer scale for the
|
||||
/// main surface. The default is inert so apps that only care about physical
|
||||
/// pixels can keep using [`on_resize`](Self::on_resize).
|
||||
/// main surface. `scale` is the integer buffer scale (1 = standard DPI,
|
||||
/// 2 = HiDPI ×2); physical pixels equal logical pixels × scale. The default
|
||||
/// is inert so apps that only care about physical pixels can keep using
|
||||
/// [`on_resize`](Self::on_resize).
|
||||
fn on_scale_changed( &mut self, _scale: u32 ) {}
|
||||
|
||||
/// Called once at startup with a channel sender that can be used from any
|
||||
|
||||
Reference in New Issue
Block a user