Skip to content

Commit 9f851eb

Browse files
committed
Tables: added ImGuiTableFlags_HighlightHoveredColumn.
1 parent be1311c commit 9f851eb

File tree

5 files changed

+52
-24
lines changed

5 files changed

+52
-24
lines changed

docs/CHANGELOG.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Other changes:
9494
- Drag and Drop: Fixed submitting a tooltip from drop target location when using AcceptDragDropPayload()
9595
with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually.
9696
- TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438)
97+
- Tables: Added ImGuiTableFlags_HighlightHoveredColumn flag, currently highlighting column header.
9798
- Tables: Fixed an edge-case when no columns are visible + table scrollbar is visible + user
9899
code is always testing return value of TableSetColumnIndex() to coarse clip. With an active
99100
clipper it would have asserted. Without a clipper, the scrollbar range would be wrong.

imgui.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,8 @@ enum ImGuiTableFlags_
12161216
// Sorting
12171217
ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
12181218
ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
1219+
// Miscellaneous
1220+
ImGuiTableFlags_HighlightHoveredColumn = 1 << 28, // Highlight column headers when hovered (may evolve into a fuller highlight)
12191221

12201222
// [Internal] Combinations and masks
12211223
ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame,

imgui_demo.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3973,10 +3973,10 @@ static void ShowDemoWindowTables()
39733973
ImGui::PushID("Tables");
39743974

39753975
int open_action = -1;
3976-
if (ImGui::Button("Open all"))
3976+
if (ImGui::Button("Expand all"))
39773977
open_action = 1;
39783978
ImGui::SameLine();
3979-
if (ImGui::Button("Close all"))
3979+
if (ImGui::Button("Collapse all"))
39803980
open_action = 0;
39813981
ImGui::SameLine();
39823982

@@ -4262,6 +4262,7 @@ static void ShowDemoWindowTables()
42624262
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
42634263
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
42644264
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
4265+
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
42654266
PopStyleCompact();
42664267

42674268
if (ImGui::BeginTable("table1", 3, flags))
@@ -5299,6 +5300,7 @@ static void ShowDemoWindowTables()
52995300
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
53005301
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
53015302
ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
5303+
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
53025304
for (int n = 0; n < 3; n++)
53035305
{
53045306
char buf[32];
@@ -5519,9 +5521,15 @@ static void ShowDemoWindowTables()
55195521
ImGui::TreePop();
55205522
}
55215523

5522-
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
5524+
if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
55235525
{
55245526
ImGui::Checkbox("show_headers", &show_headers);
5527+
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5528+
ImGui::TreePop();
5529+
}
5530+
5531+
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
5532+
{
55255533
ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
55265534

55275535
ImGui::DragFloat2("##OuterSize", &outer_size_value.x);

imgui_internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,7 @@ struct ImGuiTableCellData
26692669
};
26702670

26712671
// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?)
2672+
// sizeof() ~ 24 bytes
26722673
struct ImGuiTableInstanceData
26732674
{
26742675
ImGuiID TableInstanceID;
@@ -2754,6 +2755,7 @@ struct IMGUI_API ImGuiTable
27542755
ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn()
27552756
ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column!
27562757
ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing).
2758+
ImGuiTableColumnIdx HighlightColumnHeader; // Index of column which should be highlighted.
27572759
ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit.
27582760
ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0.
27592761
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
@@ -2786,6 +2788,8 @@ struct IMGUI_API ImGuiTable
27862788
bool IsResetDisplayOrderRequest;
27872789
bool IsUnfrozenRows; // Set when we got past the frozen row.
27882790
bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable()
2791+
bool IsActiveIdAliveBeforeTable;
2792+
bool IsActiveIdInTable;
27892793
bool HasScrollbarYCurr; // Whether ANY instance of this table had a vertical scrollbar during the current frame.
27902794
bool HasScrollbarYPrev; // Whether ANY instance of this table had a vertical scrollbar during the previous.
27912795
bool MemoryCompacted;

imgui_tables.cpp

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
346346
flags = TableFixFlags(flags, outer_window);
347347

348348
// Initialize
349-
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
349+
const int previous_frame_active = table->LastFrameActive;
350+
const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
350351
table->ID = id;
351352
table->Flags = flags;
352353
table->LastFrameActive = g.FrameCount;
@@ -478,6 +479,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
478479
table->FreezeColumnsRequest = table->FreezeColumnsCount = 0;
479480
table->IsUnfrozenRows = true;
480481
table->DeclColumnsCount = 0;
482+
if (previous_frame_active + 1 < g.FrameCount)
483+
table->IsActiveIdInTable = false;
481484

