From 8c80d533d96a9b9ef83b1d16dd8396f61f4dd743 Mon Sep 17 00:00:00 2001 From: Louis Schnellbach Date: Wed, 26 Aug 2020 12:18:02 +0200 Subject: [PATCH] Tab Bar: Fixed a small bug where toggling a tab bar from Reorderable to not Reorderable would leave tabs reordered in the tab list popup. --- docs/CHANGELOG.txt | 2 ++ imgui_internal.h | 6 ++++-- imgui_widgets.cpp | 14 ++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 61600a6c..d5d601f9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,8 @@ Other Changes: and amends the change done in 1.76 which only affected cases were _OpenOnArrow flag was set. (This is also necessary to support full multi/range-select/drag and drop operations.) - Tab Bar: Keep tab item close button visible while dragging a tab (independent of hovering state). +- Tab Bar: Fixed a small bug where toggling a tab bar from Reorderable to not Reorderable would leave + tabs reordered in the tab list popup. [@Xipiryon] - Metrics: Various tweaks, listing windows front-to-back, greying inactive items when possible. - Demo: Add simple InputText() callbacks demo (aside from the more elaborate ones in 'Examples->Console'). - Examples: Vulkan: Reworked buffer resize handling, fix for Linux/X11. (#3390, #2626) [@RoryO] diff --git a/imgui_internal.h b/imgui_internal.h index 6bf49337..00baf037 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1710,9 +1710,10 @@ struct ImGuiTabItem float Width; // Width currently displayed 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 bool WantClose; // Marked as closed by SetTabItemClosed() - ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; WantClose = false; } + ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; WantClose = false; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1737,9 +1738,10 @@ struct ImGuiTabBar ImGuiTabBarFlags Flags; ImGuiID ReorderRequestTabId; ImS8 ReorderRequestDir; + ImS8 TabsActiveCount; // Number of tabs submitted this frame. bool WantLayout; bool VisibleTabWasSubmitted; - short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + short LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem() ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 59fa0918..352b687a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6782,15 +6782,16 @@ ImGuiTabBar::ImGuiTabBar() Flags = ImGuiTabBarFlags_None; ReorderRequestTabId = 0; ReorderRequestDir = 0; + TabsActiveCount = 0; WantLayout = VisibleTabWasSubmitted = false; LastTabItemIdx = -1; } -static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs) +static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs) { const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; - return (int)(a->Offset - b->Offset); + return (int)(a->BeginOrder - b->BeginOrder); } static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) @@ -6842,10 +6843,9 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG return true; } - // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. - // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. - if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) - ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); + // When toggling ImGuiTabBarFlags_Reorderable flag, ensure tabs are ordered based on their submission order. + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); // Flags if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) @@ -6857,6 +6857,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; tab_bar->CurrFrameVisible = g.FrameCount; tab_bar->FramePadding = g.Style.FramePadding; + tab_bar->TabsActiveCount = 0; // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap window->DC.CursorPos.x = tab_bar->BarRect.Min.x; @@ -7362,6 +7363,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); tab->ContentWidth = size.x; + tab->BeginOrder = tab_bar->TabsActiveCount++; const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;