Updated ImGui.

This commit is contained in:
Бранимир Караџић
2020-09-05 12:00:13 -07:00
parent 248d56709e
commit 6e3e2836c9
4 changed files with 173 additions and 134 deletions

View File

@@ -843,6 +843,7 @@ static void NavUpdate();
static void NavUpdateWindowing();
static void NavUpdateWindowingOverlay();
static void NavUpdateMoveResult();
static void NavUpdateInitResult();
static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static void NavEndFrame();
@@ -5250,6 +5251,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
ImGuiWindowFlags flags = window->Flags;
// Ensure that ScrollBar doesn't read last frame's SkipItems
IM_ASSERT(window->BeginCount == 0);
window->SkipItems = false;
// Draw window + handle manual resize
@@ -6031,37 +6033,41 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->BeginCount++;
g.NextWindowData.ClearFlags();
if (flags & ImGuiWindowFlags_ChildWindow)
// Update visibility
if (first_begin_of_the_frame)
{
// Child window can be out of sight and have "negative" clip windows.
// Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
window->HiddenFramesCanSkipItems = 1;
if (flags & ImGuiWindowFlags_ChildWindow)
{
// Child window can be out of sight and have "negative" clip windows.
// Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
window->HiddenFramesCanSkipItems = 1;
// Hide along with parent or if parent is collapsed
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
// Hide along with parent or if parent is collapsed
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
window->HiddenFramesCanSkipItems = 1;
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
window->HiddenFramesCannotSkipItems = 1;
}
// Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
if (style.Alpha <= 0.0f)
window->HiddenFramesCanSkipItems = 1;
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
window->HiddenFramesCannotSkipItems = 1;
// Update the Hidden flag
window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
// Update the SkipItems flag, used to early out of all items functions (no layout required)
bool skip_items = false;
if (window->Collapsed || !window->Active || window->Hidden)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
skip_items = true;
window->SkipItems = skip_items;
}
// Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
if (style.Alpha <= 0.0f)
window->HiddenFramesCanSkipItems = 1;
// Update the Hidden flag
window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
// Update the SkipItems flag, used to early out of all items functions (no layout required)
bool skip_items = false;
if (window->Collapsed || !window->Active || window->Hidden)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
skip_items = true;
window->SkipItems = skip_items;
return !skip_items;
return !window->SkipItems;
}
void ImGui::End()
@@ -7359,21 +7365,42 @@ void ImGui::EndGroup()
// [SECTION] SCROLLING
//-----------------------------------------------------------------------------
// Helper to snap on edges when aiming at an item very close to the edge,
// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
// When we refactor the scrolling API this may be configurable with a flag?
// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
{
if (target <= snap_min + snap_threshold)
return ImLerp(snap_min, target, center_ratio);
if (target >= snap_max - snap_threshold)
return ImLerp(target, snap_max, center_ratio);
return target;
}
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
{
ImVec2 scroll = window->Scroll;
if (window->ScrollTarget.x < FLT_MAX)
{
float cr_x = window->ScrollTargetCenterRatio.x;
float target_x = window->ScrollTarget.x;
scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
float center_x_ratio = window->ScrollTargetCenterRatio.x;
float scroll_target_x = window->ScrollTarget.x;
float snap_x_min = 0.0f;
float snap_x_max = window->ScrollMax.x + window->Size.x;
if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x);
}
if (window->ScrollTarget.y < FLT_MAX)
{
float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
float cr_y = window->ScrollTargetCenterRatio.y;
float target_y = window->ScrollTarget.y;
scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
float center_y_ratio = window->ScrollTargetCenterRatio.y;
float scroll_target_y = window->ScrollTarget.y;
float snap_y_min = 0.0f;
float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height;
if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
}
scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
@@ -7439,47 +7466,57 @@ float ImGui::GetScrollMaxY()
return window->ScrollMax.y;
}
void ImGui::SetScrollX(float scroll_x)
void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
{
ImGuiWindow* window = GetCurrentWindow();
window->ScrollTarget.x = scroll_x;
window->ScrollTargetCenterRatio.x = 0.0f;
window->ScrollTargetEdgeSnapDist.x = 0.0f;
}
void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
{
window->ScrollTarget.y = scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
window->ScrollTargetEdgeSnapDist.y = 0.0f;
}
void ImGui::SetScrollX(float scroll_x)
{
ImGuiContext& g = *GImGui;
SetScrollX(g.CurrentWindow, scroll_x);
}
void ImGui::SetScrollY(float scroll_y)
{
ImGuiWindow* window = GetCurrentWindow();
window->ScrollTarget.y = scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
ImGuiContext& g = *GImGui;
SetScrollY(g.CurrentWindow, scroll_y);
}
void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x)
{
window->ScrollTarget.x = new_scroll_x;
window->ScrollTargetCenterRatio.x = 0.0f;
}
void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y)
{
window->ScrollTarget.y = new_scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
}
// Note that a local position will vary depending on initial scroll value
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
// Note that a local position will vary depending on initial scroll value,
// This is a little bit confusing so bear with us:
// - local_pos = (absolution_pos - window->Pos)
// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
// - They mostly exists because of legacy API.
// Following the rules above, when trying to work with scrolling code, consider that:
// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size
void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
{
IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x);
window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset
window->ScrollTargetCenterRatio.x = center_x_ratio;
window->ScrollTargetEdgeSnapDist.x = 0.0f;
}
void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
{
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect
window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y);
window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset
window->ScrollTargetCenterRatio.y = center_y_ratio;
window->ScrollTargetEdgeSnapDist.y = 0.0f;
}
void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
@@ -7494,34 +7531,17 @@ void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
}
// Tweak: snap on edges when aiming at an item very close to the edge,
// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
// When we refactor the scrolling API this may be configurable with a flag?
// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
static float CalcScrollSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
{
if (target <= snap_min + snap_threshold)
return ImLerp(snap_min, target, center_ratio);
if (target >= snap_max - snap_threshold)
return ImLerp(target, snap_max, center_ratio);
return target;
}
// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
void ImGui::SetScrollHereX(float center_x_ratio)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float spacing_x = g.Style.ItemSpacing.x;
float target_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
// Tweak: snap on edges when aiming at an item very close to the edge
const float snap_x_threshold = ImMax(0.0f, window->WindowPadding.x - spacing_x);
const float snap_x_min = window->DC.CursorStartPos.x - window->WindowPadding.x;
const float snap_x_max = window->DC.CursorStartPos.x + window->ContentSize.x + window->WindowPadding.x;
target_x = CalcScrollSnap(target_x, snap_x_min, snap_x_max, snap_x_threshold, center_x_ratio);
SetScrollFromPosX(window, target_x - window->Pos.x, center_x_ratio);
window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
}
// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
@@ -7530,15 +7550,11 @@ void ImGui::SetScrollHereY(float center_y_ratio)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float spacing_y = g.Style.ItemSpacing.y;
float target_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
// Tweak: snap on edges when aiming at an item very close to the edge
const float snap_y_threshold = ImMax(0.0f, window->WindowPadding.y - spacing_y);
const float snap_y_min = window->DC.CursorStartPos.y - window->WindowPadding.y;
const float snap_y_max = window->DC.CursorStartPos.y + window->ContentSize.y + window->WindowPadding.y;
target_y = CalcScrollSnap(target_y, snap_y_min, snap_y_max, snap_y_threshold, center_y_ratio);
SetScrollFromPosY(window, target_y - window->Pos.y, center_y_ratio);
window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
}
//-----------------------------------------------------------------------------
@@ -8441,7 +8457,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
init_for_nav = true;
//IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
if (init_for_nav)
{
SetNavID(0, g.NavLayer, 0);
@@ -8563,17 +8579,8 @@ static void ImGui::NavUpdate()
io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f;
// Process navigation init request (select first/default focus)
// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow)
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
//IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
if (g.NavInitRequestFromMove)
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
else
SetNavID(g.NavInitResultId, g.NavLayer, 0);
g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
}
if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
NavUpdateInitResult();
g.NavInitRequest = false;
g.NavInitRequestFromMove = false;
g.NavInitResultId = 0;
@@ -8626,6 +8633,7 @@ static void ImGui::NavUpdate()
// Process NavCancel input (to close a popup, get back to parent, clear focus)
if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
{
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
if (g.ActiveId != 0)
{
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
@@ -8711,6 +8719,7 @@ static void ImGui::NavUpdate()
// (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
}
@@ -8729,7 +8738,7 @@ static void ImGui::NavUpdate()
}
if (g.NavMoveRequest && g.NavId == 0)
{
//IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true;
// Reassigning with same value, we're being explicit here.
g.NavInitResultId = 0; // -V1048
@@ -8774,6 +8783,7 @@ static void ImGui::NavUpdate()
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
float pad = window->CalcFontSize() * 0.5f;
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
@@ -8800,6 +8810,22 @@ static void ImGui::NavUpdate()
#endif
}
static void ImGui::NavUpdateInitResult()
{
// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
ImGuiContext& g = *GImGui;
if (!g.NavWindow)
return;
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
if (g.NavInitRequestFromMove)
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
else
SetNavID(g.NavInitResultId, g.NavLayer, 0);
g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
}
// Apply result from previous frame navigation directional move request
static void ImGui::NavUpdateMoveResult()
{
@@ -8859,6 +8885,7 @@ static void ImGui::NavUpdateMoveResult()
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
}
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
}
@@ -10506,8 +10533,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
ImGui::PushID(tab);
if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine();
if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "");
ImGui::PopID();
}

