Merge branch 'master' into docking

This commit is contained in:
ocornut
2026-04-01 21:01:48 +02:00
4 changed files with 125 additions and 39 deletions
+16
View File
@@ -92,6 +92,22 @@ Other Changes:
buffer on the IsItemDeactivatedAfterEdit() frame. This could create issues when buffer on the IsItemDeactivatedAfterEdit() frame. This could create issues when
using the idiom of not applying edits before IsItemDeactivatedAfterEdit(). using the idiom of not applying edits before IsItemDeactivatedAfterEdit().
(#9308, #8915, #8273) (#9308, #8915, #8273)
- Tables:
- Allow reordering columns by dragging them in the context menu. (#9312)
- Context menu now presents columns in display order. (#9312)
- Fixed and clarified the behavior of using TableSetupScrollFreeze() with columns>1,
and where some of the columns within that range were Hidable.
- Before: TableSetupScrollFreeze(N, 0) made the first N _visible_ columns
part of the scroll freeze. So if you intentionally hide columns <N
the scroll freeze area would encompass the subsequent right columns.
- After: TableSetupScrollFreeze(N, 0) makes the first N _declared_ columns
part of the scroll freeze. So if you intentionally hide columns <N
the scroll freeze area will cover less columns.
- This is generally more sane and logical.
- Fixed dragging a header to reorder outside of visible bounds (due to horizontal scrolling)
from losing active id.
- Angled Headers: angled section for column being reordered via the regular headers
stays highlighted during reordering.
- Style: - Style:
- Border sizes are now scaled (and rounded) by ScaleAllSizes(). - Border sizes are now scaled (and rounded) by ScaleAllSizes().
- When using large values with ScallAllSizes(), the following items thickness - When using large values with ScallAllSizes(), the following items thickness
+1 -1
View File
@@ -30,7 +30,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.7 WIP" #define IMGUI_VERSION "1.92.7 WIP"
#define IMGUI_VERSION_NUM 19268 #define IMGUI_VERSION_NUM 19269
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
+1
View File
@@ -3278,6 +3278,7 @@ struct IMGUI_API ImGuiTable
ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0. ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0.
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held.
ImGuiTableColumnIdx LastHeldHeaderColumn; // Index of column header being held from previous frame.
ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared)
ImGuiTableColumnIdx ReorderColumnDstOrder; // Requested display order of column being reordered. ImGuiTableColumnIdx ReorderColumnDstOrder; // Requested display order of column being reordered.
ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column.
+106 -37
View File
@@ -585,7 +585,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934) table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
table->InstanceInteracted = -1; table->InstanceInteracted = -1;
table->ContextPopupColumn = -1; table->ContextPopupColumn = -1;
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; table->ReorderColumn = table->ReorderColumnDstOrder = table->ResizedColumn = table->LastResizedColumn = -1;
table->AutoFitSingleColumn = -1; table->AutoFitSingleColumn = -1;
table->HoveredColumnBody = table->HoveredColumnBorder = -1; table->HoveredColumnBody = table->HoveredColumnBorder = -1;
for (int n = 0; n < columns_count; n++) for (int n = 0; n < columns_count; n++)
@@ -702,6 +702,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
// Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test). // Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test).
if (table->InstanceCurrent == 0) if (table->InstanceCurrent == 0)
{ {
table->LastHeldHeaderColumn = table->HeldHeaderColumn;
table->HeldHeaderColumn = -1; table->HeldHeaderColumn = -1;
if (table->ReorderColumn != -1 && table->ReorderColumnDstOrder != -1) if (table->ReorderColumn != -1 && table->ReorderColumnDstOrder != -1)
{ {
@@ -744,22 +745,36 @@ void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_
table->IsSettingsDirty = true; table->IsSettingsDirty = true;
} }
// Reorder requested by user indirection needs to verify static int TableGetMaxDisplayOrderAllowed(ImGuiTable* table, int src_order, int dst_order)
// - That we don't reorder columns with the ImGuiTableColumnFlags_NoReorder flag. {
// - That we don't cross the frozen column limit. dst_order = ImClamp(dst_order, 0, table->ColumnsCount - 1);
// (that TableSetupScrollFreeze() enforce a display order range for frozen columns. if (src_order == dst_order)
// so reordering a column across the frozen column barrier is illegal and will be undone.) return dst_order;
// Cannot cross over the frozen column limit when interactively reordering.
// TableSetupScrollFreeze() enforce a display order range for frozen columns. Reordering across the frozen column barrier is illegal and will be undone.
if (table->FreezeColumnsRequest > 0)
dst_order = (src_order < table->FreezeColumnsRequest) ? ImMin(dst_order, (int)table->FreezeColumnsRequest - 1) : ImMax(dst_order, (int)table->FreezeColumnsRequest);
// Cannot cross over a column with the ImGuiTableColumnFlags_NoReorder flag.
int reorder_dir = (src_order < dst_order) ? +1 : -1;
for (int order_n = src_order; (src_order < dst_order && order_n <= dst_order) || (dst_order < src_order && order_n >= dst_order); order_n += reorder_dir)
if (table->Columns[table->DisplayOrderToIndex[order_n]].Flags & ImGuiTableColumnFlags_NoReorder)
{
dst_order = (order_n == src_order) ? src_order : order_n - reorder_dir;
break;
}
return dst_order;
}
// Reorder requested by user interaction.
void ImGui::TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order) void ImGui::TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order)
{ {
ImGuiTableColumn* src_column = &table->Columns[column_n]; const int src_order = table->Columns[column_n].DisplayOrder;
ImGuiTableColumn* dst_column = &table->Columns[table->DisplayOrderToIndex[dst_order]];
if ((src_column->Flags | dst_column->Flags) & ImGuiTableColumnFlags_NoReorder) // FIXME: Perform a sweep test?
return;
int src_i = (src_column->IndexWithinEnabledSet != -1) ? src_column->IndexWithinEnabledSet : table->Columns.index_from_ptr(src_column); // FIXME: Hidden columns don't count into the FreezeColumns count, so what to do here is ill-defined. For now we use regular index.
int dst_i = (dst_column->IndexWithinEnabledSet != -1) ? dst_column->IndexWithinEnabledSet : table->Columns.index_from_ptr(dst_column);
if ((src_i < table->FreezeColumnsRequest) != (dst_i < table->FreezeColumnsRequest))
return;
table->ReorderColumn = (ImGuiTableColumnIdx)column_n; table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)-1;
dst_order = TableGetMaxDisplayOrderAllowed(table, src_order, dst_order);
if (dst_order != src_order)
table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order; table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order;
} }
@@ -1070,7 +1085,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
// Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping. // Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping.
int visible_n = 0;
bool has_at_least_one_column_requesting_output = false; bool has_at_least_one_column_requesting_output = false;
bool offset_x_frozen = (table->FreezeColumnsCount > 0); bool offset_x_frozen = (table->FreezeColumnsCount > 0);
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
@@ -1085,7 +1099,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen // Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer); column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer);
if (offset_x_frozen && table->FreezeColumnsCount == visible_n) if (offset_x_frozen && table->FreezeColumnsCount == column_n)
{ {
offset_x += work_rect.Min.x - table->OuterRect.Min.x; offset_x += work_rect.Min.x - table->OuterRect.Min.x;
offset_x_frozen = false; offset_x_frozen = false;
@@ -1205,11 +1219,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->CannotSkipItemsQueue >>= 1; column->CannotSkipItemsQueue >>= 1;
} }
if (visible_n < table->FreezeColumnsCount) if (column_n < table->FreezeColumnsCount)
host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x); host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x);
offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
visible_n++;
} }
// In case the table is visible (e.g. decorations) but all columns clipped, we keep a column visible. // In case the table is visible (e.g. decorations) but all columns clipped, we keep a column visible.
@@ -1290,7 +1303,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns)
if (table->FreezeColumnsRequest > 0) if (table->FreezeColumnsRequest > 0)
table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; // FIXME-FROZEN
if (table->FreezeRowsRequest > 0) if (table->FreezeRowsRequest > 0)
table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight; table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight;
table_instance->LastFrozenHeight = 0.0f; table_instance->LastFrozenHeight = 0.0f;
@@ -1692,6 +1705,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
{ {
ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder); ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder);
ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]); ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]);
table->IsSettingsDirty = true;
} }
} }
} }
@@ -3129,7 +3143,7 @@ void ImGui::TableHeadersRow()
const int columns_count = TableGetColumnCount(); const int columns_count = TableGetColumnCount();
for (int column_n = 0; column_n < columns_count; column_n++) for (int column_n = 0; column_n < columns_count; column_n++)
{ {
if (!TableSetColumnIndex(column_n)) if (!TableSetColumnIndex(column_n) && table->LastHeldHeaderColumn != column_n)
continue; continue;
// Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation) // Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation)
@@ -3300,7 +3314,7 @@ void ImGui::TableAngledHeadersRow()
// Which column needs highlight? // Which column needs highlight?
const ImGuiID row_id = GetID("##AngledHeaders"); const ImGuiID row_id = GetID("##AngledHeaders");
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
int highlight_column_n = table->HighlightColumnHeader; int highlight_column_n = (table->LastHeldHeaderColumn != -1) ? table->LastHeldHeaderColumn : table->HighlightColumnHeader;
if (highlight_column_n == -1 && table->HoveredColumnBody != -1) if (highlight_column_n == -1 && table->HoveredColumnBody != -1)
if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive))) if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive)))
highlight_column_n = table->HoveredColumnBody; highlight_column_n = table->HoveredColumnBody;
@@ -3354,13 +3368,14 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); // vector from bottom-left to top-left, and from bottom-right to top-right const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); // vector from bottom-left to top-left, and from bottom-right to top-right
// Declare row, override and draw our own background // Declare row, override and draw our own background
// FIXME-TABLE: Generally broken when overlapping frozen columns limit.
TableNextRow(ImGuiTableRowFlags_Headers, row_height); TableNextRow(ImGuiTableRowFlags_Headers, row_height);
TableNextColumn(); TableNextColumn();
const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, table->RowPosY2); const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, table->RowPosY2);
table->DrawSplitter->SetCurrentChannel(draw_list, TABLE_DRAW_CHANNEL_BG0); table->DrawSplitter->SetCurrentChannel(draw_list, TABLE_DRAW_CHANNEL_BG0);
float clip_rect_min_x = table->BgClipRect.Min.x; float clip_rect_min_x = table->BgClipRect.Min.x;
if (table->FreezeColumnsCount > 0) if (table->FreezeColumnsCount > 0)
clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->FreezeColumnsCount - 1].MaxX); clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX);
TableSetBgColor(ImGuiTableBgTarget_RowBg0, 0); // Cancel TableSetBgColor(ImGuiTableBgTarget_RowBg0, 0); // Cancel
PushClipRect(table->BgClipRect.Min, table->BgClipRect.Max, false); // Span all columns PushClipRect(table->BgClipRect.Min, table->BgClipRect.Max, false); // Span all columns
draw_list->AddRectFilled(ImVec2(table->BgClipRect.Min.x, row_r.Min.y), ImVec2(table->BgClipRect.Max.x, row_r.Max.y), GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color. draw_list->AddRectFilled(ImVec2(table->BgClipRect.Min.x, row_r.Min.y), ImVec2(table->BgClipRect.Max.x, row_r.Max.y), GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color.
@@ -3496,6 +3511,36 @@ bool ImGui::TableBeginContextMenuPopup(ImGuiTable* table)
return false; return false;
} }
// FIXME: Copied from MenuItem() for the purpose of being able to pass _SelectOnRelease (#9312)
static bool MenuItemForColumnReorder(const char* label, bool selected, bool enabled)
{
using namespace ImGui;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = offsets->DeclColumns(0.0f, label_size.x, 0.0f, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
ImGuiID id = GetID(label);
ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SpanAvailWidth;
if (g.ActiveId == id)
selectable_flags |= ImGuiSelectableFlags_Highlight; // Stays highlighted while dragging.
const bool has_been_moved = (g.ActiveId == id) && g.ActiveIdHasBeenEditedBefore; // But disable toggling once moved.
BeginDisabled(!enabled); // Don't use ImGuiSelectableFlags_Disabled so that Check mark is also affected.
bool ret = Selectable(label, false, selectable_flags, ImVec2(min_w, label_size.y)) && !has_been_moved; // Can't use IsMouseDragging(0) as button is released already.
if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && selected)
RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
EndDisabled();
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
return ret;
}
// Output context menu into current window (generally a popup) // Output context menu into current window (generally a popup)
// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data? // FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data?
// Sections to display are pulled from 'flags_for_section_to_display', which is typically == table->Flags. // Sections to display are pulled from 'flags_for_section_to_display', which is typically == table->Flags.
@@ -3512,17 +3557,17 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
return; return;
bool want_separator = false; bool want_separator = false;
const int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1; const int context_column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1;
ImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL; ImGuiTableColumn* context_column = (context_column_n != -1) ? &table->Columns[context_column_n] : NULL;
// Sizing // Sizing
if (flags_for_section_to_display & ImGuiTableFlags_Resizable) if (flags_for_section_to_display & ImGuiTableFlags_Resizable)
{ {
if (column != NULL) if (context_column != NULL)
{ {
const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled; const bool can_resize = !(context_column->Flags & ImGuiTableColumnFlags_NoResize) && context_column->IsEnabled;
if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // "###SizeOne" if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // "###SizeOne"
TableSetColumnWidthAutoSingle(table, column_n); TableSetColumnWidthAutoSingle(table, context_column_n);
} }
const char* size_all_desc; const char* size_all_desc;
@@ -3571,23 +3616,47 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
Separator(); Separator();
want_separator = true; want_separator = true;
// While reordering: we calculate min/max allowed range once here so we can avoid a O(N log N) in the loop (because the query itself does a sweep scan).
// This assume that reordering constraints output a single range, otherwise would need to either call TableGetMaxDisplayOrderAllowed() for each item below, or cache this once per frame into columns.
const bool is_reordering = (g.ActiveId != 0 && g.ActiveIdWindow == g.CurrentWindow && table->ReorderColumn != -1 && g.ActiveIdHasBeenEditedBefore); // FIXME: This is a bit of a hack.
const int reorder_src_order = is_reordering ? table->Columns[table->ReorderColumn].DisplayOrder : -1;
const int reorder_min_order = is_reordering ? TableGetMaxDisplayOrderAllowed(table, reorder_src_order, 0) : 0;
const int reorder_max_order = is_reordering ? TableGetMaxDisplayOrderAllowed(table, reorder_src_order, table->ColumnsCount - 1) : table->ColumnsCount - 1;
PushItemFlag(ImGuiItemFlags_AutoClosePopups, false); PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{ {
ImGuiTableColumn* other_column = &table->Columns[other_column_n]; const int column_n = table->DisplayOrderToIndex[order_n];
if (other_column->Flags & ImGuiTableColumnFlags_Disabled) ImGuiTableColumn* column = &table->Columns[column_n];
if (column->Flags & ImGuiTableColumnFlags_Disabled)
continue; continue;
const char* name = TableGetColumnName(table, other_column_n); const char* name = TableGetColumnName(table, column_n);
if (name == NULL || name[0] == 0) if (name == NULL || name[0] == 0)
name = "<Unknown>"; name = "<Unknown>";
// Make sure we can't hide the last active column // Make sure we can't hide the last active column
bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true; bool menu_item_enabled = (column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1) if (column->IsUserEnabled && table->ColumnsEnabledCount <= 1)
menu_item_active = false; menu_item_enabled = false;
if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active)) if (is_reordering && (column->DisplayOrder < reorder_min_order || column->DisplayOrder > reorder_max_order))
other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled; menu_item_enabled = false;
if (MenuItemForColumnReorder(name, column->IsUserEnabled, menu_item_enabled))
column->IsUserEnabledNextFrame = !column->IsUserEnabled;
// Drag to reorder
// FIXME: It is currently not possible to reorder columns marked with ImGuiTableColumnFlags_NoHide.
if (IsItemActive() && IsMouseDragging(0) && g.ActiveIdSource == ImGuiInputSource_Mouse && (table->Flags & ImGuiTableFlags_Reorderable))
{
g.ActiveIdHasBeenEditedBefore = true; // Disable toggle in MenuItemForColumnReorder() + start dimming to display allowed reorder targets.
table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
if (!IsItemHovered())
{
int reorder_dir = (g.IO.MousePos.y < (g.LastItemData.Rect.Min.y + g.LastItemData.Rect.Max.y) * 0.5f) ? -1 : +1;
float reorder_amount = (reorder_dir < 0 ? g.LastItemData.Rect.Min.y - g.IO.MousePos.y : g.IO.MousePos.y - g.LastItemData.Rect.Max.y) / g.LastItemData.Rect.GetHeight();
int dst_order = column->DisplayOrder + (int)ImCeil(reorder_amount) * reorder_dir; // Estimated target order, will be validated and clamped.
TableQueueSetColumnDisplayOrder(table, column_n, dst_order);
}
}
} }
PopItemFlag(); PopItemFlag();
} }
@@ -4057,7 +4126,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX);
BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder);
BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); BulletText("ResizedColumn: %d, HeldHeaderColumn: %d, ReorderColumn: %d", table->LastResizedColumn, table->LastHeldHeaderColumn, table->ReorderColumn);
for (int n = 0; n < table->InstanceCurrent + 1; n++) for (int n = 0; n < table->InstanceCurrent + 1; n++)
{ {
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n); ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n);