Skip to content

Commit 2b6edde

Browse files
ocornutsergeyn
authored andcommitted
Tables: Fixed incorrect border height used for logic when resizing one of several synchronized instance of a same table ID, when instances have a different height. (ocornut#3955, ocornut#3565)
1 parent ab0a893 commit 2b6edde

File tree

5 files changed

+39
-14
lines changed

5 files changed

+39
-14
lines changed

docs/CHANGELOG.txt

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ Other Changes:
5555
clipper instance. High-level languages (Lua,Rust etc.) would typically be affected. (#4822)
5656
- IsItemHovered(): added ImGuiHoveredFlags_NoNavOverride to disable the behavior where the
5757
return value is overriden by focus when gamepad/keyboard navigation is active.
58+
- Tables: Fixed incorrect border height used for logic when resizing one of several synchronized
59+
instance of a same table ID, when instances have a different height. (#3955).
5860
- Inputs: Fixed IsMouseClicked() repeat mode rate being half of keyboard repeat rate.
5961
- ColorEdit: Fixed text baseline alignment after a SameLine() after a ColorEdit() with visible label.
6062
- Stack Tool: Added option to copy item path to clipboard. (#4631)

imgui.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -12173,19 +12173,20 @@ void ImGui::ShowMetricsWindow(bool* p_open)
1217312173
{
1217412174
static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
1217512175
{
12176+
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance
1217612177
if (rect_type == TRT_OuterRect) { return table->OuterRect; }
1217712178
else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
1217812179
else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
1217912180
else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
1218012181
else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
1218112182
else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }
12182-
else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table->LastOuterHeight); }
12183+
else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); }
1218312184
else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
1218412185
else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
12185-
else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } // Note: y1/y2 not always accurate
12186-
else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
12187-
else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
12188-
else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
12186+
else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate
12187+
else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }
12188+
else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }
12189+
else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
1218912190
IM_ASSERT(0);
1219012191
return ImRect();
1219112192
}

imgui_internal.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ struct ImGuiTabBar; // Storage for a tab bar
136136
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
137137
struct ImGuiTable; // Storage for a table
138138
struct ImGuiTableColumn; // Storage for one column of a table
139+
struct ImGuiTableInstanceData; // Storage for one instance of a same table
139140
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
140141
struct ImGuiTableSettings; // Storage for a table .ini settings
141142
struct ImGuiTableColumnsSettings; // Storage for a column .ini settings
@@ -2290,6 +2291,15 @@ struct ImGuiTableCellData
22902291
ImGuiTableColumnIdx Column; // Column number
22912292
};
22922293

2294+
// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs, does that needs they could be moved to ImGuiTableTempData ?)
2295+
struct ImGuiTableInstanceData
2296+
{
2297+
float LastOuterHeight; // Outer height from last frame // FIXME: multi-instance issue (#3955)
2298+
float LastFirstRowHeight; // Height of first row from last frame // FIXME: possible multi-instance issue?
2299+
2300+
ImGuiTableInstanceData() { LastOuterHeight = LastFirstRowHeight = 0.0f; }
2301+
};
2302+
22932303
// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
22942304
struct IMGUI_API ImGuiTable
22952305
{
@@ -2332,8 +2342,6 @@ struct IMGUI_API ImGuiTable
23322342
float CellPaddingY;
23332343
float CellSpacingX1; // Spacing between non-bordered cells
23342344
float CellSpacingX2;
2335-
float LastOuterHeight; // Outer height from last frame
2336-
float LastFirstRowHeight; // Height of first row from last frame
23372345
float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
23382346
float ColumnsGivenWidth; // Sum of current column width
23392347
float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window
@@ -2353,6 +2361,8 @@ struct IMGUI_API ImGuiTable
23532361
ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window)
23542362
ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names
23552363
ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly
2364+
ImGuiTableInstanceData InstanceDataFirst;
2365+
ImVector<ImGuiTableInstanceData> InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good.
23562366
ImGuiTableColumnSortSpecs SortSpecsSingle;
23572367
ImVector<ImGuiTableColumnSortSpecs> SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good.
23582368
ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs()
@@ -2708,6 +2718,7 @@ namespace ImGui
27082718
IMGUI_API void TableDrawBorders(ImGuiTable* table);
27092719
IMGUI_API void TableDrawContextMenu(ImGuiTable* table);
27102720
IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
2721+
inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
27112722
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
27122723
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
27132724
IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);

