Switch to imgui docking branch, vendor it

This commit is contained in:
2026-02-22 18:34:37 -05:00
parent aa6065b0bd
commit 2d08a1dd54
13 changed files with 8233 additions and 310 deletions

View File

@@ -560,7 +560,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_;
ImGuiWindow* backup_hovered_window = g.HoveredWindow;
const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window->RootWindow;
const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree;
if (flatten_hovered_children)
g.HoveredWindow = window;
@@ -926,7 +926,8 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)
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;
@@ -939,16 +940,21 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
return pressed;
// Render
//bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImU32 text_col = GetColorU32(ImGuiCol_Text);
if (hovered || held)
window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col);
RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact);
RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
if (dock_node)
RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col);
else
RenderArrow(window->DrawList, bb.Min, 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); // Undock from window/collapse menu button
return pressed;
}
@@ -982,7 +988,8 @@ void ImGui::Scrollbar(ImGuiAxis axis)
// Calculate scrollbar bounding box
ImRect bb = GetWindowScrollbarRect(window, axis);
ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, window->Rect(), g.Style.WindowBorderSize);
ImRect host_rect = (window->DockIsActive ? window->DockNode->HostWindow : window)->Rect();
ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, host_rect, g.Style.WindowBorderSize);
float size_visible = window->InnerRect.Max[axis] - window->InnerRect.Min[axis];
float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f;
ImS64 scroll = (ImS64)window->Scroll[axis];
@@ -9009,9 +9016,10 @@ bool ImGui::BeginMenuBar()
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
// We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f);
const float border_top = ImMax(IM_ROUND(window->WindowBorderSize * 0.5f - window->TitleBarHeight), 0.0f);
const float border_half = IM_ROUND(window->WindowBorderSize * 0.5f);
ImRect bar_rect = window->MenuBarRect();
ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y));
ImRect clip_rect(ImFloor(bar_rect.Min.x + border_half), ImFloor(bar_rect.Min.y + border_top), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, border_half))), ImFloor(bar_rect.Max.y));
clip_rect.ClipWith(window->OuterRectClipped);
PushClipRect(clip_rect.Min, clip_rect.Max, false);
@@ -9092,10 +9100,10 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im
IM_ASSERT(dir != ImGuiDir_None);
ImGuiWindow* bar_window = FindWindowByName(name);
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());
if (bar_window == NULL || bar_window->BeginCount == 0)
{
// Calculate and set window size/position
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());
ImRect avail_rect = viewport->GetBuildWorkRect();
ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
ImVec2 pos = avail_rect.Min;
@@ -9113,7 +9121,8 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im
viewport->BuildWorkInsetMax[axis] += axis_size;
}
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
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)); // Lift normal size constraint
bool is_open = Begin(name, NULL, window_flags);
@@ -9127,6 +9136,9 @@ bool ImGui::BeginMainMenuBar()
ImGuiContext& g = *GImGui;
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
// Notify of viewport change so GetFrameHeight() can be accurate in case of DPI change
SetCurrentViewport(NULL, viewport);
// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
// FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea?
// FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings.
@@ -9184,7 +9196,7 @@ static bool IsRootOfOpenMenuSet()
const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)
return false;
return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true);
return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true, false);
}
bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
@@ -9529,8 +9541,10 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarCalcMaxTabWidth() [Internal]
// - TabBarFindTabById() [Internal]
// - TabBarFindTabByOrder() [Internal]
// - TabBarFindMostRecentlySelectedTabForActiveWindow() [Internal]
// - TabBarGetCurrentTab() [Internal]
// - TabBarGetTabName() [Internal]
// - TabBarAddTab() [Internal]
// - TabBarRemoveTab() [Internal]
// - TabBarCloseTab() [Internal]
// - TabBarScrollClamp() [Internal]
@@ -9647,7 +9661,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
return false;
IM_ASSERT(tab_bar->ID != 0);
if ((flags & ImGuiTabBarFlags_DockNode) == 0)
if ((flags & ImGuiTabBarFlags_DockNode) == 0) // Already done
PushOverrideID(tab_bar->ID);
// Add to stack
@@ -9666,7 +9680,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
// Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable
if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
if ((flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
tab_bar->TabsAddedNew = false;
// Flags
@@ -9729,7 +9744,7 @@ void ImGui::EndTabBar()
window->DC.CursorPos = tab_bar->BackupCursorPos;
tab_bar->LastTabItemIdx = -1;
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) // Already done
PopID();
g.CurrentTabBarStack.pop_back();
@@ -9971,6 +9986,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_to_tab_id = g.NavWindowingTarget->TabId;
// Apply request requests
if (scroll_to_tab_id != 0)
TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);
@@ -10016,11 +10035,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack.
static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window)
{
IM_ASSERT(docked_window == NULL); // master branch only
IM_UNUSED(docked_window);
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
if (docked_window != NULL)
{
ImGuiID id = ImHashStr(label);
IM_UNUSED(tab_bar);
IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
ImGuiID id = docked_window->TabId;
KeepAliveID(id);
return id;
}
@@ -10054,6 +10073,20 @@ ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order)
return &tab_bar->Tabs[order];
}
// 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;
}
ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
{
if (tab_bar->LastTabItemIdx < 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)
@@ -10063,12 +10096,35 @@ ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
if (tab->Window)
return tab->Window->Name;
if (tab->NameOffset == -1)
return "N/A";
IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);
return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
}
// 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->TabId) == 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)
if (!window->HasCloseButton)
tab_flags |= ImGuiTabItemFlags_NoCloseButton; // Set _NoCloseButton immediately because it will be used for first-frame width calculation.
ImGuiTabItem new_tab;
new_tab.ID = window->TabId;
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 are 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)
{
@@ -10470,11 +10526,14 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;
tab->LastFrameVisible = g.FrameCount;
tab->Flags = flags;
tab->Window = docked_window;
// Append name _WITH_ the zero-terminator
// (regular tabs are permitted in a DockNode tab bar, but window tabs not permitted in a non-DockNode tab bar)
if (docked_window != NULL)
{
IM_ASSERT(docked_window == NULL); // master branch only
IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
tab->NameOffset = -1;
}
else
{
@@ -10499,7 +10558,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;
@@ -10547,9 +10606,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
}
// Click to Select a tab
// Allow the close button to overlap
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
if (g.DragDropActive)
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) // FIXME: May be an opt-in property of the payload to disable this
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
bool hovered, held, pressed;
if (flags & ImGuiTabItemFlags_Invisible)
@@ -10559,21 +10617,74 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
if (pressed && !is_tab_button)
TabBarQueueFocus(tab_bar, tab);
// Drag and drop: re-order tabs
if (held && !tab_appearing && IsMouseDragging(0))
// Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow()
// will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id.
if (held && docked_window && g.ActiveId == id && g.ActiveIdIsJustActivated)
g.ActiveIdWindow = docked_window;
// 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
int drag_dir = 0;
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_dir = -1;
drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x;
TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);
}
else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)
{
drag_dir = +1;
drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x;
TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);
}
}
// Extract a Dockable window out of it's tab bar
const bool can_undock = docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove) && !(node->MergedFlags & ImGuiDockNodeFlags_NoUndocking);
if (can_undock)
{
// 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_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;
if (drag_distance_from_edge_x > threshold_x)
if ((drag_dir < 0 && TabBarGetTabOrder(tab_bar, tab) == 0) || (drag_dir > 0 && TabBarGetTabOrder(tab_bar, tab) == tab_bar->Tabs.Size - 1))
undocking_tab = true;
}
if (undocking_tab)
{
// Undock
// FIXME: refactor to share more code with e.g. StartMouseMovingWindow
DockContextQueueUndockWindow(&g, docked_window);
g.MovingWindow = docked_window;
SetActiveID(g.MovingWindow->MoveId, g.MovingWindow);
g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
g.ActiveIdNoClearOnFocusLoss = true;
SetActiveIdUsingAllKeyboardKeys();
}
}
}
#if 0
@@ -10622,7 +10733,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
// Render tab label, process close button
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0;
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0;
bool just_closed;
bool text_clipped;
TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
@@ -10632,6 +10743,11 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
TabBarCloseTab(tab_bar, tab);
}
// Forward Hovered state so IsItemHovered() after Begin() can work (even though we are technically hovering our parent)
// That state is copied to window->DockTabItemStatusFlags by our caller.
if (docked_window && (hovered || g.HoveredId == close_button_id))
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
// Tooltip
// (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok)
// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
@@ -10667,6 +10783,16 @@ void ImGui::SetTabItemClosed(const char* label)
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
tab->WantClose = true; // Will be processed by next call to TabBarLayout()
}
else if (ImGuiWindow* window = FindWindowByName(label))
{
if (window->DockIsActive)
if (ImGuiDockNode* node = window->DockNode)
{
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label, window);
TabBarRemoveTab(node->TabBar, tab_id);
window->DockTabWantClose = true;
}
}
}
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker)
@@ -10681,10 +10807,9 @@ ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsave
return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y);
}
ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*)
ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window)
{
IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch.
return ImVec2(0.0f, 0.0f);
return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
}
void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)