View File

@@ -4209,9 +4209,9 @@ struct ExampleAppConsole
}
ImGui::TextWrapped(
"This example implements a console with basic coloring, completion and history. A more elaborate "
"This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
"implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
ImGui::TextWrapped("Enter 'HELP' for help.");
// TODO: display items starting from the bottom

View File

@@ -163,7 +163,9 @@ namespace ImStb
// Debug Logging for selected systems. Remove the '((void)0) //' to enable.
//#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log
//#define IMGUI_DEBUG_LOG_NAV IMGUI_DEBUG_LOG // Enable log
#define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log
#define IMGUI_DEBUG_LOG_NAV(...) ((void)0) // Disable log
// Static Asserts
#if (__cplusplus >= 201100)
@@ -1583,6 +1585,7 @@ struct IMGUI_API ImGuiWindow
ImVec2 ScrollMax;
ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold
ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar.
bool ScrollbarX, ScrollbarY; // Are scrollbars visible?
bool Active; // Set to true on Begin(), unless Collapsed
@@ -1731,8 +1734,8 @@ struct ImGuiTabBar
int PrevFrameVisible;
ImRect BarRect;
float LastTabContentHeight; // Record the height of contents submitted below the tab bar
float OffsetMax; // Distance from BarRect.Min.x, locked during layout
float OffsetMaxIdeal; // Ideal offset if all tabs were visible and not clipped
float WidthAllTabs; // Actual width of all tabs (locked during layout)
float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped
float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set.
float ScrollingAnim;
float ScrollingTarget;
@@ -1824,10 +1827,10 @@ namespace ImGui
// Scrolling
IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is
IMGUI_API void SetScrollX(ImGuiWindow* window, float new_scroll_x);
IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y);
IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f);
IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f);
IMGUI_API void SetScrollX(ImGuiWindow* window, float scroll_x);
IMGUI_API void SetScrollY(ImGuiWindow* window, float scroll_y);
IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio);
IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio);
IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
// Basic Accessors
@@ -1931,7 +1934,8 @@ namespace ImGui
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar);
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags);
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button);
IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);

