Raxol. UI. ScrollWindow
(Raxol v2.6.1)
View Source
Pure cursor-follow scroll windowing for vertical selection lists.
Keeps the cursor inside a fixed-height visible window: when the cursor
would step outside the window, scroll_top moves by exactly the amount
needed to bring it back in, so the item under the cursor lands on the
same screen row it approached the edge from (edge-anchored scrolling,
not page-jump scrolling). Also derives a proportional scrollbar thumb
position/size for the windowed content, nil when everything fits.
Consumers own scroll_top as persistent state (e.g. in a TEA model)
and thread it back in as prev_scroll_top on the next call -- this
function never mutates anything, it only computes the next frame.
Summary
Functions
Proportional scrollbar thumb {start_row, size} for total rows of
content in a visible_height-row track scrolled to scroll_top.
nil when content fits without scrolling (nothing to indicate).
Windows items around cursor, given a visible_height row budget and
the previous scroll_top (for edge-anchored continuity).
Types
@type t() :: %{ visible: list(), scroll_top: non_neg_integer(), cursor_row: non_neg_integer(), overflown?: boolean(), thumb: thumb() | nil }
@type thumb() :: {start_row :: non_neg_integer(), size :: pos_integer()}
Functions
@spec thumb(non_neg_integer(), pos_integer(), non_neg_integer()) :: thumb() | nil
Proportional scrollbar thumb {start_row, size} for total rows of
content in a visible_height-row track scrolled to scroll_top.
nil when content fits without scrolling (nothing to indicate).
@spec window(list(), integer(), pos_integer(), integer()) :: t()
Windows items around cursor, given a visible_height row budget and
the previous scroll_top (for edge-anchored continuity).
cursor is clamped to items' bounds. scroll_top is clamped so the
window never runs past either end of items, regardless of what
prev_scroll_top was (stale or out-of-range inputs self-heal).
Examples
iex> w = Raxol.UI.ScrollWindow.window(Enum.to_list(1..20), 0, 10, 0)
iex> w.scroll_top
0
iex> w.cursor_row
0
iex> # cursor steps onto the last visible row -> window scrolls by 1,
iex> # cursor stays pinned to the same screen row
iex> w = Raxol.UI.ScrollWindow.window(Enum.to_list(1..20), 10, 10, 0)
iex> {w.scroll_top, w.cursor_row}
{1, 9}