From 6655ab2e43ff237edfde5fa56355e8fe07e49c7b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Feb 2024 13:48:09 +0100 Subject: [PATCH] Tables: Angled Headers: fixed TableAngledHeadersRow() incorrect background fill drawn too low. Fixed row geometry with non-small values of CellPadding. (#6917) --- docs/CHANGELOG.txt | 5 ++++- imgui_internal.h | 4 ++-- imgui_tables.cpp | 31 ++++++++++++++++++++++--------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0fa8e6d71..d15033ca9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Tables: Angled headers: fixed TableAngledHeadersRow() incorrect background fill + drawn too low, particularly visible with tables that have no scrolling. (#6917) + ----------------------------------------------------------------------- VERSION 1.90.3 (Released 2024-02-14) @@ -355,7 +358,7 @@ Other changes: with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually. - Tables: - Added angled headers support. You need to set ImGuiTableColumnFlags_AngledHeader on selected - columns and call TableAngledHeadersRow(). Added style.TableAngledHeadersAngle style option. + columns and call TableAngledHeadersRow(). Added style.TableAngledHeadersAngle style option. (#6917) - Added ImGuiTableFlags_HighlightHoveredColumn flag, currently highlighting column header. - Fixed an edge-case when no columns are visible + table scrollbar is visible + user code is always testing return value of TableSetColumnIndex() to coarse clip. With an active diff --git a/imgui_internal.h b/imgui_internal.h index 574e22159..906887c93 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2916,7 +2916,7 @@ struct IMGUI_API ImGuiTableTempData { int TableIndex; // Index in g.Tables.Buf[] pool float LastTimeActive; // Last timestamp this structure was used - float AngledheadersExtraWidth; // Used in EndTable() + float AngledHeadersExtraWidth; // Used in EndTable() ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() ImDrawListSplitter DrawSplitter; @@ -3300,7 +3300,7 @@ namespace ImGui IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); IMGUI_API void TablePushBackgroundChannel(); IMGUI_API void TablePopBackgroundChannel(); - IMGUI_API void TableAngledHeadersRowEx(float angle, float label_width = 0.0f); + IMGUI_API void TableAngledHeadersRowEx(float angle, float max_label_width = 0.0f); // Tables: Internals inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b81e9695d..6bce0adb3 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -498,7 +498,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->DeclColumnsCount = table->AngledHeadersCount = 0; if (previous_frame_active + 1 < g.FrameCount) table->IsActiveIdInTable = false; - temp_data->AngledheadersExtraWidth = 0.0f; + temp_data->AngledHeadersExtraWidth = 0.0f; // Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders() table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); @@ -1344,7 +1344,7 @@ void ImGui::EndTable() max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border); if (table->ResizedColumn != -1) max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2); - table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledheadersExtraWidth; + table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth; } // Pop clipping rect @@ -1462,7 +1462,7 @@ void ImGui::EndTable() } else if (temp_data->UserOuterSize.x <= 0.0f) { - const float decoration_size = table->TempData->AngledheadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f); + const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f); outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); } @@ -1567,6 +1567,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo } // Store name (append with zero-terminator in contiguous buffer) + // FIXME: If we recorded the number of \n in names we could compute header row height column->NameOffset = -1; if (label != NULL && label[0] != 0) { @@ -2154,6 +2155,8 @@ void ImGui::TableEndCell(ImGuiTable* table) // - TableSetColumnWidthAutoAll() [Internal] // - TableUpdateColumnsWeightFromWidth() [Internal] //------------------------------------------------------------------------- +// Note that actual columns widths are computed in TableUpdateLayout(). +//------------------------------------------------------------------------- // Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) @@ -2927,6 +2930,7 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table) // [SECTION] Tables: Headers //------------------------------------------------------------------------- // - TableGetHeaderRowHeight() [Internal] +// - TableGetHeaderAngledMaxLabelWidth() [Internal] // - TableHeadersRow() // - TableHeader() // - TableAngledHeadersRow() @@ -3180,25 +3184,25 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width) // Calculate our base metrics and set angled headers data _before_ the first call to TableNextRow() // FIXME-STYLE: Would it be better for user to submit 'max_label_width' or 'row_height' ? One can be derived from the other. - const float header_height = table->RowCellPaddingY * 2.0f + g.FontSize; + const float header_height = g.FontSize + g.Style.CellPadding.x * 2.0f; const float row_height = ImFabs(ImRotate(ImVec2(max_label_width, flip_label ? +header_height : -header_height), cos_a, sin_a).y); - const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); table->AngledHeadersHeight = row_height; table->AngledHeadersSlope = (sin_a != 0.0f) ? (cos_a / sin_a) : 0.0f; + 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 TableNextRow(ImGuiTableRowFlags_Headers, row_height); TableNextColumn(); + 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); float clip_rect_min_x = table->BgClipRect.Min.x; if (table->FreezeColumnsCount > 0) clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->FreezeColumnsCount - 1].MaxX); TableSetBgColor(ImGuiTableBgTarget_RowBg0, 0); // Cancel PushClipRect(table->BgClipRect.Min, table->BgClipRect.Max, false); // Span all columns - draw_list->AddRectFilled(table->BgClipRect.Min, table->BgClipRect.Max, 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. PushClipRect(ImVec2(clip_rect_min_x, table->BgClipRect.Min.y), table->BgClipRect.Max, true); // Span all columns - const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, window->DC.CursorPos.y + row_height); const ImGuiID row_id = GetID("##AngledHeaders"); ButtonBehavior(row_r, row_id, NULL, NULL); KeepAliveID(row_id); @@ -3209,6 +3213,7 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width) if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive))) highlight_column_n = table->HoveredColumnBody; + // Draw background and labels in first pass, then all borders. float max_x = 0.0f; for (int pass = 0; pass < 2; pass++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++) @@ -3243,13 +3248,21 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width) ImVec2 label_off = ImVec2(flip_label ? ImMax(0.0f, max_label_width - label_size.x - table->CellPaddingX) : table->CellPaddingX, table->RowCellPaddingY); int vtx_idx_begin = draw_list->_VtxCurrentIdx; RenderTextEllipsis(draw_list, label_r.Min + label_off, label_r.Max, label_r.Max.x, label_r.Max.x, label_name, NULL, &label_size); - //if (g.IO.KeyShift) { draw_list->AddRect(label_r.Min, label_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 2.0f); } int vtx_idx_end = draw_list->_VtxCurrentIdx; // Rotate and offset label ImVec2 pivot_in = label_r.GetBL(); ImVec2 pivot_out = ImVec2(column->WorkMinX, row_r.Max.y) + (flip_label ? (unit_right * clip_width) : ImVec2(header_height, 0.0f)); ShadeVertsTransformPos(draw_list, vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out); // Rotate and offset + + // Debug draw + /*if (g.IO.KeyShift) + { + vtx_idx_begin = GetForegroundDrawList()->_VtxCurrentIdx; + GetForegroundDrawList()->AddRect(label_r.Min, label_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 2.0f); + vtx_idx_end = GetForegroundDrawList()->_VtxCurrentIdx; + ShadeVertsTransformPos(GetForegroundDrawList(), vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out); // Rotate and offset + }*/ } if (pass == 1) { @@ -3259,7 +3272,7 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width) } PopClipRect(); PopClipRect(); - table->TempData->AngledheadersExtraWidth = ImMax(0.0f, max_x - table->Columns[table->RightMostEnabledColumn].MaxX); + table->TempData->AngledHeadersExtraWidth = ImMax(0.0f, max_x - table->Columns[table->RightMostEnabledColumn].MaxX); } //-------------------------------------------------------------------------