annie.pages.paging

Incremental row paging shared by the Browse and Annotator tabs (UI helper).

Both tabs render long lists of expensive rows — every row schedules a lazy frame decode — so they reveal only annie.app_state.UiSettings.page_size rows at a time. This module owns that behaviour once:

  • Pager is the pure, side-effect-free cursor: how many rows are shown, how many remain, and which slice the next page covers. It is unit-tested on its own.

  • paged() is the thin NiceGUI shell around it, providing three affordances:

    1. a Jump to row section, so a reviewer resuming a long session can type 3400 and land there. Rows before the target are never built — that is the whole point, since building them would schedule thousands of frame decodes.

    2. a Show more button (the manual fallback, always present);

    3. a scroll sentinel — a zero-noise q-intersection element parked below the rows. Quasar fires its visibility event as the sentinel nears the viewport, which reveals the next page without a click. Because the listener is bound to the element, it dies with it on refresh() rather than accumulating.

Auto-scrolling is opt-out via the Settings tab; the sentinel is consulted on every event, so toggling the setting takes effect without rebuilding the list.

A row number identifies the sample, not its slot on screen. It is annie.core.models.VideoEntry.row_id — the video’s 1-based position in the whole scanned dataset, assigned once at scan time over the sorted manifest. So a filtered Browse tab shows a sparse #3, #17, #204 rather than renumbering from 1, the Annotator’s queued subset keeps each video’s dataset number, and “I stopped at 3400” survives a restart, a filter change, and a re-queue.

Classes

Pager

A cursor over total rows, revealed one page at a time.

Functions

index_of_row_id(→ int)

Return where target sits among the shown rows' row_ids.

paged(→ None)

Render entries one page at a time, with jump, auto-scroll, and a button.

Module Contents

class annie.pages.paging.Pager[source]

A cursor over total rows, revealed one page at a time.

total

The number of rows in the backing list.

start

Index of the first row actually rendered (non-zero after a seek).

shown

Index one past the last rendered row; also the count of rendered rows when start is 0.

advance(page_size: int) → slice[source]

Reserve the next page and return the slice of rows to render.

Parameters:

page_size – Rows to reveal. Values below 1 are clamped to 1, so a bad setting can never yield an empty page and stall the caller’s loop.

Returns:

The slice of the backing list covering the newly revealed rows.

seek(index: int) → None[source]

Restart paging at index, clamped into range.

The next advance() renders the page beginning at index; rows before it are skipped entirely rather than rendered and scrolled past.

Parameters:

index – Zero-based row index to resume from.

property remaining: int

How many rows are still unrendered.

property exhausted: bool

Whether every row from start onward has been rendered.

annie.pages.paging.index_of_row_id(row_ids: collections.abc.Sequence[int], target: int) → int[source]

Return where target sits among the shown rows’ row_ids.

Row ids increase along the list (they are positions in the same sorted manifest), so a filtered list is still ordered and can be searched. A row id that was filtered out resolves to the next one still on screen, which is what a reviewer typing “3400” into a filtered Browse tab means: take me to where 3400 would be.

Parameters:
  • row_ids – The dataset row ids of the shown rows, ascending.

  • target – The dataset row id to land on.

Returns:

A 0-based index into row_ids, clamped to the last row.

annie.pages.paging.paged[T](entries: collections.abc.Sequence[T], render_row: collections.abc.Callable[[T], None], *, row_id: collections.abc.Callable[[T], int], total_rows: int, actions: collections.abc.Callable[[], None] | None = None, container: collections.abc.Callable[[], nicegui.ui.element] | None = None, page_size: int | None = None, jump_slot: nicegui.ui.element | None = None) → None[source]

Render entries one page at a time, with jump, auto-scroll, and a button.

Parameters:
  • entries – The rows to page through — already filtered, still ordered.

  • render_row – Builds one row. Called inside the rows container.

  • row_id – The dataset row id of an entry, used to drive the jump box. This is the sample’s number in the whole dataset, not its index in entries.

  • total_rows – How many rows the unfiltered dataset has, so the jump box accepts any dataset row id even when the view is filtered.

  • actions – Builds extra controls at the end of the jump row, for list-wide operations that belong next to it (the Annotator’s “Clear all”).

  • container – Factory for the element newly revealed rows are built into. Defaults to a vertical column; the Browse grid view passes a wrapping row so its boxes flow into a grid.

  • page_size – Rows revealed per page. Defaults to annie.app_state.UiSettings.page_size; the grid view reveals more.

  • jump_slot – Where to build the “Jump to row” card. When given, it is rendered into that (pre-existing, persistent) element — e.g. the Browse View panel — instead of inline above the rows. The slot is cleared first, so a re-paged list never stacks duplicate jump cards.