View File

@@ -3635,7 +3635,7 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)
*dst++ = c;
*dst = '\0';
if (CursorPos + bytes_count >= pos)
if (CursorPos >= pos + bytes_count)
CursorPos -= bytes_count;
else if (CursorPos >= pos)
CursorPos = pos;
@@ -6776,7 +6776,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarFindTabById() [Internal]
// - TabBarRemoveTab() [Internal]
// - TabBarCloseTab() [Internal]
// - TabBarScrollClamp()v
// - TabBarScrollClamp() [Internal]
// - TabBarScrollToTab() [Internal]
// - TabBarQueueChangeTabOrder() [Internal]
// - TabBarScrollingButtons() [Internal]
@@ -6800,7 +6800,7 @@ ImGuiTabBar::ImGuiTabBar()
SelectedTabId = NextSelectedTabId = VisibleTabId = 0;
CurrFrameVisible = PrevFrameVisible = -1;
LastTabContentHeight = 0.0f;
OffsetMax = OffsetMaxIdeal = OffsetNextTab = 0.0f;
WidthAllTabs = WidthAllTabsIdeal = OffsetNextTab = 0.0f;
ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f;
Flags = ImGuiTabBarFlags_None;
ReorderRequestTabId = 0;
@@ -6966,23 +6966,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Process order change request (we could probably process it when requested but it's just saner to do it in a single spot).
if (tab_bar->ReorderRequestTabId != 0)
{
if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId))
{
//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir;
if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size)
{
ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
ImGuiTabItem item_tmp = *tab1;
*tab1 = *tab2;
*tab2 = item_tmp;
if (tab2->ID == tab_bar->SelectedTabId)
scroll_track_selected_tab_id = tab2->ID;
tab1 = tab2 = NULL;
}
if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
MarkIniSettingsDirty();
}
if (TabBarProcessReorder(tab_bar))
if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId)
scroll_track_selected_tab_id = tab_bar->ReorderRequestTabId;
tab_bar->ReorderRequestTabId = 0;
}
@@ -7056,11 +7042,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x;
}
tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f);
tab_bar->WidthAllTabs = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
tab_bar->WidthAllTabsIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f);
// Horizontal scrolling buttons
const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
const bool scrolling_buttons = (tab_bar->WidthAllTabs > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
if (scrolling_buttons)
if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x!
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
@@ -7102,7 +7088,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame)
ImGuiWindow* window = g.CurrentWindow;
window->DC.CursorPos = tab_bar->BarRect.Min;
ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, 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.
@@ -7165,7 +7151,7 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling)
{
scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth());
scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth());
return ImMax(scrolling, 0.0f);
}
@@ -7189,7 +7175,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
}
}
void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir)
void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir)
{
IM_ASSERT(dir == -1 || dir == +1);
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
@@ -7197,6 +7183,28 @@ void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem*
tab_bar->ReorderRequestDir = (ImS8)dir;
}
bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
{
ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId);
if (!tab1)
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;
if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
return false;
ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
ImGuiTabItem item_tmp = *tab1;
*tab1 = *tab2;
*tab2 = item_tmp;
tab1 = tab2 = NULL;
if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
MarkIniSettingsDirty();
return true;
}
static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
{
ImGuiContext& g = *GImGui;
@@ -7308,7 +7316,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
ImGuiTabBar* tab_bar = g.CurrentTabBar;
if (tab_bar == NULL)
{
IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!");
IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!");
return false;
}
bool ret = TabItemEx(tab_bar, label, p_open, flags);
@@ -7330,7 +7338,7 @@ void ImGui::EndTabItem()
ImGuiTabBar* tab_bar = g.CurrentTabBar;
if (tab_bar == NULL)
{
IM_ASSERT(tab_bar != NULL && "Needs to be called between BeginTabBar() and EndTabBar()!");
IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!");
return;
}
IM_ASSERT(tab_bar->LastTabItemIdx >= 0);
@@ -7486,12 +7494,12 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)
{
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
TabBarQueueChangeTabOrder(tab_bar, tab, -1);
TabBarQueueReorder(tab_bar, tab, -1);
}
else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)
{
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
TabBarQueueChangeTabOrder(tab_bar, tab, +1);
TabBarQueueReorder(tab_bar, tab, +1);
}
}
}