fix(input): cursors follow the pointer while dragging and snap on drop
This commit is contained in:
1 parent
ea70cf4fca
commit
d2ba67921e
7 files changed
+292
-27
No files matched your search
@@ -89,7 +89,10 @@ using plot::RegionGrab;
|
||||
/// grabbed cursor's orientation owns -- `set_cursor_x()` for a marker,
|
||||
/// `set_cursor_y()` for a ruler -- and a dragged ruler is clamped to its own y
|
||||
/// axis' range, because a pointer past the top or bottom of `axes` has no data
|
||||
/// under it to follow (see `move_cursor()`).
|
||||
/// under it to follow (see `move_cursor()`). The writes are *free*, so the marker
|
||||
/// tracks the pointer for the whole gesture rather than hopping between the samples
|
||||
/// it would otherwise snap to; the cursor's own snap rule is applied once, on
|
||||
/// release (`Plot::snap_cursor()`), exactly as a region's is.
|
||||
/// 2. **Regions next**, resolved nearest-first against the geometry `Plot::layout()`
|
||||
/// measured: a bound within the grab radius beats the body (so the bound of a
|
||||
/// wide region is grabbable even though the pointer is inside the fill), the
|
||||
@@ -161,7 +164,7 @@ using plot::RegionGrab;
|
||||
/// The plot geometry the controller hit-tests in is device pixels (see
|
||||
/// `PlotLayout`), and each adapter converts its pointer coordinates into the same
|
||||
/// space before forwarding them. A tolerance written as a device constant would
|
||||
/// therefore change its *physical* size with the display: a 5 px grab radius is
|
||||
/// therefore change its *physical* size with the display: a 7 px grab radius is
|
||||
/// half the hand movement on a 2x panel, so the same cursor becomes harder to
|
||||
/// catch there. Both tolerances -- the cursor grab radius and the box-zoom click
|
||||
/// threshold -- are therefore logical constants, converted through
|
||||
|
||||
@@ -12,6 +12,23 @@ enum class SnapMode {
|
||||
NearestSample, ///< the cursor is pulled onto the nearest sample of the trace's x grid.
|
||||
};
|
||||
|
||||
/// How a setter stores the coordinate it is handed: the *act* of placing, not the
|
||||
/// cursor's own state (which is `SnapMode`/`HRulerSnap`).
|
||||
///
|
||||
/// `Snapped` applies the cursor's own snap rule at once -- the default, and what a
|
||||
/// programmatic placement wants: the coordinate a caller asks for is put on the grid the
|
||||
/// cursor asked for. `Free` stores the value verbatim and leaves the snap to a later act
|
||||
/// (`Plot::snap_cursor()`), which is what a *drag* wants: the marker follows the pointer
|
||||
/// under the hand and lands on the grid only when the gesture ends, exactly as a region's
|
||||
/// bounds do between `Plot::set_region()` and `Plot::snap_region()`. The two are told
|
||||
/// apart by which act the caller means, not by a second copy of the snap state -- the
|
||||
/// cursor still holds one `SnapMode` and one `HRulerSnap`, and `Free` here does not
|
||||
/// change either.
|
||||
enum class CursorPlacement {
|
||||
Snapped, ///< apply the cursor's own snap rule now (the default).
|
||||
Free, ///< store the coordinate verbatim; snap later, if at all.
|
||||
};
|
||||
|
||||
/// Which of a cursor's two coordinates is live, and how it reads: the instrument
|
||||
/// the plot has always had, and the same one turned a quarter turn (spec §14).
|
||||
///
|
||||
|
||||
@@ -388,19 +388,44 @@ class Plot {
|
||||
// --- cursors and measurements -----------------------------------------
|
||||
|
||||
/// Moves a **vertical** cursor along x, and invalidates the measurements that depend
|
||||
/// on cursors. A `SnapMode::NearestSample` cursor is pulled onto the nearest sample of
|
||||
/// the first visible trace on its x axis.
|
||||
/// on cursors. With the default `CursorPlacement::Snapped`, a `SnapMode::NearestSample`
|
||||
/// cursor is pulled onto the nearest sample of the first visible trace on its x axis;
|
||||
/// with `CursorPlacement::Free` the value is stored verbatim, whatever the snap, and the
|
||||
/// grid is applied later by `snap_cursor()`.
|
||||
///
|
||||
/// The two are the two things a caller does with this method: place a marker
|
||||
/// programmatically (default -- snap now), or move it under a pointer for the length of
|
||||
/// a gesture (`Free`). `input::Controller::move_cursor()` is the second, so **the value
|
||||
/// this stores while that drag runs, and the value `cursor(id).x` reports, is the free
|
||||
/// pointer position, not the snapped one** -- the snap is committed once, on release
|
||||
/// (`snap_cursor()`, from `Controller::end_drag()`). A caller reading `cursor(id).x`
|
||||
/// mid-drag reads what the user sees under the pointer; after the drop it reads the
|
||||
/// snapped result. A host that wants the cursor to *hop* between samples as it is
|
||||
/// dragged -- the old behaviour -- calls this without `Free` on every motion.
|
||||
///
|
||||
/// A horizontal ruler's `x` is not a coordinate of its: this is *ignored* for one, so
|
||||
/// the dead field of an orientation can never be written behind its back (see
|
||||
/// CursorOrientation). `set_cursor_y()` is the ruler's half of the pair.
|
||||
void set_cursor_x(u32 id, f64 x);
|
||||
void set_cursor_x(u32 id, f64 x, CursorPlacement placement = CursorPlacement::Snapped);
|
||||
/// Sets the snap of a **vertical** cursor, re-placing it under the new rule at once.
|
||||
/// Ignored for a horizontal ruler, whose snap is `HRulerSnap` -- see
|
||||
/// `set_cursor_h_snap()`.
|
||||
void set_cursor_snap(u32 id, SnapMode mode);
|
||||
|
||||
/// Moves a **horizontal** ruler along y, re-placing it under its own snap rule.
|
||||
/// Applies a cursor's own snap rule to the coordinate it already holds: the nearest
|
||||
/// sample for a `SnapMode::NearestSample` marker, the nearest y tick for a
|
||||
/// `HRulerSnap::NearestTick` ruler, and nothing for a `Free` cursor of either
|
||||
/// orientation. The one act `input::Controller::end_drag()` commits a cursor drag with,
|
||||
/// so the drop lands on the grid -- the same shape as `snap_region()`, which a region
|
||||
/// drag ends with, and the reason both orientations snap on drop rather than
|
||||
/// continuously.
|
||||
void snap_cursor(u32 id);
|
||||
|
||||
/// Moves a **horizontal** ruler along y, re-placing it under its own snap rule unless
|
||||
/// `CursorPlacement::Free` is passed -- in which case the value is stored verbatim and
|
||||
/// the snap waits for `snap_cursor()`, exactly as `set_cursor_x()`'s `Free` does for a
|
||||
/// marker. The two orientations therefore snap at the *same* moment of a gesture (the
|
||||
/// drop), not one continuously and the other on release.
|
||||
///
|
||||
/// Ignored for a vertical cursor -- `y` is not its coordinate -- and stored verbatim for
|
||||
/// a ruler, exactly as `set_cursor_x()` stores a `Free` cursor's x: a y outside the axis'
|
||||
@@ -409,7 +434,7 @@ class Plot {
|
||||
/// that has left the axes has no data under it, so `input::Controller` keeps a dragged
|
||||
/// ruler on its axis' range rather than storing a coordinate no pointer could reach
|
||||
/// (see `Controller::move_cursor()`).
|
||||
void set_cursor_y(u32 id, f64 y);
|
||||
void set_cursor_y(u32 id, f64 y, CursorPlacement placement = CursorPlacement::Snapped);
|
||||
/// Sets the snap of a **horizontal** ruler: `NearestTick` pulls its y onto the nearest
|
||||
/// tick of its y axis' tick set -- majors and minors alike, the one list the axis
|
||||
/// refreshed -- and `Free` leaves it where it is.
|
||||
|
||||
Reference in new issue
Block a user