whether the detail view has been opened for the current selection
the page the selection is on, derived from it rather than tracked next to it
how many pages rows fills; always at least 1, so an empty list is one empty page
the rows the current page shows
the filtered rows of the current tab, across every page
the selection's index into rows (not into pageRows)
the currently open tab
every tab, in display order, for a tab strip to draw
moves the selection delta rows, skipping disabled ones and clamping at both ends
moves delta pages; the selection lands on the target page's first selectable row
moves to the next enabled tab, delta steps on (wrapping); skips disabled tabs
opens the detail view for the current selection; false when there is nothing to open
opens id's tab; a disabled tab or an unknown id is ignored
jumps to a page by number, clamped; the selection moves to its first selectable row
replaces the query; the selection and page reset to the first row that survives it
The model behind a tabbed, searchable, paged list - an inventory, journal, shop or codex - kept apart from how it is drawn, the same split
SelectionModelalready draws for plain lists. The caller supplies the tabs and the rows per tab (any type it likes, so no item taxonomy is assumed), plus optionally how a row labels, filters and disables itself; this owns the tab choice, the query, the selection, the page and the detail/close state.The page is derived from the selection rather than tracked beside it: a selection index into the filtered rows decides which page is visible, so the two can never disagree and
nextPageis just a selection move of one page.moveskips disabled rows.Rendering is the caller's: read
pageRowsandselectedIndexeach frame, or listen toonChange.Example