Tables: added ImGuiTableFlags_SortTristate. Renamed ImGuiTableFlags_MultiSortable to ImGuiTableFlags_SortMulti. Removed now unused FlagsIn storage.

This commit is contained in:
ocornut 2020-12-11 21:33:37 +01:00
parent cad8935bfd
commit 738606a294
4 changed files with 121 additions and 85 deletions

50
imgui.h
View File

@ -1055,38 +1055,40 @@ enum ImGuiTableFlags_
ImGuiTableFlags_Reorderable = 1 << 1, // Allow reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) ImGuiTableFlags_Reorderable = 1 << 1, // Allow reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
ImGuiTableFlags_Hideable = 1 << 2, // Allow hiding/disabling columns in context menu. ImGuiTableFlags_Hideable = 1 << 2, // Allow hiding/disabling columns in context menu.
ImGuiTableFlags_Sortable = 1 << 3, // Allow sorting on one column (sort_specs_count will always be == 1). Call TableGetSortSpecs() to obtain sort specs. ImGuiTableFlags_Sortable = 1 << 3, // Allow sorting on one column (sort_specs_count will always be == 1). Call TableGetSortSpecs() to obtain sort specs.
ImGuiTableFlags_MultiSortable = 1 << 4, // Allow sorting on multiple columns by holding Shift (sort_specs_count may be > 1). Call TableGetSortSpecs() to obtain sort specs. ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file.
ImGuiTableFlags_NoSavedSettings = 1 << 5, // Disable persisting columns order, width and sort settings in the .ini file. ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
ImGuiTableFlags_ContextMenuInBody = 1 << 6, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
// Decorations // Decorations
ImGuiTableFlags_RowBg = 1 << 7, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
ImGuiTableFlags_BordersInnerH = 1 << 8, // Draw horizontal borders between rows. ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows.
ImGuiTableFlags_BordersOuterH = 1 << 9, // Draw horizontal borders at the top and bottom. ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom.
ImGuiTableFlags_BordersInnerV = 1 << 10, // Draw vertical borders between columns. ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns.
ImGuiTableFlags_BordersOuterV = 1 << 11, // Draw vertical borders on the left and right sides. ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides.
ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders.
ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders.
ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders.
ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders.
ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders.
ImGuiTableFlags_NoBordersInBody = 1 << 12, // Disable vertical borders in columns Body (borders will always appears in Headers). ImGuiTableFlags_NoBordersInBody = 1 << 11, // Disable vertical borders in columns Body (borders will always appears in Headers).
ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 13, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers).
// Sizing // Sizing
ImGuiTableFlags_ColumnsWidthStretch = 1 << 14, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details. ImGuiTableFlags_ColumnsWidthStretch = 1 << 13, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details.
ImGuiTableFlags_ColumnsWidthFixed = 1 << 15, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details. ImGuiTableFlags_ColumnsWidthFixed = 1 << 14, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details.
ImGuiTableFlags_SameWidths = 1 << 16, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable. ImGuiTableFlags_SameWidths = 1 << 15, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable.
ImGuiTableFlags_NoHeadersWidth = 1 << 17, // Disable headers' contribution to automatic width calculation. ImGuiTableFlags_NoHeadersWidth = 1 << 16, // Disable headers' contribution to automatic width calculation.
ImGuiTableFlags_NoHostExtendY = 1 << 18, // Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) ImGuiTableFlags_NoHostExtendY = 1 << 17, // Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible)
ImGuiTableFlags_NoKeepColumnsVisible = 1 << 19, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small.
ImGuiTableFlags_PreciseWidths = 1 << 20, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.
ImGuiTableFlags_NoClip = 1 << 21, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().
// Padding // Padding
ImGuiTableFlags_PadOuterX = 1 << 22, // Default if BordersOuterV is on. Enable outer-most padding. ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outer-most padding.
ImGuiTableFlags_NoPadOuterX = 1 << 23, // Default if BordersOuterV is off. Disable outer-most padding. ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outer-most padding.
ImGuiTableFlags_NoPadInnerX = 1 << 24, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).
// Scrolling // Scrolling
ImGuiTableFlags_ScrollX = 1 << 25, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX.
ImGuiTableFlags_ScrollY = 1 << 26 // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
// Sorting
ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
ImGuiTableFlags_SortTristate = 1 << 27 // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
}; };
// Flags for ImGui::TableSetupColumn() // Flags for ImGui::TableSetupColumn()
@ -1915,7 +1917,7 @@ struct ImGuiTableColumnSortSpecs
struct ImGuiTableSortSpecs struct ImGuiTableSortSpecs
{ {
const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array.
int SpecsCount; // Sort spec count. Most often 1 unless e.g. ImGuiTableFlags_MultiSortable is enabled. int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled.
bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag.
ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); }

