MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ScrollState.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ViewTransform.hpp"
4
6
7namespace MayaFlux::Kinesis {
8
9/**
10 * @brief Convert a pixel-space drag delta into a content-space delta.
11 *
12 * Scales the fraction of the viewport a pointer moved by the content
13 * extent currently visible, so drag speed stays proportionate to scale:
14 * more content in view moves the result further per pixel than less. No
15 * sign convention is imposed; a caller applies whatever sign its own
16 * semantics need (a grabbed canvas moves opposite the drag, a dragged
17 * scrollbar thumb moves with it).
18 *
19 * Shared by PanZoom2DState::apply_pan_zoom_pan and any CPU-side drag
20 * scroll: both are "drag the content by moving the viewport's frame over
21 * it," differing only in what consumes the result (a GPU ViewTransform
22 * versus a CPU layout offset).
23 *
24 * @param pixel_delta Pixel-space delta.
25 * @param visible_extent Currently visible content extent (width, height), same units as the return value.
26 * @param viewport_size_pixels Viewport size in pixels the delta was measured against.
27 */
28[[nodiscard]] MAYAFLUX_API glm::vec2 drag_to_offset_delta(
29 glm::vec2 pixel_delta,
30 glm::vec2 visible_extent,
31 glm::vec2 viewport_size_pixels) noexcept;
32
33/**
34 * @struct ScrollState
35 * @brief CPU-side scroll offset for a bounded content region.
36 *
37 * The interactable half of scrolling. offset is a content-space
38 * translation, clamped so a viewport of viewport_bounds's size never
39 * scrolls past content_bounds. offset increases as the view moves deeper
40 * into content: zero shows the top-left of content_bounds, the clamped
41 * maximum shows its bottom-right.
42 *
43 * content_bounds is not clamped to NDC. It is whatever extent the content
44 * actually occupies (the accumulated height of every row a LayoutCursor
45 * has advanced through, typically), routinely far taller than the
46 * [-1, 1] a viewport can show at once - that excess is the whole point of
47 * scrolling.
48 *
49 * A consumer applies offset however its own rendering model wants it.
50 * Portal::Forma::LayoutCursor folds it directly into placed bounds (CPU
51 * reflow, always hit-test-correct by construction, since the same value
52 * that moved the geometry is available to move the hit region too). A
53 * buffer wanting to shift many vertices at once without a per-element CPU
54 * reflow can instead derive a ViewTransform via scroll_view_transform()
55 * and skip that per-element work, at the cost of needing to remap
56 * hit-test coordinates by the same offset itself: nothing does that
57 * remapping automatically, so a GPU-only shift and CPU hit-testing will
58 * disagree the moment offset is nonzero unless something closes that loop.
59 */
61 glm::vec2 offset { 0.F, 0.F };
62 AABB2D content_bounds { .min = glm::vec2(-1.F), .max = glm::vec2(1.F) };
63 AABB2D viewport_bounds { .min = glm::vec2(-1.F), .max = glm::vec2(1.F) };
64};
65
66/**
67 * @brief Clamp a content-space offset so a viewport of the given extent
68 * never scrolls past the edges of a content region, per axis.
69 *
70 * An axis where content is smaller than the viewport clamps to zero
71 * rather than to a degenerate range: there is nothing to scroll on that
72 * axis.
73 */
74[[nodiscard]] MAYAFLUX_API glm::vec2 clamp_offset_to_content(
75 glm::vec2 offset,
76 glm::vec2 viewport_extent,
77 AABB2D content_bounds) noexcept;
78
79/**
80 * @brief Add a content-space delta to the offset and clamp to content_bounds.
81 */
82MAYAFLUX_API void apply_scroll(ScrollState& state, glm::vec2 delta) noexcept;
83
84/**
85 * @brief Apply a wheel-tick delta, scaled by speed, and clamp.
86 *
87 * Sign matches whatever convention Context::on_scroll's dx/dy already
88 * deliver on this platform; not independently verified interactively, so
89 * flip the sign here first if a wheel test scrolls backward.
90 *
91 * @param state Scroll state (offset mutated).
92 * @param dx, dy Wheel delta, as delivered by Context::ScrollFn.
93 * @param speed Content-space units per wheel tick.
94 */
95MAYAFLUX_API void apply_wheel_scroll(ScrollState& state, double dx, double dy, float speed = 0.08F) noexcept;
96
97/**
98 * @brief Build an orthographic ViewTransform that translates by +offset.
99 *
100 * For content already authored directly in NDC, as every Forma geometry
101 * function is, this is view = translate(offset), projection = identity:
102 * the vertex shader's projection * view * position reduces to
103 * position + offset, the same shift LayoutCursor applies on the CPU side.
104 *
105 * Meant for a buffer that wants to shift many vertices as one GPU-side
106 * move instead of a per-element CPU reflow. Hit-testing against elements
107 * shifted this way still needs the same offset applied to the cursor
108 * position before testing them - see ScrollState's own doc comment; this
109 * function only produces the render-side half.
110 */
111[[nodiscard]] MAYAFLUX_API ViewTransform scroll_view_transform(const ScrollState& state) noexcept;
112
113} // namespace MayaFlux::Kinesis
uint64_t offset
Definition Composite.cpp:10
ViewTransform scroll_view_transform(const ScrollState &state) noexcept
Build an orthographic ViewTransform that translates by +offset.
void apply_wheel_scroll(ScrollState &state, double dx, double dy, float speed) noexcept
Apply a wheel-tick delta, scaled by speed, and clamp.
void apply_scroll(NavigationState &st, float ticks)
Dolly eye along the current forward vector.
double speed(const Memory::HistoryBuffer< double > &history, double dt) noexcept
Absolute value of a scalar first difference.
glm::vec2 drag_to_offset_delta(glm::vec2 pixel_delta, glm::vec2 visible_extent, glm::vec2 viewport_size_pixels) noexcept
Convert a pixel-space drag delta into a content-space delta.
glm::vec2 clamp_offset_to_content(glm::vec2 offset, glm::vec2 viewport_extent, AABB2D content_bounds) noexcept
Clamp a content-space offset so a viewport of the given extent never scrolls past the edges of a cont...
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
CPU-side scroll offset for a bounded content region.