update Dear ImGui to 1.89.9

this is part of an upgrade process to the latest version of Dear ImGui
it will take a while as I am stepping through individual versions due
to the heavy modifications we've made for Furnace
This commit is contained in:
tildearrow 2025-08-09 20:45:33 -05:00
parent 0d1acc41bf
commit b3d60e512c
19 changed files with 596 additions and 409 deletions

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8
// dear imgui, v1.89.9
// (main code and documentation)
// Help:
@ -433,6 +433,7 @@ CODE
- likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2023/08/25 (1.89.9) - Clipper: Renamed IncludeRangeByIndices() (also called ForceDisplayRangeByIndices() before 1.89.6) to IncludeItemsByIndex(). Kept inline redirection function. Sorry!
- 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878)
- 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15).
- 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete).
@ -1191,7 +1192,7 @@ ImGuiStyle::ImGuiStyle()
FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
CellPadding = ImVec2(4,2); // Padding within a table cell
CellPadding = ImVec2(4,2); // Padding within a table cell. CellPadding.y may be altered between different rows.
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
@ -1338,6 +1339,7 @@ ImGuiIO::ImGuiIO()
// Note: Initialize() will setup default clipboard/ime handlers.
BackendPlatformName = BackendRendererName = NULL;
BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
PlatformLocaleDecimalPoint = '.';
// Input (NB: we already have memset zero the entire structure!)
MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
@ -1583,7 +1585,7 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
e.EventId = g.InputEventsNextEventId++;
e.MousePos.PosX = pos.x;
e.MousePos.PosY = pos.y;
e.MouseWheel.MouseSource = g.InputEventsNextMouseSource;
e.MousePos.MouseSource = g.InputEventsNextMouseSource;
g.InputEventsQueue.push_back(e);
}
@ -1607,7 +1609,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
e.EventId = g.InputEventsNextEventId++;
e.MouseButton.Button = mouse_button;
e.MouseButton.Down = down;
e.MouseWheel.MouseSource = g.InputEventsNextMouseSource;
e.MouseButton.MouseSource = g.InputEventsNextMouseSource;
g.InputEventsQueue.push_back(e);
}
@ -2622,16 +2624,15 @@ void ImGuiTextFilter::Build()
input_range.split(',', &Filters);
CountGrep = 0;
for (int i = 0; i != Filters.Size; i++)
for (ImGuiTextRange& f : Filters)
{
ImGuiTextRange& f = Filters[i];
while (f.b < f.e && ImCharIsBlankA(f.b[0]))
f.b++;
while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
f.e--;
if (f.empty())
continue;
if (Filters[i].b[0] != '-')
if (f.b[0] != '-')
CountGrep += 1;
}
}
@ -2644,9 +2645,8 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
if (text == NULL)
text = "";
for (int i = 0; i != Filters.Size; i++)
for (const ImGuiTextRange& f : Filters)
{
const ImGuiTextRange& f = Filters[i];
if (f.empty())
continue;
if (f.b[0] == '-')
@ -2934,7 +2934,7 @@ void ImGuiListClipper::End()
ItemsCount = -1;
}
void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end)
void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
{
ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.
@ -3035,26 +3035,28 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
// - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
// - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
// which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
for (int i = 0; i < data->Ranges.Size; i++)
if (data->Ranges[i].PosToIndexConvert)
for (ImGuiListClipperRange& range : data->Ranges)
if (range.PosToIndexConvert)
{
int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount);
data->Ranges[i].PosToIndexConvert = false;
int m1 = (int)(((double)range.Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
int m2 = (int)((((double)range.Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
range.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
range.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper->ItemsCount);
range.PosToIndexConvert = false;
}
ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
}
// Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
if (data->StepNo < data->Ranges.Size)
while (data->StepNo < data->Ranges.Size)
{
clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
if (clipper->DisplayStart > already_submitted) //-V1051
ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);
data->StepNo++;
if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)
continue;
return true;
}
@ -3646,13 +3648,12 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso
ImGuiContext& g = *GImGui;
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
for (int n = 0; n < g.Viewports.Size; n++)
for (ImGuiViewportP* viewport : g.Viewports)
{
// We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.
ImVec2 offset, size, uv[4];
if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
continue;
ImGuiViewportP* viewport = g.Viewports[n];
const ImVec2 pos = base_pos - offset;
const float scale = base_scale * viewport->DpiScale;
if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
@ -3737,6 +3738,7 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ ImGuiLocKey_WindowingPopup, "(Popup)" },
{ ImGuiLocKey_WindowingUntitled, "(Untitled)" },
{ ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
{ ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window."},
};
void ImGui::Initialize()
@ -3834,6 +3836,7 @@ void ImGui::Shutdown()
g.FontStack.clear();
g.OpenPopupStack.clear();
g.BeginPopupStack.clear();
g.NavTreeNodeStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
g.Viewports.clear_delete();
@ -3886,9 +3889,9 @@ void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
{
ImGuiContext& g = *ctx;
IM_ASSERT(hook_id != 0);
for (int n = 0; n < g.Hooks.Size; n++)
if (g.Hooks[n].HookId == hook_id)
g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_;
for (ImGuiContextHook& hook : g.Hooks)
if (hook.HookId == hook_id)
hook.Type = ImGuiContextHookType_PendingRemoval_;
}
// Call context hooks (used by e.g. test engine)
@ -3896,9 +3899,9 @@ void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
{
ImGuiContext& g = *ctx;
for (int n = 0; n < g.Hooks.Size; n++)
if (g.Hooks[n].Type == hook_type)
g.Hooks[n].Callback(&g, &g.Hooks[n]);
for (ImGuiContextHook& hook : g.Hooks)
if (hook.Type == hook_type)
hook.Callback(&g, &hook);
}
@ -4142,6 +4145,8 @@ void ImGui::MarkItemEdited(ImGuiID id)
// This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
ImGuiContext& g = *GImGui;
if (g.LockMarkEdited > 0)
return;
if (g.ActiveId == id || g.ActiveId == 0)
{
g.ActiveIdHasBeenEditedThisFrame = true;
@ -4267,7 +4272,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false;
// Test if using AllowOverlap and overlapped
if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0)
if ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0)
if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0)
if (g.HoveredIdPreviousFrame != g.LastItemData.ID)
return false;
@ -4335,7 +4340,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match.
// This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test.
if (item_flags & ImGuiItemflags_AllowOverlap)
if (item_flags & ImGuiItemFlags_AllowOverlap)
{
g.HoveredIdAllowOverlap = true;
if (g.HoveredIdPreviousFrame != id)
@ -4484,33 +4489,33 @@ int ImGui::GetFrameCount()
return GImGui->FrameCount;
}
static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
{
// Create the draw list on demand, because they are not frequently used for all viewports
ImGuiContext& g = *GImGui;
IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists));
ImDrawList* draw_list = viewport->DrawLists[drawlist_no];
IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists));
ImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no];
if (draw_list == NULL)
{
draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
draw_list->_OwnerName = drawlist_name;
viewport->DrawLists[drawlist_no] = draw_list;
viewport->BgFgDrawLists[drawlist_no] = draw_list;
}
// Our ImDrawList system requires that there is always a command
if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount)
if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)
{
draw_list->_ResetForNewFrame();
draw_list->PushTextureID(g.IO.Fonts->TexID);
draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount;
viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;
}
return draw_list;
}
ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
{
return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background");
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
}
ImDrawList* ImGui::GetBackgroundDrawList()
@ -4521,7 +4526,7 @@ ImDrawList* ImGui::GetBackgroundDrawList()
ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
{
return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
}
ImDrawList* ImGui::GetForegroundDrawList()
@ -4863,8 +4868,8 @@ void ImGui::NewFrame()
SetCurrentFont(GetDefaultFont());
IM_ASSERT(g.Font->IsLoaded());
ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int n = 0; n < g.Viewports.Size; n++)
virtual_space.Add(g.Viewports[n]->GetMainRect());
for (ImGuiViewportP* viewport : g.Viewports)
virtual_space.Add(viewport->GetMainRect());
g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
@ -4879,11 +4884,10 @@ void ImGui::NewFrame()
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
// Mark rendering data as invalid to prevent user who may have a handle on it to use it.
for (int n = 0; n < g.Viewports.Size; n++)
for (ImGuiViewportP* viewport : g.Viewports)
{
ImGuiViewportP* viewport = g.Viewports[n];
viewport->DrawData = NULL;
viewport->DrawDataP.Clear();
viewport->DrawDataP.Valid = false;
}
// Drag and drop keep the source ID alive so even if the source disappear our state is consistent
@ -5037,9 +5041,8 @@ void ImGui::NewFrame()
// Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (int i = 0; i != g.Windows.Size; i++)
for (ImGuiWindow* window : g.Windows)
{
ImGuiWindow* window = g.Windows[i];
window->WasActive = window->Active;
window->Active = false;
window->WriteAccessed = false;
@ -5055,9 +5058,9 @@ void ImGui::NewFrame()
for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
for (int i = 0; i < g.TablesTempData.Size; i++)
if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time)
TableGcCompactTransientBuffers(&g.TablesTempData[i]);
for (ImGuiTableTempData& table_temp_data : g.TablesTempData)
if (table_temp_data.LastTimeActive >= 0.0f && table_temp_data.LastTimeActive < memory_compact_start_time)
TableGcCompactTransientBuffers(&table_temp_data);
if (g.GcCompactAll)
GcCompactTransientMiscBuffers();
g.GcCompactAll = false;
@ -5140,15 +5143,12 @@ static void AddWindowToDrawData(ImGuiWindow* window, int layer)
ImGuiViewportP* viewport = window->Viewport;
IM_ASSERT(viewport != NULL);
g.IO.MetricsRenderWindows++;
if (window->Flags & ImGuiWindowFlags_DockNodeHost)
window->DrawList->ChannelsMerge();
if (window->DrawList->_Splitter._Count > 1)
window->DrawList->ChannelsMerge(); // Merge if user forgot to merge back. Also required in Docking branch for ImGuiWindowFlags_DockNodeHost windows.
ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList);
for (int i = 0; i < window->DC.ChildWindows.Size; i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
for (ImGuiWindow* child : window->DC.ChildWindows)
if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
AddWindowToDrawData(child, layer);
}
}
static inline int GetWindowDisplayLayer(ImGuiWindow* window)
@ -5245,10 +5245,10 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
// Draw behind window by moving the draw command at the FRONT of the draw list
{
// We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows,
// and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
// Draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
// FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
ImDrawList* draw_list = window->RootWindowDockTree->DrawList;
draw_list->ChannelsMerge();
if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
@ -5265,6 +5265,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
if (window->RootWindow->DockIsActive)
{
ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindowDockTree)->DrawList;
draw_list->ChannelsMerge();
if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min, viewport_rect.Max, false);
@ -5290,6 +5291,8 @@ ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* par
return bottom_most_visible_window;
}
// Important: AddWindowToDrawData() has not been called yet, meaning DockNodeHost windows needs a DrawList->ChannelsMerge() before usage.
// We call ChannelsMerge() lazily here at it is faster that doing a full iteration of g.Windows[] prior to calling RenderDimmedBackgrounds().
static void ImGui::RenderDimmedBackgrounds()
{
ImGuiContext& g = *GImGui;
@ -5326,6 +5329,7 @@ static void ImGui::RenderDimmedBackgrounds()
bb.Expand(distance);
if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
window->DrawList->ChannelsMerge();
if (window->DrawList->CmdBuffer.Size == 0)
window->DrawList->AddDrawCmd();
window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
@ -5434,9 +5438,8 @@ void ImGui::EndFrame()
// We cannot do that on FocusWindow() because children may not exist yet
g.WindowsTempSortBuffer.resize(0);
g.WindowsTempSortBuffer.reserve(g.Windows.Size);
for (int i = 0; i != g.Windows.Size; i++)
for (ImGuiWindow* window : g.Windows)
{
ImGuiWindow* window = g.Windows[i];
if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
continue;
AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
@ -5468,28 +5471,30 @@ void ImGui::Render()
if (g.FrameCountEnded != g.FrameCount)
EndFrame();
const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount);
if (g.FrameCountRendered == g.FrameCount)
return;
g.FrameCountRendered = g.FrameCount;
g.IO.MetricsRenderWindows = 0;
g.IO.MetricsRenderWindows = 0;
CallContextHooks(&g, ImGuiContextHookType_RenderPre);
// Add background ImDrawList (for each active viewport)
for (int n = 0; n != g.Viewports.Size; n++)
for (ImGuiViewportP* viewport : g.Viewports)
{
ImGuiViewportP* viewport = g.Viewports[n];
InitViewportDrawData(viewport);
if (viewport->DrawLists[0] != NULL)
if (viewport->BgFgDrawLists[0] != NULL)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
}
// Draw modal/window whitening backgrounds
RenderDimmedBackgrounds();
// Add ImDrawList to render
ImGuiWindow* windows_to_render_top_most[2];
windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindowDockTree : NULL;
windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
for (int n = 0; n != g.Windows.Size; n++)
for (ImGuiWindow* window : g.Windows)
{
ImGuiWindow* window = g.Windows[n];
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window);
@ -5498,30 +5503,25 @@ void ImGui::Render()
if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
AddRootWindowToDrawData(windows_to_render_top_most[n]);
// Draw modal/window whitening backgrounds
if (first_render_of_frame)
RenderDimmedBackgrounds();
// Draw software mouse cursor if requested by io.MouseDrawCursor flag
if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None)
if (g.IO.MouseDrawCursor && g.MouseCursor != ImGuiMouseCursor_None)
RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
// Setup ImDrawData structures for end-user
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
for (int n = 0; n < g.Viewports.Size; n++)
for (ImGuiViewportP* viewport : g.Viewports)
{
ImGuiViewportP* viewport = g.Viewports[n];
FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder);
// Add foreground ImDrawList (for each active viewport)
if (viewport->DrawLists[1] != NULL)
if (viewport->BgFgDrawLists[1] != NULL)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
// We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch).
ImDrawData* draw_data = &viewport->DrawDataP;
IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount);
for (int draw_list_n = 0; draw_list_n < draw_data->CmdLists.Size; draw_list_n++)
draw_data->CmdLists[draw_list_n]->_PopUnusedDrawCmd();
for (ImDrawList* draw_list : draw_data->CmdLists)
draw_list->_PopUnusedDrawCmd();
g.IO.MetricsRenderVertices += draw_data->TotalVtxCount;
g.IO.MetricsRenderIndices += draw_data->TotalIdxCount;
@ -5727,7 +5727,7 @@ bool ImGui::IsItemEdited()
void ImGui::SetNextItemAllowOverlap()
{
ImGuiContext& g = *GImGui;
g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap;
g.NextItemData.ItemFlags |= ImGuiItemFlags_AllowOverlap;
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@ -6600,18 +6600,18 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
ImVec2 collapse_button_pos;
if (has_close_button)
{
pad_r += button_sz;
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
pad_r += button_sz + style.ItemInnerSpacing.x;
}
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
{
pad_r += button_sz;
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
pad_r += button_sz + style.ItemInnerSpacing.x;
}
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
{
collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
pad_l += button_sz;
collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y);
pad_l += button_sz + style.ItemInnerSpacing.x;
}
// Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
@ -6705,9 +6705,9 @@ ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
return NULL;
// Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.
for (int i = 0; i < g.OpenPopupStack.Size; i++)
for (ImGuiPopupData& popup_data : g.OpenPopupStack)
{
ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
ImGuiWindow* popup_window = popup_data.Window;
if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
continue;
if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
@ -7532,9 +7532,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const
{
// Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source.
// We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it.
if ((g.MovingWindow == window) && (g.IO.ConfigDockingWithShift == g.IO.KeyShift))
if ((window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0)
BeginDockableDragDropSource(window);
if (g.MovingWindow == window && (window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0)
BeginDockableDragDropSource(window);
// Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead.
if (g.DragDropActive && !(flags & ImGuiWindowFlags_NoDocking))
@ -9727,8 +9726,8 @@ static const char* GetMouseSourceName(ImGuiMouseSource source)
static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
{
ImGuiContext& g = *GImGui;
if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; }
if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
@ -10474,7 +10473,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w < 0 : use default spacing if offset_from_start_x == 0, no spacing if offset_from_start_x != 0
// spacing_w >= 0 : enforce spacing amount
void ImGui::SameLine(float offset_from_start_x, float spacing_w)
{
@ -10508,9 +10507,6 @@ ImVec2 ImGui::GetCursorScreenPos()
return window->DC.CursorPos;
}
// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc.
// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50)
// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos...
void ImGui::SetCursorScreenPos(const ImVec2& pos)
{
ImGuiWindow* window = GetCurrentWindow();
@ -12131,6 +12127,19 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
NavUpdateAnyRequestFlag();
}
// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data)
{
ImGuiContext& g = *GImGui;
g.NavMoveScoringItems = false;
g.LastItemData.ID = tree_node_data->ID;
g.LastItemData.InFlags = tree_node_data->InFlags;
g.LastItemData.NavRect = tree_node_data->NavRect;
NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult()
NavClearPreferredPosForAxis(ImGuiAxis_Y);
NavUpdateAnyRequestFlag();
}
void ImGui::NavMoveRequestCancel()
{
ImGuiContext& g = *GImGui;
@ -12627,7 +12636,7 @@ void ImGui::NavUpdateCreateMoveRequest()
scoring_rect.TranslateY(scoring_rect_offset_y);
if (g.NavMoveSubmitted)
NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags);
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure we have a non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
//if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
}
@ -13903,9 +13912,9 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
{
ImGuiContext& g = *GImGui;
const ImGuiID type_hash = ImHashStr(type_name);
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
return &g.SettingsHandlers[handler_n];
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.TypeHash == type_hash)
return &handler;
return NULL;
}
@ -13914,9 +13923,9 @@ void ImGui::ClearIniSettings()
{
ImGuiContext& g = *GImGui;
g.SettingsIniData.clear();
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].ClearAllFn)
g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.ClearAllFn != NULL)
handler.ClearAllFn(&g, &handler);
}
bool ImGui::LoadIniSettingsFromDisk(const char* ini_filename, bool redundancy)
@ -13987,9 +13996,9 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
// Call pre-read handlers
// Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].ReadInitFn)
g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.ReadInitFn != NULL)
handler.ReadInitFn(&g, &handler);
void* entry_data = NULL;
ImGuiSettingsHandler* entry_handler = NULL;
@ -14033,9 +14042,9 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
memcpy(buf, ini_data, ini_size);
// Call post-read handlers
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].ApplyAllFn)
g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.ApplyAllFn != NULL)
handler.ApplyAllFn(&g, &handler);
}
bool ImGui::SaveIniSettingsToDisk(const char* ini_filename, bool redundancy)
@ -14086,11 +14095,8 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
g.SettingsDirtyTimer = 0.0f;
g.SettingsIniData.Buf.resize(0);
g.SettingsIniData.Buf.push_back(0);
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
{
ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
handler->WriteAllFn(&g, handler, &g.SettingsIniData);
}
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
handler.WriteAllFn(&g, &handler, &g.SettingsIniData);
if (out_size)
*out_size = (size_t)g.SettingsIniData.size();
return g.SettingsIniData.c_str();
@ -14159,8 +14165,8 @@ void ImGui::ClearWindowSettings(const char* name)
static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{
ImGuiContext& g = *ctx;
for (int i = 0; i != g.Windows.Size; i++)
g.Windows[i]->SettingsOffset = -1;
for (ImGuiWindow* window : g.Windows)
window->SettingsOffset = -1;
g.SettingsWindows.clear();
}
@ -14211,9 +14217,8 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
// Gather data from windows that were active during this session
// (if a window wasn't opened in this session we preserve its settings)
ImGuiContext& g = *ctx;
for (int i = 0; i != g.Windows.Size; i++)
for (ImGuiWindow* window : g.Windows)
{
ImGuiWindow* window = g.Windows[i];
if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
continue;
@ -17372,14 +17377,13 @@ static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* o
r.Max.x -= style.WindowBorderSize;
float button_sz = g.FontSize;
ImVec2 window_menu_button_pos = r.Min;
r.Min.x += style.FramePadding.x;
r.Max.x -= style.FramePadding.x;
ImVec2 window_menu_button_pos = ImVec2(r.Min.x, r.Min.y + style.FramePadding.y);
if (node->HasCloseButton)
{
r.Max.x -= button_sz;
if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - style.FramePadding.x, r.Min.y);
if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
r.Max.x -= button_sz + style.ItemInnerSpacing.x;
}
if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Left)
{
@ -17387,8 +17391,8 @@ static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* o
}
else if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Right)
{
r.Max.x -= button_sz + style.FramePadding.x;
window_menu_button_pos = ImVec2(r.Max.x, r.Min.y);
window_menu_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
r.Max.x -= button_sz + style.ItemInnerSpacing.x;
}
if (out_tab_bar_rect) { *out_tab_bar_rect = r; }
if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; }
@ -18879,6 +18883,17 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
IM_ASSERT(g.MovingWindow == window);
IM_ASSERT(g.CurrentWindow == window);
// 0: Hold SHIFT to disable docking, 1: Hold SHIFT to enable docking.
if (g.IO.ConfigDockingWithShift != g.IO.KeyShift)
{
// When ConfigDockingWithShift is set, display a tooltip to increase UI affordance.
// We cannot set for HoveredWindowUnderMovingWindow != NULL here, as it is only valid/useful when drag and drop is already active
// (because of the 'is_mouse_dragging_with_an_expected_destination' logic in UpdateViewportsNewFrame() function)
if (g.IO.ConfigDockingWithShift && g.MouseStationaryTimer >= 1.0f && g.ActiveId >= 1.0f)
SetTooltip("%s", LocalizeGetMsg(ImGuiLocKey_DockingHoldShiftToDock));
return;
}
g.LastItemData.ID = window->MoveId;
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
@ -19404,10 +19419,9 @@ void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP*
ImVec2 scale = bb.GetSize() / viewport->Size;
ImVec2 off = bb.Min - viewport->Pos * scale;
float alpha_mul = (viewport->Flags & ImGuiViewportFlags_IsMinimized) ? 0.30f : 1.00f;
window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
for (int i = 0; i != g.Windows.Size; i++)
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
for (ImGuiWindow* thumb_window : g.Windows)
{
ImGuiWindow* thumb_window = g.Windows[i];
if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))
continue;
if (thumb_window->Viewport != viewport)
@ -19436,13 +19450,12 @@ static void RenderViewportsThumbnails()
// We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports.
float SCALE = 1.0f / 8.0f;
ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int n = 0; n < g.Viewports.Size; n++)
bb_full.Add(g.Viewports[n]->GetMainRect());
for (ImGuiViewportP* viewport : g.Viewports)
bb_full.Add(viewport->GetMainRect());
ImVec2 p = window->DC.CursorPos;
ImVec2 off = p - bb_full.Min * SCALE;
for (int n = 0; n < g.Viewports.Size; n++)
for (ImGuiViewportP* viewport : g.Viewports)
{
ImGuiViewportP* viewport = g.Viewports[n];
ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);
ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);
}
@ -19557,9 +19570,8 @@ static void MetricsHelpMarker(const char* desc)
// [DEBUG] List fonts in a font atlas and display its texture
void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
{
for (int i = 0; i < atlas->Fonts.Size; i++)
for (ImFont* font : atlas->Fonts)
{
ImFont* font = atlas->Fonts[i];
PushID(font);
DebugNodeFont(font);
PopID();
@ -19760,9 +19772,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
ImVector<ImGuiWindow*>& temp_buffer = g.WindowsTempSortBuffer;
temp_buffer.resize(0);
for (int i = 0; i < g.Windows.Size; i++)
if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount)
temp_buffer.push_back(g.Windows[i]);
for (ImGuiWindow* window : g.Windows)
if (window->LastFrameActive + 1 >= g.FrameCount)
temp_buffer.push_back(window);
struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
@ -19774,22 +19786,21 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// DrawLists
int drawlist_count = 0;
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
drawlist_count += g.Viewports[viewport_i]->DrawDataP.CmdLists.Size;
for (ImGuiViewportP* viewport : g.Viewports)
drawlist_count += viewport->DrawDataP.CmdLists.Size;
if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
{
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
for (ImGuiViewportP* viewport : g.Viewports)
{
ImGuiViewportP* viewport = g.Viewports[viewport_i];
bool viewport_has_drawlist = false;
for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++)
for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
{
if (!viewport_has_drawlist)
Text("Active DrawLists in Viewport #%d, ID: 0x%08X", viewport->Idx, viewport->ID);
viewport_has_drawlist = true;
DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList");
DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
}
}
TreePop();
@ -19833,22 +19844,21 @@ void ImGui::ShowMetricsWindow(bool* p_open)
viewport->Window ? viewport->Window->Name : "N/A");
TreePop();
}
for (int i = 0; i < g.Viewports.Size; i++)
DebugNodeViewport(g.Viewports[i]);
for (ImGuiViewportP* viewport : g.Viewports)
DebugNodeViewport(viewport);
TreePop();
}
// Details for Popups
if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
{
for (int i = 0; i < g.OpenPopupStack.Size; i++)
for (const ImGuiPopupData& popup_data : g.OpenPopupStack)
{
// As it's difficult to interact with tree nodes while popups are open, we display everything inline.
const ImGuiPopupData* popup_data = &g.OpenPopupStack[i];
ImGuiWindow* window = popup_data->Window;
ImGuiWindow* window = popup_data.Window;
BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'",
popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
popup_data.PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
popup_data.BackupNavWindow ? popup_data.BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
}
TreePop();
}
@ -19929,8 +19939,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
{
for (int n = 0; n < g.SettingsHandlers.Size; n++)
BulletText("\"%s\"", g.SettingsHandlers[n].TypeName);
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
BulletText("\"%s\"", handler.TypeName);
TreePop();
}
if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
@ -20119,9 +20129,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Overlay: Display windows Rectangles and Begin Order
if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
{
for (int n = 0; n < g.Windows.Size; n++)
for (ImGuiWindow* window : g.Windows)
{
ImGuiWindow* window = g.Windows[n];
if (!window->WasActive)
continue;
ImDrawList* draw_list = GetForegroundDrawList(window);
@ -20197,8 +20206,8 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
return;
BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
for (ImGuiOldColumnData& column : columns->Columns)
BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", (int)columns->Columns.index_from_ptr(&column), column.OffsetNorm, GetColumnOffsetFromNorm(columns, column.OffsetNorm));
TreePop();
}
@ -20519,11 +20528,8 @@ void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
return;
for (int n = 0; n < storage->Data.Size; n++)
{
const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
for (const ImGuiStorage::ImGuiStoragePair& p : storage->Data)
BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
}
TreePop();
}
@ -20594,8 +20600,8 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport)
(flags & ImGuiViewportFlags_NoAutoMerge) ? " NoAutoMerge" : "",
(flags & ImGuiViewportFlags_TopMost) ? " TopMost" : "",
(flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "");
for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++)
DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList");
for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
TreePop();
}
}
@ -20660,8 +20666,8 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
{
for (int n = 0; n < window->ColumnsStorage.Size; n++)
DebugNodeColumns(&window->ColumnsStorage[n]);
for (ImGuiOldColumns& columns : window->ColumnsStorage)
DebugNodeColumns(&columns);
TreePop();
}
DebugNodeStorage(&window->StateStorage, "Storage");
@ -20798,6 +20804,38 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//-----------------------------------------------------------------------------
// Draw a small cross at current CursorPos in current window's DrawList
void ImGui::DebugDrawCursorPos(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 pos = window->DC.CursorPos;
window->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f);
window->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f);
}
// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList
void ImGui::DebugDrawLineExtents(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float curr_x = window->DC.CursorPos.x;
float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y);
float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f);
}
// Draw last item rect in ForegroundDrawList (so it is always visible)
void ImGui::DebugDrawItemRect(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col);
}
// [DEBUG] Locate item position/rectangle given an ID.
static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green
void ImGui::DebugLocateItem(ImGuiID target_id)