From 64b1e448d20c9be9275af731c34b4c7bf14a8e95 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 Sep 2023 15:22:10 +0200 Subject: [PATCH] TabBar, Style: added style.TabBarBorderSize and associated ImGuiStyleVar_TabBarBorderSize. (#6820, #4859, #5022, #5239) Removed ImGuiTabItemFlags_Preview. Will need cherry-picking in master. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 ++++++++---- imgui.h | 2 ++ imgui_demo.cpp | 1 + imgui_internal.h | 5 +++-- imgui_widgets.cpp | 24 ++++++++++-------------- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 611e1ff50..d7b1e2757 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -129,6 +129,8 @@ Other changes: - Windows: Layout of Close/Collapse buttons uses style.ItemInnerSpacing.x between items, stopped incorrectly using FramePadding in a way where hit-boxes could overlap when setting large values. (#6749) +- TabBar, Style: added style.TabBarBorderSize and associated ImGuiStyleVar_TabBarBorderSize. + Tweaked rendering of that separator to allow thicker values. (#6820, #4859, #5022, #5239) - InputFloat, SliderFloat, DragFloat: always turn both '.' and ',' into the current decimal point character when using Decimal/Scientific character filter. (#6719, #2278) [@adamsepp] - ColorEdit, ColorPicker: Manipulating options popup don't mark item as edited. (#6722) diff --git a/imgui.cpp b/imgui.cpp index d27348553..c2419f90e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1208,6 +1208,7 @@ ImGuiStyle::ImGuiStyle() TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. @@ -3204,6 +3205,7 @@ static const ImGuiDataVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize @@ -16678,7 +16680,7 @@ bool ImGui::DockNodeBeginAmendTabBar(ImGuiDockNode* node) return false; Begin(node->HostWindow->Name); PushOverrideID(node->ID); - bool ret = BeginTabBarEx(node->TabBar, node->TabBar->BarRect, node->TabBar->Flags, node); + bool ret = BeginTabBarEx(node->TabBar, node->TabBar->BarRect, node->TabBar->Flags); IM_UNUSED(ret); IM_ASSERT(ret); return true; @@ -16768,7 +16770,6 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w DockNodeAddTabBar(node); tab_bar = node->TabBar; } - tab_bar->ID = GetID("#TabBar"); ImGuiID focus_tab_id = 0; node->IsFocused = is_focused; @@ -16850,7 +16851,10 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode;// | ImGuiTabBarFlags_FittingPolicyScroll; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; - BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags, node); + tab_bar->ID = GetID("#TabBar"); + tab_bar->SeparatorMinX = node->Pos.x + host_window->WindowBorderSize; // Separator cover the whole node width + tab_bar->SeparatorMaxX = node->Pos.x + node->Size.x - host_window->WindowBorderSize; + BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags); //host_window->DrawList->AddRect(tab_bar_rect.Min, tab_bar_rect.Max, IM_COL32(255,0,255,255)); // Backup style colors @@ -17330,7 +17334,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock PushStyleColor(ImGuiCol_Text, overlay_col_text); for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++) { - ImGuiTabItemFlags tab_flags = ImGuiTabItemFlags_Preview | ((payload_window->Flags & ImGuiWindowFlags_UnsavedDocument) ? ImGuiTabItemFlags_UnsavedDocument : 0); + ImGuiTabItemFlags tab_flags = (payload_window->Flags & ImGuiWindowFlags_UnsavedDocument) ? ImGuiTabItemFlags_UnsavedDocument : 0; if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); diff --git a/imgui.h b/imgui.h index 41bcde1dd..d39ab3591 100644 --- a/imgui.h +++ b/imgui.h @@ -1726,6 +1726,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_GrabMinSize, // float GrabMinSize ImGuiStyleVar_GrabRounding, // float GrabRounding ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize @@ -1994,6 +1995,7 @@ struct ImGuiStyle float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6d156ebe0..51be2777e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6464,6 +6464,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); diff --git a/imgui_internal.h b/imgui_internal.h index 31cc4094d..9d0ec710a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2749,7 +2749,6 @@ enum ImGuiTabItemFlagsPrivate_ ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. - ImGuiTabItemFlags_Preview = 1 << 23, // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) }; // Storage for one active tab item (sizeof() 48 bytes) @@ -2794,6 +2793,8 @@ struct IMGUI_API ImGuiTabBar float ScrollingSpeed; float ScrollingRectMinX; float ScrollingRectMaxX; + float SeparatorMinX; + float SeparatorMaxX; ImGuiID ReorderRequestTabId; ImS16 ReorderRequestOffset; ImS8 BeginCount; @@ -3503,7 +3504,7 @@ namespace ImGui // Tab Bars inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } - IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node); + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order); IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index eba295f53..5d1dd459d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7801,16 +7801,19 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); tab_bar->ID = id; - return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused, NULL); + tab_bar->SeparatorMinX = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); + tab_bar->SeparatorMaxX = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); } -bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node) +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; if (window->SkipItems) return false; + IM_ASSERT(tab_bar->ID != 0); if ((flags & ImGuiTabBarFlags_DockNode) == 0) PushOverrideID(tab_bar->ID); @@ -7854,19 +7857,12 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); // Draw separator + // (it would be misleading to draw this in EndTabBar() suggesting that it may be drawn over tabs, as tab bar are appendable) const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); - const float y = tab_bar->BarRect.Max.y - 1.0f; - if (dock_node != NULL) + if (g.Style.TabBarBorderSize > 0.0f) { - const float separator_min_x = dock_node->Pos.x + window->WindowBorderSize; - const float separator_max_x = dock_node->Pos.x + dock_node->Size.x - window->WindowBorderSize; - window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); - } - else - { - const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); - const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); - window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + const float y = tab_bar->BarRect.Max.y; + window->DrawList->AddRectFilled(ImVec2(tab_bar->SeparatorMinX, y - g.Style.TabBarBorderSize), ImVec2(tab_bar->SeparatorMaxX, y), col); } return true; } @@ -8918,7 +8914,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI IM_ASSERT(width > 0.0f); const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); const float y1 = bb.Min.y + 1.0f; - const float y2 = bb.Max.y + ((flags & ImGuiTabItemFlags_Preview) ? 0.0f : -1.0f); + const float y2 = bb.Max.y - g.Style.TabBarBorderSize; draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);