Skip to main content

teksilo_core/
overscroll.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! [`OverscrollBehavior`] — boundary scroll-chaining policy.
5//!
6//! Shared by every scrollable surface (the `teksilo-widgets` scrollables —
7//! `ScrollArea` / `ListView` / `TreeView` / `TableView` — and the
8//! `teksilo-scene` `SceneView` pan handler). It lives in `teksilo-core` so
9//! both tiers can name it without `teksilo-scene` depending on
10//! `teksilo-widgets`. `teksilo-widgets` re-exports it as
11//! `teksilo_widgets::OverscrollBehavior` for backwards compatibility.
12
13/// Below this many logical pixels a scroll/pan axis is considered "did not
14/// move" (so a fully-clamped boundary event chains). Shared by the widget
15/// scrollables and the `teksilo-scene` pan handler so the boundary threshold
16/// is defined once. Tighter than a display pixel, looser than f32 clamp noise.
17pub const SCROLL_MOVE_EPSILON: f32 = 1e-3;
18
19/// Controls whether a scrollable surface chains scroll events to its ancestor
20/// when it reaches a boundary — the equivalent of CSS `overscroll-behavior`.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum OverscrollBehavior {
23    /// At a boundary, decline the event (`Ignored`) so it propagates to the
24    /// next ancestor scrollable. The default (`overscroll-behavior: auto`).
25    ///
26    /// Note: a scrollable whose content fits entirely (nothing to scroll on
27    /// either axis) is *always* at its boundary, so under `Chain` it lets the
28    /// wheel through to an ancestor rather than swallowing it. This matches
29    /// the web; set [`Contain`](Self::Contain) on a fit-to-content panel that
30    /// should absorb the wheel regardless.
31    #[default]
32    Chain,
33    /// Always absorb the event (`Handled`), even at the boundary — no
34    /// chaining. Equivalent to `overscroll-behavior: contain`.
35    Contain,
36}