mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-12 02:00:58 +01:00
Internals: Docking, Tab Bar: Add DockNodeBeginAmendTabBar() and work toward making hybrid dock node with windows tab bars somehow work (not done).
This commit is contained in:
parent
bae2240eda
commit
b26f1530b7
44
imgui.cpp
44
imgui.cpp
@ -12510,6 +12510,8 @@ bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode*
|
|||||||
// - DockNodeStartMouseMovingWindow()
|
// - DockNodeStartMouseMovingWindow()
|
||||||
// - DockNodeUpdate()
|
// - DockNodeUpdate()
|
||||||
// - DockNodeUpdateWindowMenu()
|
// - DockNodeUpdateWindowMenu()
|
||||||
|
// - DockNodeBeginAmendTabBar()
|
||||||
|
// - DockNodeEndAmendTabBar()
|
||||||
// - DockNodeUpdateTabBar()
|
// - DockNodeUpdateTabBar()
|
||||||
// - DockNodeAddTabBar()
|
// - DockNodeAddTabBar()
|
||||||
// - DockNodeRemoveTabBar()
|
// - DockNodeRemoveTabBar()
|
||||||
@ -13231,7 +13233,8 @@ static ImGuiID ImGui::DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar*
|
|||||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||||
{
|
{
|
||||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||||
IM_ASSERT(tab->Window != NULL);
|
if (tab->Window == NULL)
|
||||||
|
continue;
|
||||||
if (Selectable(tab->Window->Name, tab->ID == tab_bar->SelectedTabId))
|
if (Selectable(tab->Window->Name, tab->ID == tab_bar->SelectedTabId))
|
||||||
ret_tab_id = tab->ID;
|
ret_tab_id = tab->ID;
|
||||||
SameLine();
|
SameLine();
|
||||||
@ -13243,6 +13246,26 @@ static ImGuiID ImGui::DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar*
|
|||||||
return ret_tab_id;
|
return ret_tab_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User helper to append/amend into a dock node tab bar. Most commonly used to add e.g. a "+" button.
|
||||||
|
bool ImGui::DockNodeBeginAmendTabBar(ImGuiDockNode* node)
|
||||||
|
{
|
||||||
|
if (node->TabBar == NULL || node->HostWindow == NULL)
|
||||||
|
return false;
|
||||||
|
Begin(node->HostWindow->Name);
|
||||||
|
PushOverrideID(node->ID);
|
||||||
|
bool ret = BeginTabBarEx(node->TabBar, node->TabBar->BarRect, node->TabBar->Flags, node);
|
||||||
|
IM_ASSERT(ret);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui::DockNodeEndAmendTabBar()
|
||||||
|
{
|
||||||
|
EndTabBar();
|
||||||
|
PopID();
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit the tab bar corresponding to a dock node and various housekeeping details.
|
||||||
static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window)
|
static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@ -13446,7 +13469,14 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
|
|||||||
if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id)
|
if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id)
|
||||||
{
|
{
|
||||||
bool held;
|
bool held;
|
||||||
ButtonBehavior(title_bar_rect, title_bar_id, NULL, &held);
|
ButtonBehavior(title_bar_rect, title_bar_id, NULL, &held, ImGuiButtonFlags_AllowItemOverlap);
|
||||||
|
if (g.HoveredId == title_bar_id)
|
||||||
|
{
|
||||||
|
// ImGuiButtonFlags_AllowItemOverlap + SetItemAllowOverlap() required for appending into dock node tab bar,
|
||||||
|
// otherwise dragging window will steal HoveredId and amended tabs cannot get them.
|
||||||
|
host_window->DC.LastItemId = title_bar_id;
|
||||||
|
SetItemAllowOverlap();
|
||||||
|
}
|
||||||
if (held)
|
if (held)
|
||||||
{
|
{
|
||||||
if (IsMouseClicked(0))
|
if (IsMouseClicked(0))
|
||||||
@ -15847,13 +15877,13 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|||||||
const char* buf_end = buf + IM_ARRAYSIZE(buf);
|
const char* buf_end = buf + IM_ARRAYSIZE(buf);
|
||||||
const bool is_active = (tab_bar->PrevFrameVisible >= ImGui::GetFrameCount() - 2);
|
const bool is_active = (tab_bar->PrevFrameVisible >= ImGui::GetFrameCount() - 2);
|
||||||
p += ImFormatString(p, buf_end - p, "Tab Bar 0x%08X (%d tabs)%s", tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
|
p += ImFormatString(p, buf_end - p, "Tab Bar 0x%08X (%d tabs)%s", tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
|
||||||
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
|
|
||||||
{
|
|
||||||
p += ImFormatString(p, buf_end - p, " { ");
|
p += ImFormatString(p, buf_end - p, " { ");
|
||||||
for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)
|
for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)
|
||||||
p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", tab_bar->Tabs[tab_n].Window->Name);
|
{
|
||||||
p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
|
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||||
|
p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???");
|
||||||
}
|
}
|
||||||
|
p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
|
||||||
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
||||||
bool open = ImGui::TreeNode(tab_bar, "%s", buf);
|
bool open = ImGui::TreeNode(tab_bar, "%s", buf);
|
||||||
if (!is_active) { PopStyleColor(); }
|
if (!is_active) { PopStyleColor(); }
|
||||||
@ -15872,7 +15902,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|||||||
ImGui::PushID(tab);
|
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(0, 2);
|
||||||
if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
|
if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
|
||||||
ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth);
|
ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???", tab->Offset, tab->Width, tab->ContentWidth);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
@ -2170,6 +2170,8 @@ namespace ImGui
|
|||||||
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
|
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
|
||||||
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
|
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
|
||||||
IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos);
|
IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos);
|
||||||
|
IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode* node);
|
||||||
|
IMGUI_API void DockNodeEndAmendTabBar();
|
||||||
inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
|
inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
|
||||||
inline int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
|
inline int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
|
||||||
inline ImGuiDockNode* GetWindowDockNode() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockNode; }
|
inline ImGuiDockNode* GetWindowDockNode() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockNode; }
|
||||||
|
@ -6824,7 +6824,7 @@ struct ImGuiTabBarSection
|
|||||||
namespace ImGui
|
namespace ImGui
|
||||||
{
|
{
|
||||||
static void TabBarLayout(ImGuiTabBar* tab_bar);
|
static void TabBarLayout(ImGuiTabBar* tab_bar);
|
||||||
static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label);
|
static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window);
|
||||||
static float TabBarCalcMaxTabWidth();
|
static float TabBarCalcMaxTabWidth();
|
||||||
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
|
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
|
||||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections);
|
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections);
|
||||||
@ -6918,7 +6918,7 @@ 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
|
// 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)))
|
if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
|
||||||
if (tab_bar->Tabs.Size > 1 && (flags & ImGuiTabBarFlags_DockNode) == 0)
|
if (tab_bar->Tabs.Size > 1 && (flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid
|
||||||
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
|
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
|
||||||
tab_bar->TabsAddedNew = false;
|
tab_bar->TabsAddedNew = false;
|
||||||
|
|
||||||
@ -7177,6 +7177,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||||||
{
|
{
|
||||||
ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];
|
ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];
|
||||||
tab->Offset = tab_offset;
|
tab->Offset = tab_offset;
|
||||||
|
tab->NameOffset = -1;
|
||||||
tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f);
|
tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||||
}
|
}
|
||||||
tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f);
|
tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f);
|
||||||
@ -7184,6 +7185,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||||||
section_tab_index += section->TabCount;
|
section_tab_index += section->TabCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear name buffers
|
||||||
|
tab_bar->TabsNames.Buf.resize(0);
|
||||||
|
|
||||||
// If we have lost the selected tab, select the next most recently active one
|
// If we have lost the selected tab, select the next most recently active one
|
||||||
if (found_selected_tab_id == false)
|
if (found_selected_tab_id == false)
|
||||||
tab_bar->SelectedTabId = 0;
|
tab_bar->SelectedTabId = 0;
|
||||||
@ -7220,21 +7224,18 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||||||
tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing;
|
tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing;
|
||||||
tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing;
|
tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing;
|
||||||
|
|
||||||
// Clear name buffers
|
|
||||||
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
|
|
||||||
tab_bar->TabsNames.Buf.resize(0);
|
|
||||||
|
|
||||||
// Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame)
|
// Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame)
|
||||||
ImGuiWindow* window = g.CurrentWindow;
|
ImGuiWindow* window = g.CurrentWindow;
|
||||||
window->DC.CursorPos = tab_bar->BarRect.Min;
|
window->DC.CursorPos = tab_bar->BarRect.Min;
|
||||||
ItemSize(ImVec2(tab_bar->WidthAllTabsIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y);
|
ItemSize(ImVec2(tab_bar->WidthAllTabsIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack.
|
// Dockable uses Name/ID in the global namespace. Non-dockable items use the ID stack.
|
||||||
static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label)
|
static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window)
|
||||||
{
|
{
|
||||||
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
|
if (docked_window != NULL)
|
||||||
{
|
{
|
||||||
|
IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
|
||||||
ImGuiID id = ImHashStr(label);
|
ImGuiID id = ImHashStr(label);
|
||||||
KeepAliveID(id);
|
KeepAliveID(id);
|
||||||
return id;
|
return id;
|
||||||
@ -7581,7 +7582,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const ImGuiStyle& style = g.Style;
|
const ImGuiStyle& style = g.Style;
|
||||||
const ImGuiID id = TabBarCalcTabID(tab_bar, label);
|
const ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window);
|
||||||
|
|
||||||
// If the user called us with *p_open == false, we early out and don't render.
|
// If the user called us with *p_open == false, we early out and don't render.
|
||||||
// We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
|
// We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
|
||||||
@ -7631,9 +7632,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|||||||
tab->Window = docked_window;
|
tab->Window = docked_window;
|
||||||
|
|
||||||
// Append name with zero-terminator
|
// Append name with zero-terminator
|
||||||
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
|
// (regular tabs are permitted in a DockNode tab bar, but window tabs not permitted in a non-DockNode tab bar)
|
||||||
|
if (tab->Window != NULL)
|
||||||
{
|
{
|
||||||
IM_ASSERT(tab->Window != NULL);
|
IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
|
||||||
tab->NameOffset = -1;
|
tab->NameOffset = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -7851,7 +7853,7 @@ void ImGui::SetTabItemClosed(const char* label)
|
|||||||
if (is_within_manual_tab_bar)
|
if (is_within_manual_tab_bar)
|
||||||
{
|
{
|
||||||
ImGuiTabBar* tab_bar = g.CurrentTabBar;
|
ImGuiTabBar* tab_bar = g.CurrentTabBar;
|
||||||
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
|
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL);
|
||||||
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
|
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
|
||||||
tab->WantClose = true; // Will be processed by next call to TabBarLayout()
|
tab->WantClose = true; // Will be processed by next call to TabBarLayout()
|
||||||
}
|
}
|
||||||
@ -7860,7 +7862,7 @@ void ImGui::SetTabItemClosed(const char* label)
|
|||||||
if (window->DockIsActive)
|
if (window->DockIsActive)
|
||||||
if (ImGuiDockNode* node = window->DockNode)
|
if (ImGuiDockNode* node = window->DockNode)
|
||||||
{
|
{
|
||||||
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label);
|
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label, window);
|
||||||
TabBarRemoveTab(node->TabBar, tab_id);
|
TabBarRemoveTab(node->TabBar, tab_id);
|
||||||
window->DockTabWantClose = true;
|
window->DockTabWantClose = true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user