SmartTableSorting.h
The ordering maths, kept away from the widget so it can be tested without one.
The table never sorts. It says a sort was asked for and draws whatever order comes back, and a model doing the ordering itself reaches for these. None of them touch a widget, a world or a thread, so a model can call them from wherever its sort runs.
- Namespace
- SmartTable::Sorting
- Members
- 8
Public functions 8
Compares without case, and reads a run of digits as one number.
Asteroid 10 comes before Asteroid 2 in plain text. Past the digits this carries no text order of its own, so a letter with a mark on it lands where plain text puts it and usually not where a reader would.
007 and 7 hold the same number, and the count of leading zeroes settles them once everything else has tied. Fewer zeroes come first. A shorter string that is the start of a longer one comes first.
Puts InOutIndices in order by one or more key levels. Pure: no widget, no UObject, any thread.
A descending level turns its own values round and nothing else. Empty keys go last either way, and that rule lives in here, where no caller can lose it by turning a comparison round.
Rows that tie on every level come out in row number order, so one input always gives one answer. Every level in KeyLevels is read by the original row number and never by place in InOutIndices. No levels at all leaves the order exactly as it arrived.
What a header click asks for next, on a column sorted Current.
Ascending goes to descending. Descending goes to unsorted while bAllowNone is on, and straight back to ascending while it is off, which leaves a table two states and no way to reach unsorted by clicking. Anything else starts at ascending, unsorted included.
The spec a plain header click gives: this column alone.
It replaces and never adds. Growing a spec belongs to SpecWithSecondary, which leaves a plain click as the way back to a table sorted by one column and nothing else.
A Mode of None gives an empty spec. That is how a table goes back to unsorted.
The spec a Shift header click gives: Current, with this column as the second level.
The column is dropped from Current before it is added again, so it can never sit at two levels at once. A Shift click on the column already primary drops it to second and raises the old second to primary, which is what turns a two level sort round without clearing it first.
Two levels at most: EColumnSortPriority offers Primary and Secondary, and a third level would order rows by something the header cannot draw. An empty Current makes the column the primary instead. A Mode of None takes the column off the spec.
Whether Spec holds a level that is not ColumnId, which is something for ColumnId to be second to.
The Then Sort By This menu entry asks this before it offers itself. On an empty spec SpecWithSecondary gives back a primary, which reads right under a click and wrong under a label that starts with Then.
False for nothing sorted at all, and false for this column being the only level, where second would mean second to itself.
Which of Candidates could not move a single row as a second sort level.
A second level only reorders rows that tie on the first. A column can do nothing exactly when it holds one value through every group of ties, and a primary whose values are all different leaves no group at all. PrimaryColumn is never in the answer, even where Candidates lists it, and fewer than two rows cannot tie.
ReadKey takes a presented row number, so the rows arrive in the order the sort put them in and one pass over them is enough. Pure: no widget, no model type, nothing bound to the game thread.
The ids of the columns a sort may use, in the order they were authored.