482485
// Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders()
483486
table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong);
@@ -974,8 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
974977
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
975978
table_instance->HoveredRowLast = table_instance->HoveredRowNext;
976979
table_instance->HoveredRowNext = -1;
977-
table->HoveredColumnBody = -1;
978-
table->HoveredColumnBorder = -1;
980+
table->HoveredColumnBody = table->HoveredColumnBorder = -1;
979981
const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight));
980982
const ImGuiID backup_active_id = g.ActiveId;
981983
g.ActiveId = 0;
@@ -1122,13 +1124,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
11221124
// because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu.
11231125
const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x);
11241126
if (is_hovering_table && table->HoveredColumnBody == -1)
1125-
{
11261127
if (g.IO.MousePos.x >= unused_x1)
11271128
table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;
1128-
}
11291129
if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable))
11301130
table->Flags &= ~ImGuiTableFlags_Resizable;
11311131

1132+
table->IsActiveIdAliveBeforeTable = (g.ActiveIdIsAlive != 0);
1133+
11321134
// [Part 8] Lock actual OuterRect/WorkRect right-most position.
11331135
// This is done late to handle the case of fixed-columns tables not claiming more widths that they need.
11341136
// Because of this we are careful with uses of WorkRect and InnerClipRect before this point.
@@ -1161,6 +1163,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
11611163
table->IsLayoutLocked = true;
11621164
table->IsUsingHeaders = false;
11631165

1166+
// Highlight header
1167+
table->HighlightColumnHeader = -1;
1168+
if (table->IsContextPopupOpen && table->ContextPopupColumn != -1 && table->InstanceInteracted == table->InstanceCurrent)
1169+
table->HighlightColumnHeader = table->ContextPopupColumn;
1170+
else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != table->ColumnsCount && table->HoveredColumnBorder == -1)
1171+
if (g.ActiveId == 0 || (table->IsActiveIdInTable || g.DragDropActive))
1172+
table->HighlightColumnHeader = table->HoveredColumnBody;
1173+
11641174
// [Part 11] Context menu
11651175
if (TableBeginContextMenuPopup(table))
11661176
{
@@ -1382,6 +1392,8 @@ void ImGui::EndTable()
13821392
table->ResizedColumnNextWidth = new_width;
13831393
}
13841394

1395+
table->IsActiveIdInTable = (g.ActiveIdIsAlive != 0 && table->IsActiveIdAliveBeforeTable == false);
1396+
13851397
// Pop from id stack
13861398
IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!");
13871399
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
@@ -2301,6 +2313,7 @@ void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
23012313
// - TablePopBackgroundChannel() [Internal]
23022314
// - TableSetupDrawChannels() [Internal]
23032315
// - TableMergeDrawChannels() [Internal]
2316+
// - TableGetColumnBorderCol() [Internal]
23042317
// - TableDrawBorders() [Internal]
23052318
//-------------------------------------------------------------------------
23062319

@@ -2584,6 +2597,18 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
25842597
}
25852598
}
25862599

2600+
static ImU32 TableGetColumnBorderCol(ImGuiTable* table, int order_n, int column_n)
2601+
{
2602+
const bool is_hovered = (table->HoveredColumnBorder == column_n);
2603+
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);
2604+
const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1);
2605+
if (is_resized || is_hovered)
2606+
return ImGui::GetColorU32(is_resized ? ImGuiCol_SeparatorActive : ImGuiCol_SeparatorHovered);
2607+
if (is_frozen_separator || (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)))
2608+
return table->BorderColorStrong;
2609+
return table->BorderColorLight;
2610+
}
2611+
25872612
// FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow)
25882613
void ImGui::TableDrawBorders(ImGuiTable* table)
25892614
{
@@ -2626,21 +2651,9 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
26262651

26272652
// Draw in outer window so right-most column won't be clipped
26282653
// Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling.
2629-
ImU32 col;
2630-
float draw_y2;
2631-
if (is_hovered || is_resized || is_frozen_separator)
2632-
{
2633-
draw_y2 = draw_y2_body;
2634-
col = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong;
2635-
}
2636-
else
2637-
{
2638-
draw_y2 = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? draw_y2_head : draw_y2_body;
2639-
col = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? table->BorderColorStrong : table->BorderColorLight;
2640-
}
2641-
2654+
float draw_y2 = (is_hovered || is_resized || is_frozen_separator || (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) == 0) ? draw_y2_body : draw_y2_head;
26422655
if (draw_y2 > draw_y1)
2643-
inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), col, border_size);
2656+
inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), TableGetColumnBorderCol(table, order_n, column_n), border_size);
26442657
}
26452658
}
26462659

@@ -2994,7 +3007,6 @@ void ImGui::TableHeader(const char* label)
29943007
column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x);
29953008

29963009
// Keep header highlighted when context menu is open.
2997-
const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent);
29983010
ImGuiID id = window->GetID(label);
29993011
ImRect bb(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0f));
30003012
ItemSize(ImVec2(0.0f, label_height)); // Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal
@@ -3005,9 +3017,10 @@ void ImGui::TableHeader(const char* label)
30053017
//GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG]
30063018

30073019
// Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items.
3020+
const bool highlight = (table->HighlightColumnHeader == column_n);
30083021
bool hovered, held;
30093022
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap);
3010-
if (held || hovered || selected)
3023+
if (held || hovered || highlight)
30113024
{
30123025
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
30133026
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);

0 commit comments

Comments
 (0)