View File

@ -4572,8 +4572,6 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Sorting")) if (ImGui::TreeNode("Sorting"))
{ {
HelpMarker("Use Shift+Click to sort on multiple columns");
// Create item list // Create item list
static ImVector<MyItem> items; static ImVector<MyItem> items;
if (items.Size == 0) if (items.Size == 0)
@ -4589,10 +4587,16 @@ static void ShowDemoWindowTables()
} }
} }
ImGuiTableFlags flags = // Options
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable static ImGuiTableFlags flags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollY; | ImGuiTableFlags_ScrollY;
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
if (ImGui::BeginTable("##table", 4, flags, ImVec2(0, TEXT_BASE_HEIGHT * 15), 0.0f)) if (ImGui::BeginTable("##table", 4, flags, ImVec2(0, TEXT_BASE_HEIGHT * 15), 0.0f))
{ {
// Declare columns // Declare columns
@ -4651,11 +4655,11 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNode("Advanced")) if (ImGui::TreeNode("Advanced"))
{ {
static ImGuiTableFlags flags = static ImGuiTableFlags flags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
| ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_ColumnsWidthFixed;
;
enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
static int contents_type = CT_Button; static int contents_type = CT_Button;
@ -4683,7 +4687,6 @@ static void ShowDemoWindowTables()
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable); ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
ImGui::CheckboxFlags("ImGuiTableFlags_MultiSortable", &flags, ImGuiTableFlags_MultiSortable);
ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings); ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody); ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
ImGui::TreePop(); ImGui::TreePop();
@ -4744,6 +4747,15 @@ static void ShowDemoWindowTables()
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen)) if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
{ {
ImGui::Checkbox("show_headers", &show_headers); ImGui::Checkbox("show_headers", &show_headers);
@ -4799,13 +4811,13 @@ static void ShowDemoWindowTables()
// Declare columns // Declare columns
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, -1.0f, MyItemColumnID_ID); ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, -1.0f, MyItemColumnID_ID);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Name); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Name);
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action); ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action);
ImGui::TableSetupColumn("Quantity (Long Label)", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Quantity);// , ImGuiTableColumnFlags_WidthAutoResize); ImGui::TableSetupColumn("Quantity (Long Label)", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Quantity);// , ImGuiTableColumnFlags_WidthAutoResize);
ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Description); ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Description);
ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
// Sort our data if sort specs have been changed! // Sort our data if sort specs have been changed!
ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs();

View File

