mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-27 16:29:02 +08:00
Tab Bar: Further simplification of section/clip rect handling. (#3291)
This commit is contained in:
parent
6b76781c66
commit
1ec464eb9a
@ -10563,10 +10563,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
|
||||
draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
|
||||
if (tab_bar->Sections[0].Width > 0.0f)
|
||||
draw_list->AddLine(ImVec2(tab_bar->BarRect.Min.x + tab_bar->Sections[0].Width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Min.x + tab_bar->Sections[0].Width, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
if (tab_bar->Sections[2].Width > 0.0f)
|
||||
draw_list->AddLine(ImVec2(tab_bar->BarRect.Max.x - tab_bar->Sections[2].Width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x - tab_bar->Sections[2].Width, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
}
|
||||
if (open)
|
||||
{
|
||||
|
@ -1725,16 +1725,6 @@ struct ImGuiTabItem
|
||||
ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; IndexDuringLayout = -1; WantClose = false; }
|
||||
};
|
||||
|
||||
struct ImGuiTabBarSection
|
||||
{
|
||||
int TabStartIndex; // Index of first tab in this section.
|
||||
int TabCount; // Number of tabs in this section.
|
||||
float Width; // Sum of width of tabs in this section (after shrinking down)
|
||||
float Spacing; // Horizontal spacing at the end of the section.
|
||||
|
||||
ImGuiTabBarSection(){ memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Storage for a tab bar (sizeof() 92~96 bytes)
|
||||
struct ImGuiTabBar
|
||||
{
|
||||
@ -1753,6 +1743,8 @@ struct ImGuiTabBar
|
||||
float ScrollingTarget;
|
||||
float ScrollingTargetDistToVisibility;
|
||||
float ScrollingSpeed;
|
||||
float ScrollingRectMinX;
|
||||
float ScrollingRectMaxX;
|
||||
ImGuiTabBarFlags Flags;
|
||||
ImGuiID ReorderRequestTabId;
|
||||
ImS8 ReorderRequestDir;
|
||||
@ -1762,7 +1754,6 @@ struct ImGuiTabBar
|
||||
bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame
|
||||
short LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem()
|
||||
ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar()
|
||||
ImGuiTabBarSection Sections[3]; // Layout sections: Leading, Central, Trailing
|
||||
ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer.
|
||||
|
||||
ImGuiTabBar();
|
||||
|
@ -6801,13 +6801,22 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
|
||||
// - TabBarTabListPopupButton() [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiTabBarSection
|
||||
{
|
||||
int TabCount; // Number of tabs in this section.
|
||||
float Width; // Sum of width of tabs in this section (after shrinking down)
|
||||
float Spacing; // Horizontal spacing at the end of the section.
|
||||
|
||||
ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
static void TabBarLayout(ImGuiTabBar* tab_bar);
|
||||
static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label);
|
||||
static float TabBarCalcMaxTabWidth();
|
||||
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
|
||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections);
|
||||
static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);
|
||||
static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);
|
||||
}
|
||||
@ -6820,6 +6829,7 @@ ImGuiTabBar::ImGuiTabBar()
|
||||
LastTabContentHeight = 0.0f;
|
||||
WidthAllTabs = WidthAllTabsIdeal = 0.0f;
|
||||
ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f;
|
||||
ScrollingRectMinX = ScrollingRectMaxX = 0.0f;
|
||||
Flags = ImGuiTabBarFlags_None;
|
||||
ReorderRequestTabId = 0;
|
||||
ReorderRequestDir = 0;
|
||||
@ -6860,12 +6870,6 @@ static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
|
||||
return ImGuiPtrOrIndex(tab_bar);
|
||||
}
|
||||
|
||||
static ImVec2 GetTabBarScrollingButtonSize()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return ImVec2(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f);
|
||||
}
|
||||
|
||||
bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -6969,14 +6973,13 @@ void ImGui::EndTabBar()
|
||||
static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTabBarSection* sections = tab_bar->Sections;
|
||||
tab_bar->WantLayout = false;
|
||||
|
||||
// Garbage collect by compacting list
|
||||
// Detect if we need to sort out tab list (e.g. in rare case where a tab changed section)
|
||||
int tab_dst_n = 0;
|
||||
bool need_sort_by_section = false;
|
||||
sections[0].TabCount = sections[1].TabCount = sections[2].TabCount = 0;
|
||||
ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing
|
||||
for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];
|
||||
@ -7015,13 +7018,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
// Calculate spacing between sections
|
||||
sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;
|
||||
sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;
|
||||
sections[2].Spacing = 0.0f;
|
||||
sections[0].TabStartIndex = 0;
|
||||
sections[1].TabStartIndex = sections[0].TabStartIndex + sections[0].TabCount;
|
||||
sections[2].TabStartIndex = sections[1].TabStartIndex + sections[1].TabCount;
|
||||
sections[0].Width = 0.0f;
|
||||
sections[1].Width = 0.0f;
|
||||
sections[2].Width = 0.0f;
|
||||
|
||||
// Setup next selected tab
|
||||
ImGuiID scroll_track_selected_tab_id = 0;
|
||||
@ -7054,6 +7050,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
|
||||
// Compute ideal tabs widths + store them into shrink buffer
|
||||
ImGuiTabItem* most_recently_selected_tab = NULL;
|
||||
int curr_section_n = -1;
|
||||
bool found_selected_tab_id = false;
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
@ -7076,7 +7073,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
|
||||
int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
section->Width += tab->ContentWidth + (tab_n > section->TabStartIndex ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||
section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||
curr_section_n = section_n;
|
||||
|
||||
// Store data so we can build an array sorted by width if we need to shrink tabs down
|
||||
int shrink_buffer_index = shrink_buffer_indexes[section_n]++;
|
||||
@ -7135,23 +7133,24 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
}
|
||||
|
||||
// Layout all active tabs
|
||||
float next_tab_offset = 0.0f;
|
||||
int section_tab_index = 0;
|
||||
float tab_offset = 0.0f;
|
||||
tab_bar->WidthAllTabs = 0.0f;
|
||||
for (int section_n = 0; section_n < 3; section_n++)
|
||||
{
|
||||
// FIXME: The +1.0f is in TabBarScrollingButtons()
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
if (section_n == 2)
|
||||
next_tab_offset = ImMin(tab_bar->BarRect.GetWidth() - section->Width, next_tab_offset);
|
||||
tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset);
|
||||
|
||||
for (int tab_n = 0; tab_n < section->TabCount; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[section->TabStartIndex + tab_n];
|
||||
tab->Offset = next_tab_offset;
|
||||
next_tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];
|
||||
tab->Offset = tab_offset;
|
||||
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);
|
||||
next_tab_offset += section->Spacing;
|
||||
tab_offset += section->Spacing;
|
||||
section_tab_index += section->TabCount;
|
||||
}
|
||||
|
||||
// If we have lost the selected tab, select the next most recently active one
|
||||
@ -7167,7 +7166,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
// Update scrolling
|
||||
if (scroll_track_selected_tab_id)
|
||||
if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id))
|
||||
TabBarScrollToTab(tab_bar, scroll_track_selected_tab);
|
||||
TabBarScrollToTab(tab_bar, scroll_track_selected_tab, sections);
|
||||
tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);
|
||||
tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);
|
||||
if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
|
||||
@ -7183,6 +7182,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
tab_bar->ScrollingSpeed = 0.0f;
|
||||
}
|
||||
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;
|
||||
|
||||
// Clear name buffers
|
||||
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
@ -7264,13 +7265,12 @@ static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling)
|
||||
return ImMax(scrolling, 0.0f);
|
||||
}
|
||||
|
||||
static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections)
|
||||
{
|
||||
if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))
|
||||
return;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTabBarSection* sections = tab_bar->Sections;
|
||||
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
|
||||
int order = tab_bar->GetTabOrder(tab);
|
||||
|
||||
@ -7336,7 +7336,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
const ImVec2 arrow_button_size = GetTabBarScrollingButtonSize();
|
||||
const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f);
|
||||
const float scrolling_buttons_width = arrow_button_size.x * 2.0f;
|
||||
|
||||
const ImVec2 backup_cursor_pos = window->DC.CursorPos;
|
||||
@ -7605,21 +7605,19 @@ 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;
|
||||
size.x = tab->Width;
|
||||
if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
|
||||
else
|
||||
if (is_central_section)
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
|
||||
else
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bb(pos, pos + size);
|
||||
|
||||
// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)
|
||||
// Leading buttons will be clipped by BarRect.Max.x, Trailing buttons will be clipped at BarRect.Min.x + LeadingsWidth (+ spacing if there are some buttons), and central tabs will be clipped inbetween
|
||||
float offset_trailing = (flags & (ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_Leading)) ? 0.0f : tab_bar->Sections[2].Width + tab_bar->Sections[1].Spacing;
|
||||
float offset_leading = (flags & ImGuiTabItemFlags_Leading) ? 0.0f : tab_bar->Sections[0].Width + tab_bar->Sections[0].Spacing;
|
||||
bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x + offset_leading) || (bb.Max.x > tab_bar->BarRect.Max.x - offset_trailing);
|
||||
const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX);
|
||||
if (want_clip_rect)
|
||||
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x + offset_leading), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x - offset_trailing, bb.Max.y), true);
|
||||
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true);
|
||||
|
||||
ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;
|
||||
ItemSize(bb.GetSize(), style.FramePadding.y);
|
||||
|
Loading…
Reference in New Issue
Block a user