From f23c39c395e4412f6f83786f591bdc4e727af203 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Aug 2020 15:16:16 +0200 Subject: [PATCH] Tab Bar: Fixed handling of scrolling policy with leading/trailing tabs. + warning fixes + bunch of renaming. (#3291) Demo tweaks. --- imgui.cpp | 11 ++++- imgui_demo.cpp | 72 ++++++++++------------------ imgui_internal.h | 7 +-- imgui_widgets.cpp | 120 +++++++++++++++++++++++++++------------------- 4 files changed, 109 insertions(+), 101 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ec107aed..427fffc9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10559,6 +10559,15 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } bool open = ImGui::TreeNode(tab_bar, "%s", buf); if (!is_active) { PopStyleColor(); } + if (is_active && ImGui::IsItemHovered()) + { + ImDrawList* draw_list = ImGui::GetForegroundDrawList(); + draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255)); + if (tab_bar->WidthLeading > 0.0f) + draw_list->AddLine(ImVec2(tab_bar->BarRect.Min.x + tab_bar->WidthLeading, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Min.x + tab_bar->WidthLeading, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + if (tab_bar->WidthTrailing > 0.0f) + draw_list->AddLine(ImVec2(tab_bar->BarRect.Max.x - tab_bar->WidthTrailing, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x - tab_bar->WidthTrailing, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + } if (open) { for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) @@ -10567,7 +10576,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::PushID(tab); if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine(); - ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : ""); + ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth); ImGui::PopID(); } ImGui::TreePop(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 42a3bf31..3cc153cb 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2355,16 +2355,15 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("TabItem Button")) + if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) { - static int next_id = 0; - static ImVector tabs_list; - if (next_id == 0) // Initialize with a default tab - for (int i = 0; i < 9; i++) - tabs_list.push_back(next_id++); + static ImVector active_tabs; + static int next_tab_id = 0; + if (next_tab_id == 0) // Initialize with some default tabs + for (int i = 0; i < 3; i++) + active_tabs.push_back(next_tab_id++); static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; - ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); @@ -2375,63 +2374,40 @@ static void ShowDemoWindowLayout() static bool show_trailing_button = true; ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); - static bool enable_position = false; - ImGui::Checkbox("Enable Leading/Trailing TabItem()", &enable_position); if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) { - if (show_leading_button) + // Demo Leading Tabs: click the "?" button to open a menu + // Note that it is possible to submit regular non-button tabs with Leading/Trailing flags, + // or Button without Leading/Trailing flags... but they tend to make more sense together. + if (show_leading_button && ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) + ImGui::OpenPopup("MyHelpMenu"); + if (ImGui::BeginPopup("MyHelpMenu")) { - if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) - tabs_list.push_back(next_id++); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Add a new TabItem() in the tab bar"); - - // Popup Context also works with TabItemButton - if (ImGui::BeginPopupContextItem()) - { - ImGui::Text("I'm a popup!"); - if (ImGui::Button("Close")) - ImGui::CloseCurrentPopup(); - ImGui::EndPopup(); - } + ImGui::Selectable("Hello!"); + ImGui::EndPopup(); } - bool close_current_tab = false; - if (show_trailing_button) - { - if (ImGui::TabItemButton("X", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) - close_current_tab = true; - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Close the currently selected TabItem()"); - } + // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+") + if (show_trailing_button && ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) + active_tabs.push_back(next_tab_id++); - for (int n = 0; n < tabs_list.Size; ) + // Submit our regular tabs + for (int n = 0; n < active_tabs.Size; ) { - int mod = tabs_list[n] % 3; - ImGuiTabItemFlags flags = mod == 0 ? 0 : mod == 1 ? ImGuiTabItemFlags_Leading : ImGuiTabItemFlags_Trailing; - if (!enable_position) - flags = 0; - - char name[16]; - snprintf(name, IM_ARRAYSIZE(name), "%04d", tabs_list[n]); bool open = true; - if (ImGui::BeginTabItem(name, &open, flags)) + char name[16]; + snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); + if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) { ImGui::Text("This is the %s tab!", name); ImGui::EndTabItem(); - - if (close_current_tab) - { - open = false; - ImGui::SetTabItemClosed(name); - } } if (!open) - tabs_list.erase(tabs_list.Data + n); + active_tabs.erase(active_tabs.Data + n); else - ++n; + n++; } ImGui::EndTabBar(); diff --git a/imgui_internal.h b/imgui_internal.h index 0563e7c5..5a3d468b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1719,9 +1719,10 @@ struct ImGuiTabItem float ContentWidth; // Width of actual contents, stored during BeginTabItem() call ImS16 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames ImS8 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable + ImS8 IndexDuringLayout; // Index only used during TabBarLayout() bool WantClose; // Marked as closed by SetTabItemClosed() - ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; WantClose = false; } + ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; IndexDuringLayout = -1; WantClose = false; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1738,8 +1739,8 @@ struct ImGuiTabBar float LastTabContentHeight; // Record the height of contents submitted below the tab bar float WidthAllTabs; // Actual width of all tabs (locked during layout) float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped - float LeadingWidth; // Total width used by leading button - float TrailingWidth; // Total width used by trailing button + float WidthLeading; // Total width used by leading button + float WidthTrailing; // Total width used by trailing button float ScrollingAnim; float ScrollingTarget; float ScrollingTargetDistToVisibility; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 79031027..35c47793 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6815,7 +6815,7 @@ ImGuiTabBar::ImGuiTabBar() CurrFrameVisible = PrevFrameVisible = -1; LastTabContentHeight = 0.0f; WidthAllTabs = WidthAllTabsIdeal = 0.0f; - LeadingWidth = TrailingWidth = 0.0f; + WidthLeading = WidthTrailing = 0.0f; ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f; Flags = ImGuiTabBarFlags_None; ReorderRequestTabId = 0; @@ -7015,11 +7015,15 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + // Reserve shrink buffer for maximum possible number of tabs (but tabs with Trailing/Leading won't shrink) + int tab_n_shrinkable = 0; + g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); + // Compute ideal widths - g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); // Reserve for maximum possible number of tabs, - int tab_n_shrinkable = 0; // ..but buttons won't shrink - tab_bar->LeadingWidth = tab_bar->TrailingWidth = 0.0f; - float width_total_contents = 0.0f; + float width_central = 0.0f; + tab_bar->WidthLeading = tab_bar->WidthTrailing = 0.0f; + const float tab_max_width = TabBarCalcMaxTabWidth(); + ImGuiTabItem* most_recently_selected_tab = NULL; bool found_selected_tab_id = false; for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) @@ -7027,9 +7031,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); - if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) - if (!(tab->Flags & ImGuiTabItemFlags_Button)) - most_recently_selected_tab = tab; + if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button)) + most_recently_selected_tab = tab; if (tab->ID == tab_bar->SelectedTabId) found_selected_tab_id = true; @@ -7042,79 +7045,95 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) float width = tab->ContentWidth; if (tab->Flags & ImGuiTabItemFlags_Leading) - tab_bar->LeadingWidth += width + g.Style.ItemInnerSpacing.x; + { + tab_bar->WidthLeading += width + g.Style.ItemInnerSpacing.x; + } else if (tab->Flags & ImGuiTabItemFlags_Trailing) - tab_bar->TrailingWidth += width + g.Style.ItemInnerSpacing.x; + { + tab_bar->WidthTrailing += width + g.Style.ItemInnerSpacing.x; + } else { - width_total_contents += width + (tab_n_shrinkable > 0 ? g.Style.ItemInnerSpacing.x : 0.0f); - // Store data so we can build an array sorted by width if we need to shrink tabs down - g.ShrinkWidthBuffer[tab_n_shrinkable].Index = tab_n; + width = ImMin(tab->ContentWidth, tab_max_width); + width_central += width + (tab_n_shrinkable > 0 ? g.Style.ItemInnerSpacing.x : 0.0f); + g.ShrinkWidthBuffer[tab_n_shrinkable].Index = tab_n; // Store data so we can build an array sorted by width if we need to shrink tabs down g.ShrinkWidthBuffer[tab_n_shrinkable].Width = tab->ContentWidth; tab_n_shrinkable++; } + + IM_ASSERT(width > 0.0f); + tab->Width = width; } // Compute width - const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - tab_bar->LeadingWidth - tab_bar->TrailingWidth, 0.0f); - float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; + const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - tab_bar->WidthLeading - tab_bar->WidthTrailing, 0.0f); + float width_excess = (width_avail < width_central) ? (width_central - width_avail) : 0.0f; if (width_excess > 0.0f && !(tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll)) { // If we don't have enough room, resize down the largest tabs first ShrinkWidths(g.ShrinkWidthBuffer.Data, tab_n_shrinkable, width_excess); for (int tab_n = 0; tab_n < tab_n_shrinkable; tab_n++) tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); - } - else - { - const float tab_max_width = TabBarCalcMaxTabWidth(); + width_central -= width_excess; +#if 0 + width_central = (tab_bar->WidthLeading > 0.0f) ? -g.Style.ItemInnerSpacing.x : 0.0f; for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - tab->Width = ImMin(tab->ContentWidth, tab_max_width); - IM_ASSERT(tab->Width > 0.0f); + if ((tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) == 0) + width_central += tab->Width + g.Style.ItemInnerSpacing.x; } +#endif } // Layout all active tabs - float offset_x_button_leading = 0.0f; - float offset_x_button_trailing = tab_bar->BarRect.GetWidth() - tab_bar->TrailingWidth + g.Style.ItemInnerSpacing.x; - float offset_x_regular = tab_bar->LeadingWidth; - float offset_x_ideal = offset_x_regular; + float offset_x_pos_leading = 0.0f; + float offset_x_pos_central = tab_bar->WidthLeading; +#if 0 + float offset_x_pos_trailing = tab_bar->BarRect.GetWidth() - tab_bar->WidthTrailing + g.Style.ItemInnerSpacing.x; // Right-most layout +#else + float offset_x_pos_trailing = tab_bar->WidthLeading + width_central; // Trailing layout + if (offset_x_pos_trailing > 0.0f) + offset_x_pos_trailing += g.Style.ItemInnerSpacing.x; +#endif + + float width_ideal = tab_bar->WidthLeading; for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; float width = tab->Width + g.Style.ItemInnerSpacing.x; if (tab->Flags & ImGuiTabItemFlags_Leading) { - tab->Offset = offset_x_button_leading; - offset_x_button_leading += width; + tab->Offset = offset_x_pos_leading; + offset_x_pos_leading += width; } else if (tab->Flags & ImGuiTabItemFlags_Trailing) { - tab->Offset = offset_x_button_trailing; - offset_x_button_trailing += width; + tab->Offset = offset_x_pos_trailing; + offset_x_pos_trailing += width; } else { - tab->Offset = offset_x_regular; + tab->Offset = offset_x_pos_central; if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) scroll_track_selected_tab_id = tab->ID; - offset_x_regular += width; - offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x; + offset_x_pos_central += width; + width_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x; } } - tab_bar->WidthAllTabs = ImMax(offset_x_regular - g.Style.ItemInnerSpacing.x + tab_bar->TrailingWidth, 0.0f); - tab_bar->WidthAllTabsIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x + tab_bar->TrailingWidth, 0.0f); + tab_bar->WidthAllTabs = ImMax(offset_x_pos_central - g.Style.ItemInnerSpacing.x + tab_bar->WidthTrailing, 0.0f); + tab_bar->WidthAllTabsIdeal = ImMax(width_ideal - g.Style.ItemInnerSpacing.x + tab_bar->WidthTrailing, 0.0f); // Horizontal scrolling buttons const bool scrolling_buttons = (tab_bar->WidthAllTabs > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); if (scrolling_buttons) if (ImGuiTabItem* scroll_track_selected_tab = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x and each trailing tab->Offset + { if (scroll_track_selected_tab->Flags & ImGuiTabItemFlags_Button) scroll_track_selected_tab_id = scroll_track_selected_tab->ID; else scroll_track_selected_tab_id = tab_bar->SelectedTabId = scroll_track_selected_tab->ID; + } // If we have lost the selected tab, select the next most recently active one if (found_selected_tab_id == false) @@ -7154,9 +7173,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) ImGuiWindow* window = g.CurrentWindow; window->DC.CursorPos = tab_bar->BarRect.Min; ItemSize(ImVec2(tab_bar->WidthAllTabsIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); - - window->DrawList->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Min + ImVec2(tab_bar->LeadingWidth, tab_bar->BarRect.GetHeight()), IM_COL32(255, 0, 0, 255)); - window->DrawList->AddRect(tab_bar->BarRect.Max - ImVec2(tab_bar->TrailingWidth, tab_bar->BarRect.GetHeight()), tab_bar->BarRect.Max, IM_COL32(0, 255, 0, 255)); } // Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. @@ -7238,18 +7254,24 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) int order = tab_bar->GetTabOrder(tab); - float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f); - float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); + // Scrolling happens only in the central section (leading/trailing sections are not scrolling) + float scrollable_width = tab_bar->BarRect.GetWidth() - tab_bar->WidthLeading - tab_bar->WidthTrailing; + + // We make all tabs positions all relative WidthLeading to make code simpler + float tab_x1 = tab->Offset - tab_bar->WidthLeading + (order > 0 ? -margin : 0.0f); + float tab_x2 = tab->Offset - tab_bar->WidthLeading + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); tab_bar->ScrollingTargetDistToVisibility = 0.0f; - if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth())) + if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width)) { + // Scroll to the left tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); tab_bar->ScrollingTarget = tab_x1; } - else if (tab_bar->ScrollingTarget < tab_x2 - tab_bar->BarRect.GetWidth()) + else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width) { - tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - tab_bar->BarRect.GetWidth()) - tab_bar->ScrollingAnim, 0.0f); - tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth(); + // Scroll to the right + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - scrollable_width; } } @@ -7420,7 +7442,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - IM_ASSERT_USER_ERROR(!(flags & ImGuiTabItemFlags_Button), "BeginTabItem() Can't be used with button flags, use TabItemButton() instead!"); + IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! bool ret = TabItemEx(tab_bar, label, p_open, flags); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) @@ -7460,7 +7482,7 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT_USER_ERROR(tab_bar, "TabItemButton() needs to be called between BeginTabBar() and EndTabBar()!"); + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder); @@ -7491,7 +7513,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, return false; } - IM_ASSERT(!p_open || (p_open && !(flags & ImGuiTabItemFlags_Button))); // TabItemButton should not have visible content + IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) if (flags & ImGuiTabItemFlags_NoCloseButton) @@ -7568,7 +7591,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Layout size.x = tab->Width; - //if (is_tab_button && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); else @@ -7578,8 +7600,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) // If TabBar fitting policy is scroll, then just clip through the BarRect - float offset_leading = (flags & ImGuiTabItemFlags_Leading) ? 0.0f : tab_bar->LeadingWidth; - float offset_trailing = (flags & (ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_Leading)) ? 0.0f : tab_bar->TrailingWidth; // Leading buttons will be clipped by BarRect.Max.x, trailing buttons will be clipped at BarRect.Minx + LeadingsWidth + float offset_leading = (flags & ImGuiTabItemFlags_Leading) ? 0.0f : tab_bar->WidthLeading; + float offset_trailing = (flags & (ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_Leading)) ? 0.0f : tab_bar->WidthTrailing; // Leading buttons will be clipped by BarRect.Max.x, trailing buttons will be clipped at BarRect.Minx + LeadingsWidth bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x + offset_leading) || (bb.Max.x + offset_trailing > tab_bar->BarRect.Max.x); if (want_clip_rect) PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x + offset_leading), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x - offset_trailing, bb.Max.y), true);