@ -1906,8 +1906,7 @@ struct ImGuiTableColumn
{ {
ImRect ClipRect; // Clipping rectangle for the column ImRect ClipRect; // Clipping rectangle for the column
ImGuiID UserID; // Optional, value passed to TableSetupColumn() ImGuiID UserID; // Optional, value passed to TableSetupColumn()
ImGuiTableColumnFlags FlagsIn; // Flags as they were provided by user. See ImGuiTableColumnFlags_ ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_
ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_
float MinX; // Absolute positions float MinX; // Absolute positions
float MaxX; float MaxX;
float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
@ -1939,9 +1938,12 @@ struct ImGuiTableColumn
bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen).
bool IsPreserveWidthAuto; bool IsPreserveWidthAuto;
ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
ImS8 SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit
ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem
ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3)
ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each)
ImU8 SortDirectionsAvailList; // Ordered of available sort directions (2-bits each)
ImGuiTableColumn() ImGuiTableColumn()
{ {
@ -2307,7 +2309,8 @@ namespace ImGui
IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
IMGUI_API void TableFixColumnSortDirection(ImGuiTableColumn* column); IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column);
IMGUI_API void TableBeginRow(ImGuiTable* table); IMGUI_API void TableBeginRow(ImGuiTable* table);
IMGUI_API void TableEndRow(ImGuiTable* table); IMGUI_API void TableEndRow(ImGuiTable* table);
IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n);

View File

