|
@@ -6960,12 +6960,17 @@ ImGuiTabBar::ImGuiTabBar()
|
|
|
LastTabItemIdx = -1;
|
|
|
}
|
|
|
|
|
|
+static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab)
|
|
|
+{
|
|
|
+ return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+}
|
|
|
+
|
|
|
static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs)
|
|
|
{
|
|
|
const ImGuiTabItem* a = (const ImGuiTabItem*)lhs;
|
|
|
const ImGuiTabItem* b = (const ImGuiTabItem*)rhs;
|
|
|
- const int a_section = (a->Flags & ImGuiTabItemFlags_Leading) ? 0 : (a->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
- const int b_section = (b->Flags & ImGuiTabItemFlags_Leading) ? 0 : (b->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+ const int a_section = TabItemGetSectionIdx(a);
|
|
|
+ const int b_section = TabItemGetSectionIdx(b);
|
|
|
if (a_section != b_section)
|
|
|
return a_section - b_section;
|
|
|
return (int)(a->IndexDuringLayout - b->IndexDuringLayout);
|
|
@@ -7134,11 +7139,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|
|
tab->IndexDuringLayout = (ImS16)tab_dst_n;
|
|
|
|
|
|
// We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another)
|
|
|
- int curr_tab_section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+ int curr_tab_section_n = TabItemGetSectionIdx(tab);
|
|
|
if (tab_dst_n > 0)
|
|
|
{
|
|
|
ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1];
|
|
|
- int prev_tab_section_n = (prev_tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (prev_tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+ int prev_tab_section_n = TabItemGetSectionIdx(prev_tab);
|
|
|
if (curr_tab_section_n == 0 && prev_tab_section_n != 0)
|
|
|
need_sort_by_section = true;
|
|
|
if (prev_tab_section_n == 2 && curr_tab_section_n != 2)
|
|
@@ -7210,7 +7215,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|
|
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
|
|
|
tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x;
|
|
|
|
|
|
- int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+ int section_n = TabItemGetSectionIdx(tab);
|
|
|
ImGuiTabBarSection* section = §ions[section_n];
|
|
|
section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);
|
|
|
curr_section_n = section_n;
|
|
@@ -7265,7 +7270,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|
|
if (shrinked_width < 0.0f)
|
|
|
continue;
|
|
|
|
|
|
- int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
|
|
+ int section_n = TabItemGetSectionIdx(tab);
|
|
|
sections[section_n].Width -= (tab->Width - shrinked_width);
|
|
|
tab->Width = shrinked_width;
|
|
|
}
|
|
@@ -7410,7 +7415,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
|
|
|
ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id);
|
|
|
if (tab == NULL)
|
|
|
return;
|
|
|
- if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))
|
|
|
+ if (tab->Flags & ImGuiTabItemFlags_SectionMask_)
|
|
|
return;
|
|
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -7439,56 +7444,48 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir)
|
|
|
+void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset)
|
|
|
{
|
|
|
- IM_ASSERT(dir == -1 || dir == +1);
|
|
|
+ IM_ASSERT(offset != 0);
|
|
|
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
|
|
|
tab_bar->ReorderRequestTabId = tab->ID;
|
|
|
- tab_bar->ReorderRequestDir = (ImS8)dir;
|
|
|
+ tab_bar->ReorderRequestOffset = (ImS16)offset;
|
|
|
}
|
|
|
|
|
|
-void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos)
|
|
|
+void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
|
|
|
-
|
|
|
if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0)
|
|
|
return;
|
|
|
|
|
|
- int source_idx = tab_bar->Tabs.index_from_ptr(tab);
|
|
|
- float bar_x = tab_bar->BarRect.Min.x;
|
|
|
- int dir = bar_x + tab->Offset > mouse_pos.x ? -1 : +1;
|
|
|
- int target_idx = source_idx;
|
|
|
+ const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;
|
|
|
+ const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0);
|
|
|
|
|
|
- for (int i = source_idx; 0 <= i && i < tab_bar->Tabs.Size; i += dir)
|
|
|
+ // Count number of contiguous tabs we are crossing over
|
|
|
+ const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1;
|
|
|
+ const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab);
|
|
|
+ int dst_idx = src_idx;
|
|
|
+ for (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir)
|
|
|
{
|
|
|
- const ImGuiTabItem* target_tab = &tab_bar->Tabs[i];
|
|
|
-
|
|
|
- // Reorder only within tab groups with _Leading, _Trailing flag or without either of them.
|
|
|
- if ((target_tab->Flags & ImGuiTabItemFlags_Leading) != (tab->Flags & ImGuiTabItemFlags_Leading))
|
|
|
- break;
|
|
|
- if ((target_tab->Flags & ImGuiTabItemFlags_Trailing) != (tab->Flags & ImGuiTabItemFlags_Trailing))
|
|
|
+ // Reordered tabs must share the same section
|
|
|
+ const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i];
|
|
|
+ if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder)
|
|
|
break;
|
|
|
-
|
|
|
- // Do not reorder past tabs with _NoReorder flag.
|
|
|
- if (target_tab->Flags & ImGuiTabItemFlags_NoReorder)
|
|
|
+ if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_))
|
|
|
break;
|
|
|
+ dst_idx = i;
|
|
|
|
|
|
- target_idx = i; // target_tab can be swapped with dragged tab.
|
|
|
-
|
|
|
- // Current tab is destination tab under mouse position. Also include space after tab, so when mouse cursor is
|
|
|
- // between tabs we would not continue checking further tabs that are not hovered.
|
|
|
- if (dir > 0 && mouse_pos.x < bar_x + target_tab->Offset + target_tab->Width + g.Style.ItemInnerSpacing.x) // End of tab is past mouse_pos.
|
|
|
- break;
|
|
|
- if (dir < 0 && mouse_pos.x > bar_x + target_tab->Offset - g.Style.ItemInnerSpacing.x) // Mouse pos is past start of tab.
|
|
|
+ // Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered.
|
|
|
+ const float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x;
|
|
|
+ const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x;
|
|
|
+ //GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255));
|
|
|
+ if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2))
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (target_idx != source_idx)
|
|
|
- {
|
|
|
- tab_bar->ReorderRequestTabId = tab->ID;
|
|
|
- tab_bar->ReorderRequestDir = (ImS8)(target_idx - source_idx);
|
|
|
- }
|
|
|
+ if (dst_idx != src_idx)
|
|
|
+ TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx);
|
|
|
}
|
|
|
|
|
|
bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
|
|
@@ -7498,30 +7495,23 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
|
|
|
return false;
|
|
|
|
|
|
//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
|
|
|
- int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir;
|
|
|
+ int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset;
|
|
|
if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
|
|
|
return false;
|
|
|
|
|
|
- // Reordered TabItem must share the same position flags than target
|
|
|
+ // Reordered tabs must share the same section
|
|
|
+ // (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too)
|
|
|
ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
|
|
|
if (tab2->Flags & ImGuiTabItemFlags_NoReorder)
|
|
|
return false;
|
|
|
- if ((tab1->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (tab2->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)))
|
|
|
+ if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_))
|
|
|
return false;
|
|
|
|
|
|
ImGuiTabItem item_tmp = *tab1;
|
|
|
- ImGuiTabItem* src, *dst;
|
|
|
- if (tab_bar->ReorderRequestDir > 0)
|
|
|
- {
|
|
|
- dst = tab1;
|
|
|
- src = tab1 + 1;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dst = tab2 + 1;
|
|
|
- src = tab2;
|
|
|
- }
|
|
|
- memmove(dst, src, abs(tab_bar->ReorderRequestDir) * sizeof(ImGuiTabItem));
|
|
|
+ ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2;
|
|
|
+ ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1;
|
|
|
+ const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset;
|
|
|
+ memmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem));
|
|
|
*tab2 = item_tmp;
|
|
|
|
|
|
if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
|
|
@@ -7803,7 +7793,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|
|
const ImVec2 backup_main_cursor_pos = window->DC.CursorPos;
|
|
|
|
|
|
// Layout
|
|
|
- const bool is_central_section = (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) == 0;
|
|
|
+ const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;
|
|
|
size.x = tab->Width;
|
|
|
if (is_central_section)
|
|
|
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
|