mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-11-04 01:34:32 +00:00 
			
		
		
		
	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. (#3955, #3565)
This commit is contained in:
		@@ -55,6 +55,8 @@ Other Changes:
 | 
			
		||||
  clipper instance. High-level languages (Lua,Rust etc.) would typically be affected. (#4822)
 | 
			
		||||
- IsItemHovered(): added ImGuiHoveredFlags_NoNavOverride to disable the behavior where the
 | 
			
		||||
  return value is overriden by focus when gamepad/keyboard navigation is active.
 | 
			
		||||
- 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. (#3955).
 | 
			
		||||
- Inputs: Fixed IsMouseClicked() repeat mode rate being half of keyboard repeat rate.
 | 
			
		||||
- ColorEdit: Fixed text baseline alignment after a SameLine() after a ColorEdit() with visible label.
 | 
			
		||||
- Stack Tool: Added option to copy item path to clipboard. (#4631)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								imgui.cpp
									
									
									
									
									
								
							@@ -12173,19 +12173,20 @@ void ImGui::ShowMetricsWindow(bool* p_open)
 | 
			
		||||
    {
 | 
			
		||||
        static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
 | 
			
		||||
        {
 | 
			
		||||
            ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance
 | 
			
		||||
            if (rect_type == TRT_OuterRect)                     { return table->OuterRect; }
 | 
			
		||||
            else if (rect_type == TRT_InnerRect)                { return table->InnerRect; }
 | 
			
		||||
            else if (rect_type == TRT_WorkRect)                 { return table->WorkRect; }
 | 
			
		||||
            else if (rect_type == TRT_HostClipRect)             { return table->HostClipRect; }
 | 
			
		||||
            else if (rect_type == TRT_InnerClipRect)            { return table->InnerClipRect; }
 | 
			
		||||
            else if (rect_type == TRT_BackgroundClipRect)       { return table->BgClipRect; }
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            else if (rect_type == TRT_ColumnsClipRect)          { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
 | 
			
		||||
            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
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            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
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            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); }
 | 
			
		||||
            IM_ASSERT(0);
 | 
			
		||||
            return ImRect();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,7 @@ struct ImGuiTabBar;                 // Storage for a tab bar
 | 
			
		||||
struct ImGuiTabItem;                // Storage for a tab item (within a tab bar)
 | 
			
		||||
struct ImGuiTable;                  // Storage for a table
 | 
			
		||||
struct ImGuiTableColumn;            // Storage for one column of a table
 | 
			
		||||
struct ImGuiTableInstanceData;      // Storage for one instance of a same table
 | 
			
		||||
struct ImGuiTableTempData;          // Temporary storage for one table (one per table in the stack), shared between tables.
 | 
			
		||||
struct ImGuiTableSettings;          // Storage for a table .ini settings
 | 
			
		||||
struct ImGuiTableColumnsSettings;   // Storage for a column .ini settings
 | 
			
		||||
@@ -2290,6 +2291,15 @@ struct ImGuiTableCellData
 | 
			
		||||
    ImGuiTableColumnIdx         Column;     // Column number
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 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 ?)
 | 
			
		||||
struct ImGuiTableInstanceData
 | 
			
		||||
{
 | 
			
		||||
    float                       LastOuterHeight;            // Outer height from last frame // FIXME: multi-instance issue (#3955)
 | 
			
		||||
    float                       LastFirstRowHeight;         // Height of first row from last frame // FIXME: possible multi-instance issue?
 | 
			
		||||
 | 
			
		||||
    ImGuiTableInstanceData()    { LastOuterHeight = LastFirstRowHeight = 0.0f; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
 | 
			
		||||
struct IMGUI_API ImGuiTable
 | 
			
		||||
{
 | 
			
		||||
@@ -2332,8 +2342,6 @@ struct IMGUI_API ImGuiTable
 | 
			
		||||
    float                       CellPaddingY;
 | 
			
		||||
    float                       CellSpacingX1;              // Spacing between non-bordered cells
 | 
			
		||||
    float                       CellSpacingX2;
 | 
			
		||||
    float                       LastOuterHeight;            // Outer height from last frame
 | 
			
		||||
    float                       LastFirstRowHeight;         // Height of first row from last frame
 | 
			
		||||
    float                       InnerWidth;                 // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
 | 
			
		||||
    float                       ColumnsGivenWidth;          // Sum of current column width
 | 
			
		||||
    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
 | 
			
		||||
    ImGuiWindow*                InnerWindow;                // Window holding the table data (== OuterWindow or a child window)
 | 
			
		||||
    ImGuiTextBuffer             ColumnsNames;               // Contiguous buffer holding columns names
 | 
			
		||||
    ImDrawListSplitter*         DrawSplitter;               // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly
 | 
			
		||||
    ImGuiTableInstanceData      InstanceDataFirst;
 | 
			
		||||
    ImVector<ImGuiTableInstanceData>    InstanceDataExtra;  // FIXME-OPT: Using a small-vector pattern would be good.
 | 
			
		||||
    ImGuiTableColumnSortSpecs   SortSpecsSingle;
 | 
			
		||||
    ImVector<ImGuiTableColumnSortSpecs> SortSpecsMulti;     // FIXME-OPT: Using a small-vector pattern would be good.
 | 
			
		||||
    ImGuiTableSortSpecs         SortSpecs;                  // Public facing sorts specs, this is what we return in TableGetSortSpecs()
 | 
			
		||||
@@ -2708,6 +2718,7 @@ namespace ImGui
 | 
			
		||||
    IMGUI_API void          TableDrawBorders(ImGuiTable* table);
 | 
			
		||||
    IMGUI_API void          TableDrawContextMenu(ImGuiTable* table);
 | 
			
		||||
    IMGUI_API void          TableMergeDrawChannels(ImGuiTable* table);
 | 
			
		||||
    inline ImGuiTableInstanceData*   TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
 | 
			
		||||
    IMGUI_API void          TableSortSpecsSanitize(ImGuiTable* table);
 | 
			
		||||
    IMGUI_API void          TableSortSpecsBuild(ImGuiTable* table);
 | 
			
		||||
    IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
 | 
			
		||||
 
 | 
			
		||||
@@ -361,6 +361,8 @@ bool    ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
 | 
			
		||||
    table->IsLayoutLocked = false;
 | 
			
		||||
    table->InnerWidth = inner_width;
 | 
			
		||||
    temp_data->UserOuterSize = outer_size;
 | 
			
		||||
    if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no)
 | 
			
		||||
        table->InstanceDataExtra.push_back(ImGuiTableInstanceData());
 | 
			
		||||
 | 
			
		||||
    // When not using a child window, WorkRect.Max will grow as we append contents.
 | 
			
		||||
    if (use_child_window)
 | 
			
		||||
@@ -933,9 +935,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
 | 
			
		||||
            width_remaining_for_stretched_columns -= 1.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
 | 
			
		||||
    table->HoveredColumnBody = -1;
 | 
			
		||||
    table->HoveredColumnBorder = -1;
 | 
			
		||||
    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));
 | 
			
		||||
    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));
 | 
			
		||||
    const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
 | 
			
		||||
 | 
			
		||||
    // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
 | 
			
		||||
@@ -1096,7 +1099,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
 | 
			
		||||
    // [Part 10] Hit testing on borders
 | 
			
		||||
    if (table->Flags & ImGuiTableFlags_Resizable)
 | 
			
		||||
        TableUpdateBorders(table);
 | 
			
		||||
    table->LastFirstRowHeight = 0.0f;
 | 
			
		||||
    table_instance->LastFirstRowHeight = 0.0f;
 | 
			
		||||
    table->IsLayoutLocked = true;
 | 
			
		||||
    table->IsUsingHeaders = false;
 | 
			
		||||
 | 
			
		||||
@@ -1141,10 +1144,11 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
 | 
			
		||||
    // use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not
 | 
			
		||||
    // really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height).
 | 
			
		||||
    // Actual columns highlight/render will be performed in EndTable() and not be affected.
 | 
			
		||||
    ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
 | 
			
		||||
    const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
 | 
			
		||||
    const float hit_y1 = table->OuterRect.Min.y;
 | 
			
		||||
    const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table->LastOuterHeight);
 | 
			
		||||
    const float hit_y2_head = hit_y1 + table->LastFirstRowHeight;
 | 
			
		||||
    const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);
 | 
			
		||||
    const float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight;
 | 
			
		||||
 | 
			
		||||
    for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1223,6 +1227,7 @@ void    ImGui::EndTable()
 | 
			
		||||
            TableOpenContextMenu((int)table->HoveredColumnBody);
 | 
			
		||||
 | 
			
		||||
    // Finalize table height
 | 
			
		||||
    ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
 | 
			
		||||
    inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
 | 
			
		||||
    inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
 | 
			
		||||
    inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
 | 
			
		||||