@ -190,10 +190,6 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
if ((flags & (ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ColumnsWidthFixed)) == 0) if ((flags & (ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ColumnsWidthFixed)) == 0)
flags |= (flags & ImGuiTableFlags_ScrollX) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch; flags |= (flags & ImGuiTableFlags_ScrollX) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch;
// Adjust flags: MultiSortable automatically enable Sortable
if (flags & ImGuiTableFlags_MultiSortable)
flags |= ImGuiTableFlags_Sortable;
// Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV) // Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV)
if (flags & ImGuiTableFlags_SameWidths) if (flags & ImGuiTableFlags_SameWidths)
flags = (flags & ~ImGuiTableFlags_Resizable) | ImGuiTableFlags_NoKeepColumnsVisible; flags = (flags & ~ImGuiTableFlags_Resizable) | ImGuiTableFlags_NoKeepColumnsVisible;
@ -562,7 +558,6 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
} }
// Adjust flags: default width mode + stretch columns are not allowed when auto extending // Adjust flags: default width mode + stretch columns are not allowed when auto extending
// Set 'column->FlagsIn' and 'column->Flags'.
static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in)
{ {
ImGuiTableColumnFlags flags = flags_in; ImGuiTableColumnFlags flags = flags_in;
@ -594,8 +589,23 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I
//IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used. //IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used.
// Preserve status flags // Preserve status flags
column->FlagsIn = flags_in;
column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_);
// Build an ordered list of available sort directions
column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0;
if (table->Flags & ImGuiTableFlags_Sortable)
{
int count = 0, mask = 0, list = 0;
if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; }
if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }
if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; }
if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }
if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; }
column->SortDirectionsAvailList = (ImU8)list;
column->SortDirectionsAvailMask = (ImU8)mask;
column->SortDirectionsAvailCount = (ImU8)count;
ImGui::TableFixColumnSortDirection(table, column);
}
} }
// Layout columns for the frame. This is in essence the followup to BeginTable(). // Layout columns for the frame. This is in essence the followup to BeginTable().
@ -644,7 +654,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (!column->IsEnabled && column->SortOrder != -1) if (!column->IsEnabled && column->SortOrder != -1)
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
} }
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable)) if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
bool start_auto_fit = false; bool start_auto_fit = false;
@ -662,6 +672,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder; ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder;
if (column->IsEnabled) if (column->IsEnabled)
{ {
// Mark as enabled and link to previous/next enabled column
column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
column->NextEnabledColumn = -1; column->NextEnabledColumn = -1;
if (last_visible_column_idx != -1) if (last_visible_column_idx != -1)
@ -678,6 +689,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
} }
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
} }
if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))
table->IsSortSpecsDirty = true;
table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
// [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible
@ -707,11 +720,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0) if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0)
count_resizable++; count_resizable++;
// We have a unusual edge case where if the user doesn't call TableGetSortSpecs() but has sorting enabled
// or varying sorting flags, we still want the sorting arrows to honor those flags.
if (table->Flags & ImGuiTableFlags_Sortable)
TableFixColumnSortDirection(column);
// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
// Combine width from regular rows + width from headers unless requested not to. // Combine width from regular rows + width from headers unless requested not to.
if (!column->IsPreserveWidthAuto) if (!column->IsPreserveWidthAuto)
@ -942,7 +950,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables. // Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables.
// FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY. // FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY.
// Taking advantage of LastOuterHeight would yield good results there... // Taking advantage of LastOuterHeight would yield good results there...
// FIXME-TABLE: IsVisible == false is disabled because it effectively means not submitting will reduces contents width which is fed to outer_window->DC.CursorMaxPos.x, // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x,
// and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else). // and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else).
// Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small. // Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small.
column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x);
@ -958,9 +966,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Mark column as SkipItems (ignoring all items/layout) // Mark column as SkipItems (ignoring all items/layout)
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
//if (!is_visible && (column->Flags & ImGuiTableColumnFlags_AutoCull))
// if ((column->AutoFitQueue & 1) == 0 && (column->CannotSkipItemsQueue & 1) == 0)
// column->IsSkipItems = true;
if (column->IsSkipItems) if (column->IsSkipItems)
IM_ASSERT(!is_visible); IM_ASSERT(!is_visible);
@ -1177,7 +1182,8 @@ void ImGui::EndTable()
#if 0 #if 0
// Strip out dummy channel draw calls // Strip out dummy channel draw calls
// We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out) // We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out)
// (The problem with this approach is we are effectively making it harder for users watching metrics to spot wasted vertices) // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway.
// Cons: making it harder for users watching metrics/debugger to spot the wasted vertices.
if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1)
{ {
ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel];
@ -1281,7 +1287,6 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
// When passing a width automatically enforce WidthFixed policy // When passing a width automatically enforce WidthFixed policy
// (vs TableFixColumnFlags would default to WidthAutoResize) // (vs TableFixColumnFlags would default to WidthAutoResize)
// (we write to FlagsIn which is a little misleading, another solution would be to pass init_width_or_weight to TableFixColumnFlags)
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0)
if ((table->Flags & ImGuiTableFlags_ColumnsWidthFixed) && (init_width_or_weight > 0.0f)) if ((table->Flags & ImGuiTableFlags_ColumnsWidthFixed) && (init_width_or_weight > 0.0f))
flags |= ImGuiTableColumnFlags_WidthFixed; flags |= ImGuiTableColumnFlags_WidthFixed;
@ -1313,7 +1318,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
column->IsEnabled = column->IsEnabledNextFrame = false; column->IsEnabled = column->IsEnabledNextFrame = false;
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
{ {
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reordered when building the sort specs. column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
} }
} }
@ -2342,6 +2347,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// - TableGetSortSpecs() // - TableGetSortSpecs()
// - TableFixColumnSortDirection() [Internal] // - TableFixColumnSortDirection() [Internal]
// - TableGetColumnNextSortDirection() [Internal]
// - TableSetColumnSortDirection() [Internal] // - TableSetColumnSortDirection() [Internal]
// - TableSortSpecsSanitize() [Internal] // - TableSortSpecsSanitize() [Internal]
// - TableSortSpecsBuild() [Internal] // - TableSortSpecsBuild() [Internal]
@ -2367,22 +2373,39 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
if (table->IsSortSpecsDirty) if (table->IsSortSpecsDirty)
TableSortSpecsBuild(table); TableSortSpecsBuild(table);
return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL; return &table->SortSpecs;
} }
void ImGui::TableFixColumnSortDirection(ImGuiTableColumn* column) static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n)
{ {
// Initial sort state IM_ASSERT(n < column->SortDirectionsAvailCount);
if (column->SortDirection == ImGuiSortDirection_None) return (column->SortDirectionsAvailList >> (n << 1)) & 0x03;
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImS8)(ImGuiSortDirection_Ascending);
// Handle NoSortAscending/NoSortDescending
if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending))
column->SortDirection = ImGuiSortDirection_Descending;
else if (column->SortDirection == ImGuiSortDirection_Descending && (column->Flags & ImGuiTableColumnFlags_NoSortDescending))
column->SortDirection = ImGuiSortDirection_Ascending;
} }
// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending)
void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column)
{
if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0)
return;
column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0);
table->IsSortSpecsDirty = true;
}
// Calculate next sort direction that would be set after clicking the column
// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click.
// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op.
IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2);
ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column)
{
IM_ASSERT(column->SortDirectionsAvailCount > 0);
if (column->SortOrder == -1)
return TableGetColumnAvailSortDirection(column, 0);
for (int n = 0; n < 3; n++)
if (column->SortDirection == TableGetColumnAvailSortDirection(column, n))
return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount);
IM_ASSERT(0);
return ImGuiSortDirection_None;
}
// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert // Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert
// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. // the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code.
@ -2391,8 +2414,10 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable; ImGuiTable* table = g.CurrentTable;
if (!(table->Flags & ImGuiTableFlags_MultiSortable)) if (!(table->Flags & ImGuiTableFlags_SortMulti))
append_to_sort_specs = false; append_to_sort_specs = false;
if (!(table->Flags & ImGuiTableFlags_SortTristate))
IM_ASSERT(sort_direction != ImGuiSortDirection_None);
ImGuiTableColumnIdx sort_order_max = 0; ImGuiTableColumnIdx sort_order_max = 0;
if (append_to_sort_specs) if (append_to_sort_specs)
@ -2400,8 +2425,10 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder); sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder);
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
column->SortDirection = (ImS8)sort_direction; column->SortDirection = (ImU8)sort_direction;
if (column->SortOrder == -1 || !append_to_sort_specs) if (column->SortDirection == ImGuiSortDirection_None)
column->SortOrder = -1;
else if (column->SortOrder == -1 || !append_to_sort_specs)
column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0; column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0;
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
@ -2409,7 +2436,7 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
ImGuiTableColumn* other_column = &table->Columns[other_column_n]; ImGuiTableColumn* other_column = &table->Columns[other_column_n];
if (other_column != column && !append_to_sort_specs) if (other_column != column && !append_to_sort_specs)
other_column->SortOrder = -1; other_column->SortOrder = -1;
TableFixColumnSortDirection(other_column); TableFixColumnSortDirection(table, other_column);
} }
table->IsSettingsDirty = true; table->IsSettingsDirty = true;
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
@ -2435,7 +2462,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
} }
const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1); const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1);
const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_MultiSortable); const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti);
if (need_fix_linearize || need_fix_single_sort_order) if (need_fix_linearize || need_fix_single_sort_order)
{ {
ImU64 fixed_mask = 0x00; ImU64 fixed_mask = 0x00;
@ -2465,7 +2492,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
} }
// Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag) // Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag)
if (sort_order_count == 0) if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
@ -2473,7 +2500,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
{ {
sort_order_count = 1; sort_order_count = 1;
column->SortOrder = 0; column->SortOrder = 0;
TableFixColumnSortDirection(column); column->SortDirection = TableGetColumnAvailSortDirection(column, 0);
break; break;
} }
} }
@ -2487,9 +2514,8 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table)
TableSortSpecsSanitize(table); TableSortSpecsSanitize(table);
// Write output // Write output
const bool single_sort_specs = (table->SortSpecsCount <= 1); table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
table->SortSpecsMulti.resize(single_sort_specs ? 0 : table->SortSpecsCount); ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
ImGuiTableColumnSortSpecs* sort_specs = single_sort_specs ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
@ -2688,14 +2714,7 @@ void ImGui::TableHeader(const char* label)
// Handle clicking on column header to adjust Sort Order // Handle clicking on column header to adjust Sort Order
if (pressed && table->ReorderColumn != column_n) if (pressed && table->ReorderColumn != column_n)
{ {
// Set new sort direction ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column);
// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click.
// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op.
ImGuiSortDirection sort_direction;
if (column->SortOrder == -1)
sort_direction = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending;
else
sort_direction = (column->SortDirection == ImGuiSortDirection_Ascending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending;
TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift);
} }
} }