Repository navigation
table: Sort from the header cell and report one-row visible ranges - #3385
Open
AncientPixel wants to merge 2 commits into
Open
AncientPixel wants to merge 2 commits into
AncientPixel wants to merge 2 commits into
Conversation
A click on a column header only selected the column. Sorting needed a click on the small sort icon, which users read as a direction indicator rather than a button (longbridge#3362). A click anywhere on a sortable column's header now cycles its sort. The sort icon no longer has its own click handler, so a click on it bubbles to the header and sorts once. A click on a header without a sort still selects the column, and the arrow keys still select any column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PRpJSFk3zTwdgAJHehdZFm
`visible_rows_changed` skipped every range of one row or fewer, because uniform_list also calls its render callback with `ix..ix+1` to measure a row. So a one-row table never reported `0..1`, a table that dropped to no rows kept its stale range, and with `stripe` the filler rows pushed the reported end past `rows_count`. A "showing a-b of n" footer had to clamp locally and showed a wrong range on load. The one-row guard now applies only when there is more than one item, the reported end is clamped to the item count, and the empty-table branch reports `0..0`. A clamped range left empty while items exist is stale (the list scrolls back next frame) and is not reported. The column axis gets the same item-count guard, since its virtual list measures the same way; that path has no dedicated test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PRpJSFk3zTwdgAJHehdZFm
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3362
Description
Two small DataTable fixes in
TableState, one commit each. They are separate, so I can split them into two PRs if you prefer.1. Sort a column from its header
On
main, a click on a column header only selects the column: the header'son_click(crates/component/src/table/state.rs:1650-1654) callson_col_head_click(state.rs:822-836), which callsset_selected_col. Sorting happens only in the click handler of the small sort icon (state.rs:1614-1625). As #3362 says, users read that icon as a direction indicator, not a button, and expect a header click to sort.Now
on_col_head_click(state.rs:824) sorts when the table is sortable and the column has a sort (Column::sortable(),ascending(),descending()orsort(..)). It calls the sameperform_sort, so the cycle is unchanged: default, descending, ascending, default. The sort icon's own click handler is removed. A click on the icon now bubbles to the header and sorts once. The icon keeps its hover and active styles. A click on a header without a sort still selects the column, as before.Behaviour change: a click on a sortable header now sorts instead of selecting the column. Column selection stays reachable for those columns from the keyboard (
left/right/tab, which already select columns) and from code (set_selected_col,set_selection). A mouse-only user can no longer select a sortable column. I did not add an option to restore the old click behaviour, because the issue asks for the new behaviour as the default and nothing in the table depends on selecting a sortable column by mouse. If you prefer an option, I can add one.The sort icon's header background (#2379) is not touched.
2. Report visible row ranges of one row or none
On
main,update_visible_range_if_needreturned early for any range of one row or fewer (state.rs:1340-1344), becauseuniform_listalso calls the render callback withix..ix+1to measure a row. As a result:0..1;state.rs:2461-2490) does not render the list, sovisible_rows_changedkept the stale range;stripe, the filler rows (state.rs:2443-2447) are part of the list, so the reported end could passrows_count(a 3-row striped table reported0..8).An app that shows "Showing a-b of n" under a table had to clamp the range itself and still showed a wrong range on first load.
The fix (
state.rs:1344-1364):update_visible_range_if_needtakes the item count. The one-item guard applies only when there is more than one item.0..0(state.rs:2480). This is the only report made fromrenderitself; the others run inside the list callbacks. The existing equality check means this fires once, and not at all for a table that starts empty.The column axis had the same guard. Its virtual list (
crates/base/src/virtual_list.rs:314-335) measures withix..ix+1too, so a table with one scrollable column never reported0..1. The column call now passes the number of scrollable columns (columns_count - left fixed columns) and gets the same treatment. The reported column range is still relative to the scrollable columns, as before. No test covers the column path.The
visible_rows_changeddoc comment now says the range never ends pastrows_countand that an empty table reports0..0.Remaining edge: when there is more than one row but the viewport is shorter than one row, the real range is one row long and is still skipped, because it cannot be told apart from the measuring call.
This change was written with AI assistance (Claude Code).
Breaking Changes
No public signature changes. There are two behaviour changes:
TableEvent::SelectColumn. Headers without a sort behave as before.TableDelegate::visible_rows_changednow also fires with0..1for a one-row table and0..0when the rows drop to none, and its end never passesrows_count.visible_columns_changedlikewise fires for a single scrollable column.How to Test
New UI tests in
crates/kit/tests/collections.rs, using a delegate that recordsperform_sortandvisible_rows_changedcalls:table_header_click_sorts_sortable_columns_and_selects_the_rest: clicks("col-header", 0)three times and checksperform_sortsaw descending, ascending, default, with no column selected; then clicks("col-header", 1)(no sort) and checks column 1 is selected and no sort ran.table_reports_one_row_and_empty_visible_ranges: a 1-row table reports0..1; after the row count drops to 0 and a frame renders, it reports0..0.table_visible_range_stops_at_the_last_row_under_stripe_filler: a 3-row striped table never reports a range ending past 3.All three failed on
main([]sorts, no0..1report,[0..3, 0..8]) and pass with the change.Clippy is clean for the touched crates. The
-A clippy::nonminimal_boolis only there because clippy on Rust 1.95 flagscrates/base/src/calendar.rs:132, which this PR does not touch.Checklist
cargo runfor story tests related to the changes.Tested macOS, Windows and Linux platforms performance (if the change is platform-specific)Not applicable: the change is not platform-specific.🤖 Generated with Claude Code
https://claude.ai/code/session_01PRpJSFk3zTwdgAJHehdZFm