1
0
mirror of https://github.com/wolfpld/tracy.git synced 2025-03-20 07:40:02 +08:00

Switch imgui to docking branch.

This commit is contained in:
Bartosz Taudul
2020-05-03 13:16:17 +02:00
parent aa7851d1d7
commit c5f1128209
10 changed files with 7238 additions and 350 deletions
+181 -33
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.76
// dear imgui, v1.77 WIP
// (widgets code)
/*
@@ -480,13 +480,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
flags |= ImGuiButtonFlags_PressedOnDefault_;
ImGuiWindow* backup_hovered_window = g.HoveredWindow;
const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window;
const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window->RootWindow;
if (flatten_hovered_children)
g.HoveredWindow = window;
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0 && window->DC.LastItemId != id)
ImGuiTestEngineHook_ItemAdd(&g, bb, id);
IMGUI_TEST_ENGINE_ITEM_ADD(bb, id);
#endif
bool pressed = false;
@@ -500,11 +500,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
{
const float DRAG_DROP_HOLD_TIMER = 0.70f;
hovered = true;
SetHoveredID(id);
if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, 0.70f, 0.00f))
if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, DRAG_DROP_HOLD_TIMER, 0.00f))
{
pressed = true;
g.DragDropHoldJustPressedId = id;
FocusWindow(window);
}
}
@@ -784,7 +786,8 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size)
return pressed;
}
bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
// The Collapse button also functions as a Dock Menu button.
bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -795,16 +798,22 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
// Render
//bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
ImVec2 off = dock_node ? ImVec2(IM_FLOOR(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f);
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImU32 text_col = GetColorU32(ImGuiCol_Text);
ImVec2 center = bb.GetCenter();
if (hovered || held)
window->DrawList->AddCircleFilled(center/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12);
RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
window->DrawList->AddCircleFilled(center + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, bg_col, 12);
if (dock_node)
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, text_col);
else
RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
// Switch to moving the window after mouse is moved beyond the initial drag threshold
if (IsItemActive() && IsMouseDragging(0))
StartMouseMovingWindow(window);
StartMouseMovingWindowOrNode(window, dock_node, true);
return pressed;
}
@@ -1132,6 +1141,7 @@ bool ImGui::RadioButton(const char* label, bool active)
if (label_size.x > 0.0f)
RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
return pressed;
}
@@ -4192,7 +4202,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
if (!is_readonly)
g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize);
{
g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
g.PlatformImePosViewport = window->Viewport;
}
}
}
else
@@ -5360,10 +5373,11 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// It is rather standard that arrow click react on Down rather than Up and we'd be tempted to make it the default
// (by removing the _OpenOnArrow test below), however this would have a perhaps surprising effect on CollapsingHeader()?
// So right now we are making this optional. May evolve later.
// We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work.
if (is_mouse_x_over_arrow && (flags & ImGuiTreeNodeFlags_OpenOnArrow))
button_flags |= ImGuiButtonFlags_PressedOnClick;
else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
button_flags |= ImGuiButtonFlags_PressedOnDoubleClick;
button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
else
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
@@ -5375,7 +5389,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
bool toggled = false;
if (!is_leaf)
{
if (pressed)
if (pressed && g.DragDropHoldJustPressedId != id)
{
if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id))
toggled = true;
@@ -5383,8 +5397,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job
if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0])
toggled = true;
if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
toggled = false;
}
else if (pressed && g.DragDropHoldJustPressedId == id)
{
IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold);
if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
toggled = true;
}
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
@@ -5485,7 +5503,8 @@ void ImGui::TreePush(const void* ptr_id)
void ImGui::TreePushOverrideID(ImGuiID id)
{
ImGuiWindow* window = GetCurrentWindow();
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
Indent();
window->DC.TreeDepth++;
window->IDStack.push_back(id);
@@ -6167,18 +6186,39 @@ void ImGui::EndMenuBar()
window->DC.MenuBarAppending = false;
}
// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
bool ImGui::BeginMainMenuBar()
{
ImGuiContext& g = *GImGui;
ImGuiViewportP* viewport = g.Viewports[0];
ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar");
// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
SetNextWindowPos(ImVec2(0.0f, 0.0f));
SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
// Get our rectangle at the top of the work area
if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0)
{
// Set window position
// We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. However menu-bar will affect the minimum window size so we'll get the right height.
ImVec2 menu_bar_pos = viewport->Pos + viewport->CurrWorkOffsetMin;
ImVec2 menu_bar_size = ImVec2(viewport->Size.x - viewport->CurrWorkOffsetMin.x + viewport->CurrWorkOffsetMax.x, 1.0f);
SetNextWindowPos(menu_bar_pos);
SetNextWindowSize(menu_bar_size);
}
// Create window
SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint, however the presence of a menu-bar will give us the minimum height we want.
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
PopStyleVar(2);
// Report our size into work area (for next frame) using actual window size
menu_bar_window = GetCurrentWindow();
if (menu_bar_window->BeginCount == 1)
viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y;
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
if (!is_open)
{
@@ -6451,6 +6491,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarCalcTabID() [Internal]
// - TabBarCalcMaxTabWidth() [Internal]
// - TabBarFindTabById() [Internal]
// - TabBarAddTab() [Internal]
// - TabBarRemoveTab() [Internal]
// - TabBarCloseTab() [Internal]
// - TabBarScrollClamp()v
@@ -6518,10 +6559,10 @@ 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);
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused, NULL);
}
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags)
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -6538,7 +6579,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
if (tab_bar->CurrFrameVisible == g.FrameCount)
{
//IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount);
IM_ASSERT(0);
//IM_ASSERT(0);
return true;
}
@@ -6565,6 +6606,13 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
// Draw separator
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)
{
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);
@@ -6685,7 +6733,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab);
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
const bool has_close_button = tab->Window ? tab->Window->HasCloseButton : ((tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0);
tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x;
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth;
@@ -6749,6 +6797,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
tab_bar->VisibleTabId = tab_bar->SelectedTabId;
tab_bar->VisibleTabWasSubmitted = false;
// CTRL+TAB can override visible tab temporarily
if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar)
tab_bar->VisibleTabId = scroll_track_selected_tab_id = g.NavWindowingTarget->ID;
// Update scrolling
if (scroll_track_selected_tab_id)
if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id))
@@ -6805,6 +6857,38 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
return NULL;
}
// FIXME: See references to #2304 in TODO.txt
ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar)
{
ImGuiTabItem* most_recently_selected_tab = NULL;
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected)
if (tab->Window && tab->Window->WasActive)
most_recently_selected_tab = tab;
}
return most_recently_selected_tab;
}
// The purpose of this call is to register tab in advance so we can control their order at the time they appear.
// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL);
IM_ASSERT(g.CurrentTabBar != tab_bar); // Can't work while the tab bar is active as our tab doesn't have an X offset yet, in theory we could/should test something like (tab_bar->CurrFrameVisible < g.FrameCount) but we'd need to solve why triggers the commented early-out assert in BeginTabBarEx() (probably dock node going from implicit to explicit in same frame)
ImGuiTabItem new_tab;
new_tab.ID = window->ID;
new_tab.Flags = tab_flags;
new_tab.LastFrameVisible = tab_bar->CurrFrameVisible; // Required so BeginTabBar() doesn't ditch the tab
if (new_tab.LastFrameVisible == -1)
new_tab.LastFrameVisible = g.FrameCount - 1;
new_tab.Window = window; // Required so tab bar layout can compute the tab width before tab submission
tab_bar->Tabs.push_back(new_tab);
}
// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
{
@@ -6980,7 +7064,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!");
return false;
}
bool ret = TabItemEx(tab_bar, label, p_open, flags);
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
@@ -7008,7 +7092,7 @@ void ImGui::EndTabItem()
window->IDStack.pop_back();
}
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags)
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
{
// Layout whole tab bar if not already done
if (tab_bar->WantLayout)
@@ -7023,6 +7107,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
const ImGuiID id = TabBarCalcTabID(tab_bar, label);
// If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
if (p_open && !*p_open)
{
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
@@ -7059,10 +7144,20 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);
tab->LastFrameVisible = g.FrameCount;
tab->Flags = flags;
tab->Window = docked_window;
// Append name with zero-terminator
tab->NameOffset = tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label, label + strlen(label) + 1);
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
{
IM_ASSERT(tab->Window != NULL);
tab->NameOffset = -1;
}
else
{
IM_ASSERT(tab->Window == NULL);
tab->NameOffset = tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Append name _with_ the zero-terminator.
}
// If we are not reorderable, always reset offset based on submission order.
// (We already handled layout and sizing using the previous known order, but sizing is not affected by order!)
@@ -7085,7 +7180,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
tab_bar->VisibleTabWasSubmitted = true;
// On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches
if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing)
if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL)
if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs))
tab_contents_visible = true;
@@ -7128,7 +7223,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Click to Select a tab
ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap);
if (g.DragDropActive)
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW))
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
@@ -7140,23 +7235,66 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
if (!held)
SetItemAllowOverlap();
// Drag and drop: re-order tabs
if (held && !tab_appearing && IsMouseDragging(0))
// Drag and drop a single floating window node moves it
ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL;
const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1);
if (held && single_floating_window_node && IsMouseDragging(0, 0.0f))
{
if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable))
// Move
StartMouseMovingWindow(docked_window);
}
else if (held && !tab_appearing && IsMouseDragging(0))
{
// Drag and drop: re-order tabs
float drag_distance_from_edge_x = 0.0f;
if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL)))
{
// While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)
{
drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x;
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
TabBarQueueChangeTabOrder(tab_bar, tab, -1);
}
else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)
{
drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x;
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
TabBarQueueChangeTabOrder(tab_bar, tab, +1);
}
}
// Extract a Dockable window out of it's tab bar
if (docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove))
{
// We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar
bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id);
if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift)
{
float threshold_base = g.FontSize;
//float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize;
float threshold_x = (threshold_base * 2.2f);
float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
//GetForegroundDrawList()->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG]
float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y);
if (distance_from_edge_y >= threshold_y)
undocking_tab = true;
else if (drag_distance_from_edge_x > threshold_x)
if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1))
undocking_tab = true;
}
if (undocking_tab)
{
// Undock
DockContextQueueUndockWindow(&g, docked_window);
g.MovingWindow = docked_window;
g.ActiveId = g.MovingWindow->MoveId;
g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
}
}
}
#if 0
@@ -7219,6 +7357,16 @@ void ImGui::SetTabItemClosed(const char* label)
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
TabBarRemoveTab(tab_bar, tab_id);
}
else if (ImGuiWindow* window = FindWindowByName(label))
{
if (window->DockIsActive)
if (ImGuiDockNode* node = window->DockNode)
{
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label);
TabBarRemoveTab(node->TabBar, tab_id);
window->DockTabWantClose = true;
}
}
}
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button)
@@ -7242,7 +7390,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
IM_ASSERT(width > 0.0f);
const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f));
const float y1 = bb.Min.y + 1.0f;
const float y2 = bb.Max.y - 1.0f;
const float y2 = bb.Max.y + ((flags & ImGuiTabItemFlags_Preview) ? 0.0f : -1.0f);
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);