imgui_tables.cpp

+15-7
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
361361
table->IsLayoutLocked = false;
362362
table->InnerWidth = inner_width;
363363
temp_data->UserOuterSize = outer_size;
364+
if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no)
365+
table->InstanceDataExtra.push_back(ImGuiTableInstanceData());
364366

365367
// When not using a child window, WorkRect.Max will grow as we append contents.
366368
if (use_child_window)
@@ -933,9 +935,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
933935
width_remaining_for_stretched_columns -= 1.0f;
934936
}
935937

938+
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
936939
table->HoveredColumnBody = -1;
937940
table->HoveredColumnBorder = -1;
938-
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->LastOuterHeight));
941+
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));
939942
const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
940943

941944
// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
@@ -1096,7 +1099,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
10961099
// [Part 10] Hit testing on borders
10971100
if (table->Flags & ImGuiTableFlags_Resizable)
10981101
TableUpdateBorders(table);
1099-
table->LastFirstRowHeight = 0.0f;
1102+
table_instance->LastFirstRowHeight = 0.0f;
11001103
table->IsLayoutLocked = true;
11011104
table->IsUsingHeaders = false;
11021105

@@ -1141,10 +1144,11 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
11411144
// use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not
11421145
// really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height).
11431146
// Actual columns highlight/render will be performed in EndTable() and not be affected.
1147+
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
11441148
const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
11451149
const float hit_y1 = table->OuterRect.Min.y;
1146-
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table->LastOuterHeight);
1147-
const float hit_y2_head = hit_y1 + table->LastFirstRowHeight;
1150+
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);
1151+
const float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight;
11481152

11491153
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
11501154
{
@@ -1223,6 +1227,7 @@ void ImGui::EndTable()
12231227
TableOpenContextMenu((int)table->HoveredColumnBody);
12241228

12251229
// Finalize table height
1230+
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
12261231
inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
12271232
inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
12281233
inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
@@ -1233,7 +1238,7 @@ void ImGui::EndTable()
12331238
else if (!(flags & ImGuiTableFlags_NoHostExtendY))
12341239
table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height
12351240
table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
1236-
table->LastOuterHeight = table->OuterRect.GetHeight();
1241+
table_instance->LastOuterHeight = table->OuterRect.GetHeight();
12371242

12381243
// Setup inner scrolling range
12391244
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
@@ -1749,7 +1754,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
17491754
const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
17501755
const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
17511756
if (table->CurrentRow == 0)
1752-
table->LastFirstRowHeight = bg_y2 - bg_y1;
1757+
TableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1;
17531758

17541759
const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);
17551760
if (is_visible)
@@ -2502,10 +2507,11 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
25022507
inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
25032508

25042509
// Draw inner border and resizing feedback
2510+
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
25052511
const float border_size = TABLE_BORDER_SIZE;
25062512
const float draw_y1 = table->InnerRect.Min.y;
25072513
const float draw_y2_body = table->InnerRect.Max.y;
2508-
const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table->LastFirstRowHeight) : draw_y1;
2514+
const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1;
25092515
if (table->Flags & ImGuiTableFlags_BordersInnerV)
25102516
{
25112517
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
@@ -3536,6 +3542,8 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
35363542
GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
35373543
if (!open)
35383544
return;
3545+
if (table->InstanceCurrent > 0)
3546+
ImGui::Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1);
35393547
bool clear_settings = SmallButton("Clear settings");
35403548
BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));
35413549
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");

imgui_widgets.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3533,6 +3533,9 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f
35333533
// - InputText()
35343534
// - InputTextWithHint()
35353535
// - InputTextMultiline()
3536+
// - InputTextGetCharInfo() [Internal]
3537+
// - InputTextReindexLines() [Internal]
3538+
// - InputTextReindexLinesRange() [Internal]
35363539
// - InputTextEx() [Internal]
35373540
//-------------------------------------------------------------------------
35383541

0 commit comments

Comments
 (0)