@@ -1233,7 +1238,7 @@ void    ImGui::EndTable()
 | 
			
		||||
    else if (!(flags & ImGuiTableFlags_NoHostExtendY))
 | 
			
		||||
        table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height
 | 
			
		||||
    table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
 | 
			
		||||
    table->LastOuterHeight = table->OuterRect.GetHeight();
 | 
			
		||||
    table_instance->LastOuterHeight = table->OuterRect.GetHeight();
 | 
			
		||||
 | 
			
		||||
    // Setup inner scrolling range
 | 
			
		||||
    // 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)
 | 
			
		||||
    const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
 | 
			
		||||
    const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
 | 
			
		||||
    if (table->CurrentRow == 0)
 | 
			
		||||
        table->LastFirstRowHeight = bg_y2 - bg_y1;
 | 
			
		||||
        TableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1;
 | 
			
		||||
 | 
			
		||||
    const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);
 | 
			
		||||
    if (is_visible)
 | 
			
		||||
@@ -2502,10 +2507,11 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
 | 
			
		||||
    inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
 | 
			
		||||
 | 
			
		||||
    // Draw inner border and resizing feedback
 | 
			
		||||
    ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
 | 
			
		||||
    const float border_size = TABLE_BORDER_SIZE;
 | 
			
		||||
    const float draw_y1 = table->InnerRect.Min.y;
 | 
			
		||||
    const float draw_y2_body = table->InnerRect.Max.y;
 | 
			
		||||
    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;
 | 
			
		||||
    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;
 | 
			
		||||
    if (table->Flags & ImGuiTableFlags_BordersInnerV)
 | 
			
		||||
    {
 | 
			
		||||
        for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
 | 
			
		||||
@@ -3536,6 +3542,8 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
 | 
			
		||||
        GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
 | 
			
		||||
    if (!open)
 | 
			
		||||
        return;
 | 
			
		||||
    if (table->InstanceCurrent > 0)
 | 
			
		||||
        ImGui::Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1);
 | 
			
		||||
    bool clear_settings = SmallButton("Clear settings");
 | 
			
		||||
    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));
 | 
			
		||||
    BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
 | 
			
		||||
 
 | 
			
		||||
@@ -3533,6 +3533,9 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f
 | 
			
		||||
// - InputText()
 | 
			
		||||
// - InputTextWithHint()
 | 
			
		||||
// - InputTextMultiline()
 | 
			
		||||
// - InputTextGetCharInfo() [Internal]
 | 
			
		||||
// - InputTextReindexLines() [Internal]
 | 
			
		||||
// - InputTextReindexLinesRange() [Internal]
 | 
			
		||||
// - InputTextEx() [Internal]
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user