update Dear ImGui to 1.92.3 - comment wrap working

finally I can get rid of that silly text
so much drama over a freaking setting...

nobody got the reference
This commit is contained in:
tildearrow 2025-09-17 19:09:03 -05:00
parent c0da289d40
commit e583a49436
23 changed files with 1082 additions and 568 deletions

View file

@ -1,4 +1,4 @@
// dear imgui, v1.92.2b
// dear imgui, v1.92.3
// (main code and documentation)
// Help:
@ -412,6 +412,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
- TL;DR; if the assert triggers, you can add a Dummy({0,0}) call to validate extending parent boundaries.
- 2025/06/11 (1.92.0) - Renamed/moved ImGuiConfigFlags_DpiEnableScaleFonts -> bool io.ConfigDpiScaleFonts.
- Renamed/moved ImGuiConfigFlags_DpiEnableScaleViewports -> bool io.ConfigDpiScaleViewports. **Neither of those flags are very useful in current code. They will be useful once we merge font changes.**
[there was a bug on 2025/06/12: when using the old config flags names, they were not imported correctly into the new ones, fixed on 2025/09/12]
- 2025/06/11 (1.92.0) - THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, BUT INEVITABLY SOME USERS WILL BE AFFECTED.
IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/
As part of the plan to reduce impact of API breaking changes, several unfinished changes/features/refactors related to font and text systems and scaling will be part of subsequent releases (1.92.1+).
@ -454,7 +455,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
- Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) since v1.91.8. It is quite important you keep it automatic until we decide if we want to provide a way to express finer policy, otherwise you will likely waste texture space when using large glyphs. Note that the imgui_freetype backend doesn't use and does not need oversampling.
- Fonts: specifying glyph ranges is now unnecessary. The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. All GetGlyphRangesXXXX() functions are now marked obsolete: GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), GetGlyphRangesThai(), GetGlyphRangesVietnamese().
- Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327)
- Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't.
- Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one), you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't.
- Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFont(NULL, style.FontSizeBase * factor)' or to manipulate other scaling factors.
- Fonts: obsoleted ImFont::Scale which is not useful anymore.
- Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things:
@ -536,7 +537,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
in doubt it is almost always better to do an intermediate intptr_t cast, since it allows casting any pointer/integer type without warning:
- May warn: ImGui::Image((void*)MyTextureData, ...);
- May warn: ImGui::Image((void*)(intptr_t)MyTextureData, ...);
- Won't warn: ImGui::Image((ImTextureID)(intptr_t)MyTextureData), ...);
- Won't warn: ImGui::Image((ImTextureID)(intptr_t)MyTextureData, ...);
- note that you can always define ImTextureID to be your own high-level structures (with dedicated constructors) if you like.
- 2024/10/03 (1.91.3) - drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is a still special value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76)
- drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed).
@ -826,7 +827,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
- ShowTestWindow() -> use ShowDemoWindow()
- IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
- IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
- SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
- SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f))
- GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing()
- ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg
- ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding
@ -1443,6 +1444,7 @@ ImGuiStyle::ImGuiStyle()
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axises)
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
@ -1468,6 +1470,7 @@ ImGuiStyle::ImGuiStyle()
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
DockingNodeHasCloseButton = true; // Docking nodes have their own CloseButton() to close all docked windows.
DockingSeparatorSize = 2.0f; // Thickness of resizing border between docked windows
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
@ -1515,6 +1518,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
ColumnsMinSpacing = ImTrunc(ColumnsMinSpacing * scale_factor);
ScrollbarSize = ImTrunc(ScrollbarSize * scale_factor);
ScrollbarRounding = ImTrunc(ScrollbarRounding * scale_factor);
ScrollbarPadding = ImTrunc(ScrollbarPadding * scale_factor);
GrabMinSize = ImTrunc(GrabMinSize * scale_factor);
GrabRounding = ImTrunc(GrabRounding * scale_factor);
LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor);
@ -2141,7 +2145,7 @@ void ImStrncpy(char* dst, const char* src, size_t count)
if (count < 1)
return;
if (count > 1)
strncpy(dst, src, count - 1);
strncpy(dst, src, count - 1); // FIXME-OPT: strncpy not only doesn't guarantee 0-termination, it also always writes the whole array
dst[count - 1] = 0;
}
@ -2462,6 +2466,17 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
return ~crc;
}
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// FIXME-OPT: This is not designed to be optimal. Use with care.
const char* ImHashSkipUncontributingPrefix(const char* label)
{
const char* result = label;
while (unsigned char c = *label++)
if (c == '#' && label[0] == '#' && label[1] == '#')
result = label - 1;
return result;
}
//-----------------------------------------------------------------------------
// [SECTION] MISC HELPERS/UTILITIES (File functions)
//-----------------------------------------------------------------------------
@ -3138,19 +3153,21 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
va_end(args_copy);
}
IM_MSVC_RUNTIME_CHECKS_OFF
void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
{
IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
if (old_size == new_size)
return;
if (EndOffset == 0 || base[EndOffset - 1] == '\n')
LineOffsets.push_back(EndOffset);
Offsets.push_back(EndOffset);
const char* base_end = base + new_size;
for (const char* p = base + old_size; (p = (const char*)ImMemchr(p, '\n', base_end - p)) != 0; )
if (++p < base_end) // Don't push a trailing offset on last \n
LineOffsets.push_back((int)(intptr_t)(p - base));
Offsets.push_back((int)(intptr_t)(p - base));
EndOffset = ImMax(EndOffset, new_size);
}
IM_MSVC_RUNTIME_CHECKS_RESTORE
//-----------------------------------------------------------------------------
// [SECTION] ImGuiListClipper
@ -3188,7 +3205,7 @@ static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>&
}
}
static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
static void ImGuiListClipper_SeekCursorAndSetupPrevLine(ImGuiListClipper* clipper, float pos_y, float line_height)
{
// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
@ -3206,10 +3223,13 @@ static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_
{
if (table->IsInsideRow)
ImGui::TableEndRow(table);
table->RowPosY2 = window->DC.CursorPos.y;
const int row_increase = (int)((off_y / line_height) + 0.5f);
table->CurrentRow += row_increase;
table->RowBgColorCounter += row_increase;
if (row_increase > 0 && (clipper->Flags & ImGuiListClipperFlags_NoSetTableRowCounters) == 0) // If your clipper item height is != from actual table row height, consider using ImGuiListClipperFlags_NoSetTableRowCounters. See #8886.
{
table->CurrentRow += row_increase;
table->RowBgColorCounter += row_increase;
}
table->RowPosY2 = window->DC.CursorPos.y;
}
}
@ -3292,7 +3312,7 @@ void ImGuiListClipper::SeekCursorForItem(int item_n)
// - StartPosY starts from ItemsFrozen, by adding SeekOffsetY we generally cancel that out (SeekOffsetY == LossynessOffset - ItemsFrozen * ItemsHeight).
// - The reason we store SeekOffsetY instead of inferring it, is because we want to allow user to perform Seek after the last step, where ImGuiListClipperData is already done.
float pos_y = (float)((double)StartPosY + StartSeekOffsetY + (double)item_n * ItemsHeight);
ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, ItemsHeight);
ImGuiListClipper_SeekCursorAndSetupPrevLine(this, pos_y, ItemsHeight);
}
static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
@ -3391,7 +3411,6 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
if (g.NavId != 0 && window->NavLastIds[0] == g.NavId)
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
// Add visible range
float min_y = window->ClipRect.Min.y;
float max_y = window->ClipRect.Max.y;
@ -3410,6 +3429,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0));
}
// Add main visible range
const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(min_y, max_y, off_min, off_max));
@ -3475,6 +3495,13 @@ bool ImGuiListClipper::Step()
return ret;
}
// Generic helper, equivalent to old ImGui::CalcListClipping() but statelesss
void ImGui::CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end)
{
*out_visible_start = ImMax((int)((clip_rect.Min.y - pos.y) / items_height), 0);
*out_visible_end = ImMax((int)ImCeil((clip_rect.Max.y - pos.y) / items_height), *out_visible_start);
}
//-----------------------------------------------------------------------------
// [SECTION] STYLING
//-----------------------------------------------------------------------------
@ -3586,6 +3613,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarPadding) }, // ImGuiStyleVar_ScrollbarPadding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize
@ -4218,7 +4246,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
WheelingWindowReleaseTimer = 0.0f;
DebugDrawIdConflictsId = 0;
DebugHookIdInfo = 0;
DebugHookIdInfoId = 0;
HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdPreviousFrameItemCount = 0;
HoveredIdAllowOverlap = false;
@ -4557,6 +4585,7 @@ void ImGui::Shutdown()
g.ClipboardHandlerData.clear();
g.MenusIdSubmittedThisFrame.clear();
g.InputTextState.ClearFreeMemory();
g.InputTextLineIndex.clear();
g.InputTextDeactivatedState.ClearFreeMemory();
g.SettingsWindows.clear();
@ -4690,6 +4719,7 @@ void ImGui::GcCompactTransientMiscBuffers()
ImGuiContext& g = *GImGui;
g.ItemFlagsStack.clear();
g.GroupStack.clear();
g.InputTextLineIndex.clear();
g.MultiSelectTempDataStacked = 0;
g.MultiSelectTempData.clear_destruct();
TableGcCompactSettings();
@ -7618,10 +7648,11 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
// Close button
if (has_close_button)
{
ImGuiItemFlags backup_item_flags = g.CurrentItemFlags;
g.CurrentItemFlags |= ImGuiItemFlags_NoFocus;
if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
*p_open = false;
g.CurrentItemFlags &= ~ImGuiItemFlags_NoFocus;
g.CurrentItemFlags = backup_item_flags;
}
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
@ -7881,7 +7912,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const
}
// Process SetNextWindow***() calls
// (FIXME: Consider splitting the HasXXX flags into X/Y components
// (FIXME: Consider splitting the HasXXX flags into X/Y components)
bool window_pos_set_by_api = false;
bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasPos)
@ -8596,12 +8627,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const
NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls
// Close requested by platform window (apply to all windows in this viewport)
// FIXME: Investigate removing the 'window->Viewport != GetMainViewport()' test, which seems superfluous.
if (p_open != NULL && window->Viewport->PlatformRequestClose && window->Viewport != GetMainViewport())
{
IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' closed by PlatformRequestClose\n", window->Name);
*p_open = false;
g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. // FIXME-NAV: Try removing.
}
if (window->DockNode == NULL || (window->DockNode->MergedFlags & ImGuiDockNodeFlags_DockSpace) == 0)
{
IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' closed by PlatformRequestClose\n", window->Name);
*p_open = false;
g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. // FIXME-NAV: Try removing.
}
// Pressing CTRL+C copy window content into the clipboard
// [EXPERIMENTAL] Breaks on nested Begin/End pairs. We need to work that out and add better logging scope.
@ -9277,7 +9310,7 @@ void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& s
}
// Content size = inner scrollable rectangle, padded with WindowPadding.
// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
// SetNextWindowContentSize(ImVec2(100,100)) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
void ImGui::SetNextWindowContentSize(const ImVec2& size)
{
ImGuiContext& g = *GImGui;
@ -9819,7 +9852,7 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
#endif
return id;
@ -9831,7 +9864,7 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
#endif
return id;
@ -9843,7 +9876,7 @@ ImGuiID ImGuiWindow::GetID(int n)
ImGuiID id = ImHashData(&n, sizeof(n), seed);
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
#endif
return id;
@ -9906,7 +9939,7 @@ void ImGui::PushOverrideID(ImGuiID id)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
#endif
window->IDStack.push_back(id);
@ -9920,7 +9953,7 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
#endif
return id;
@ -9931,7 +9964,7 @@ ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed)
ImGuiID id = ImHashData(&n, sizeof(n), seed);
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
if (g.DebugHookIdInfoId == id)
DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
#endif
return id;
@ -11585,12 +11618,12 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
}
if (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts)
{
g.IO.ConfigDpiScaleFonts = false;
g.IO.ConfigDpiScaleFonts = true;
g.IO.ConfigFlags &= ~ImGuiConfigFlags_DpiEnableScaleFonts;
}
if (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports)
{
g.IO.ConfigDpiScaleViewports = false;
g.IO.ConfigDpiScaleViewports = true;
g.IO.ConfigFlags &= ~ImGuiConfigFlags_DpiEnableScaleViewports;
}
@ -14362,6 +14395,9 @@ static ImVec2 ImGui::NavCalcPreferredRefPos()
const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID;
if (source != ImGuiInputSource_Mouse && !activated_shortcut && window == NULL)
source = ImGuiInputSource_Mouse;
// Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag.
if (source == ImGuiInputSource_Mouse)
{
@ -14377,11 +14413,11 @@ static ImVec2 ImGui::NavCalcPreferredRefPos()
ImRect ref_rect;
if (activated_shortcut)
ref_rect = g.LastItemData.NavRect;
else
else if (window != NULL)
ref_rect = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]);
// Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?)
if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX))
if (window != NULL && window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX))
{
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
ref_rect.Translate(window->Scroll - next_scroll);
@ -14892,6 +14928,8 @@ void ImGui::NavMoveRequestApplyResult()
{
g.NavNextActivateId = result->ID;
g.NavNextActivateFlags = ImGuiActivateFlags_None;
if (g.NavMoveFlags & ImGuiNavMoveFlags_FocusApi)
g.NavNextActivateFlags |= ImGuiActivateFlags_FromFocusApi;
if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing)
g.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState | ImGuiActivateFlags_FromTabbing;
}
@ -15220,7 +15258,7 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingInputSource = g.NavInputSource = ImGuiInputSource_Gamepad;
}
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
if (ImGuiWindow* window = (g.NavWindow && IsWindowNavFocusable(g.NavWindow)) ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
{
if (start_windowing_with_keyboard || g.ConfigNavWindowingWithGamepad)
g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location
@ -16305,13 +16343,9 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
{
ImGuiContext& g = *GImGui;
// Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier.
if (g.IO.ConfigDebugIniSettings == false)
{
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier.
if (const char* p = strstr(name, "###"))
name = p;
}
name = ImHashSkipUncontributingPrefix(name);
const size_t name_len = ImStrlen(name);
// Allocate chunk
@ -16565,6 +16599,8 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view
g.CurrentViewport = viewport;
IM_ASSERT(g.CurrentDpiScale > 0.0f && g.CurrentDpiScale < 99.0f); // Typical correct values would be between 1.0f and 4.0f
//IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
if (g.IO.ConfigDpiScaleFonts)
g.Style.FontScaleDpi = g.CurrentDpiScale;
// Notify platform layer of viewport changes
// FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI
@ -18956,7 +18992,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
node->HasCloseButton |= window->HasCloseButton;
window->DockIsActive = (node->Windows.Size > 1);
}
if (node_flags & ImGuiDockNodeFlags_NoCloseButton)
if ((node_flags & ImGuiDockNodeFlags_NoCloseButton) || !g.Style.DockingNodeHasCloseButton)
node->HasCloseButton = false;
// Bind or create host window
@ -21729,6 +21765,7 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImG
// - DebugNodeWindowSettings() [Internal]
// - DebugNodeWindowsList() [Internal]
// - DebugNodeWindowsListByBeginStackParent() [Internal]
// - ShowFontSelector()
//-----------------------------------------------------------------------------
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS)
@ -21944,12 +21981,12 @@ static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTex
return buf;
}
static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, const ImDrawCmd* cmd)
static const char* FormatTextureRefForDebugDisplay(char* buf, int buf_size, ImTextureRef tex_ref)
{
char* buf_end = buf + buf_size;
if (cmd->TexRef._TexData != NULL)
buf += ImFormatString(buf, buf_end - buf, "#%03d: ", cmd->TexRef._TexData->UniqueID);
return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->TexRef.GetTexID()); // Calling TexRef::GetTexID() to avoid assert of cmd->GetTexID()
if (tex_ref._TexData != NULL)
buf += ImFormatString(buf, buf_end - buf, "#%03d: ", tex_ref._TexData->UniqueID);
return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), tex_ref.GetTexID()); // Calling TexRef::GetTexID() to avoid assert of cmd->GetTexID()
}
#ifdef IMGUI_ENABLE_FREETYPE
@ -22137,7 +22174,7 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRe
char texid_desc[30];
Text("Status = %s (%d), Format = %s (%d), UseColors = %d", ImTextureDataGetStatusName(tex->Status), tex->Status, ImTextureDataGetFormatName(tex->Format), tex->Format, tex->UseColors);
Text("TexID = %s, BackendUserData = %p", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID), tex->BackendUserData);
Text("TexID = %s, BackendUserData = %p", FormatTextureRefForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->GetTexRef()), tex->BackendUserData);
TreePop();
}
PopID();
@ -23018,7 +23055,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con
}
char texid_desc[30];
FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd);
FormatTextureRefForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd->TexRef);
char buf[300];
ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
pcmd->ElemCount / 3, texid_desc, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
@ -23334,7 +23371,7 @@ void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph)
if (glyph->PackId >= 0)
{
ImTextureRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId);
Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y);
Text("PackId: 0x%X (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y);
}
Text("SourceIdx: %d", glyph->SourceIdx);
}
@ -23492,7 +23529,7 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
}
const ImVec2* pr = window->NavPreferredScoringPosRel;
for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater.
BulletText("NavPreferredScoringPosRel[%d] = (%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater.
BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportOwned ? " (Owned)" : "", window->ViewportId, window->ViewportPos.x, window->ViewportPos.y);
@ -23848,20 +23885,22 @@ void ImGui::UpdateDebugToolStackQueries()
ImGuiIDStackTool* tool = &g.DebugIDStackTool;
// Clear hook when id stack tool is not visible
g.DebugHookIdInfo = 0;
g.DebugHookIdInfoId = 0;
tool->QueryHookActive = false;
if (g.FrameCount != tool->LastActiveFrame + 1)
return;
// Update queries. The steps are: -1: query Stack, >= 0: query each stack item
// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId;
if (tool->QueryId != query_id)
const ImGuiID query_main_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId;
if (tool->QueryMainId != query_main_id)
{
tool->QueryId = query_id;
tool->QueryMainId = query_main_id;
tool->StackLevel = -1;
tool->Results.resize(0);
tool->ResultPathsBuf.resize(0);
}
if (query_id == 0)
if (query_main_id == 0)
return;
// Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)
@ -23873,11 +23912,15 @@ void ImGui::UpdateDebugToolStackQueries()
// Update hook
stack_level = tool->StackLevel;
if (stack_level == -1)
g.DebugHookIdInfo = query_id;
if (stack_level >= 0 && stack_level < tool->Results.Size)
{
g.DebugHookIdInfo = tool->Results[stack_level].ID;
g.DebugHookIdInfoId = query_main_id;
tool->QueryHookActive = true;
}
else if (stack_level >= 0 && stack_level < tool->Results.Size)
{
g.DebugHookIdInfoId = tool->Results[stack_level].ID;
tool->Results[stack_level].QueryFrameCount++;
tool->QueryHookActive = true;
}
}
@ -23887,11 +23930,17 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiIDStackTool* tool = &g.DebugIDStackTool;
if (tool->QueryHookActive == false)
{
IM_ASSERT(id == 0);
return;
}
// Step 0: stack query
// This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget.
if (tool->StackLevel == -1)
{
IM_ASSERT(tool->Results.Size == 0);
tool->StackLevel++;
tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());
for (int n = 0; n < window->IDStack.Size + 1; n++)
@ -23906,42 +23955,48 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat
ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
switch (data_type)
if (info->DescOffset == -1)
{
case ImGuiDataType_S32:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
break;
case ImGuiDataType_String:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)ImStrlen((const char*)data_id), (const char*)data_id);
break;
case ImGuiDataType_Pointer:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
break;
case ImGuiDataType_ID:
if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
return;
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
break;
default:
IM_ASSERT(0);
const char* result = NULL;
const char* result_end = NULL;
switch (data_type)
{
case ImGuiDataType_S32:
ImFormatStringToTempBuffer(&result, &result_end, "%d", (int)(intptr_t)data_id);
break;
case ImGuiDataType_String:
ImFormatStringToTempBuffer(&result, &result_end, "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)ImStrlen((const char*)data_id), (const char*)data_id);
break;
case ImGuiDataType_Pointer:
ImFormatStringToTempBuffer(&result, &result_end, "(void*)0x%p", data_id);
break;
case ImGuiDataType_ID:
// PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
ImFormatStringToTempBuffer(&result, &result_end, "0x%08X [override]", id);
break;
default:
IM_ASSERT(0);
}
info->DescOffset = tool->ResultPathsBuf.size();
tool->ResultPathsBuf.append(result, result_end + 1); // Include zero terminator
}
info->QuerySuccess = true;
info->DataType = data_type;
info->DataType = (ImS8)data_type;
}
static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size)
{
ImGuiStackLevelInfo* info = &tool->Results[n];
ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;
ImGuiWindow* window = (info->DescOffset == -1 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;
if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name);
return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", ImHashSkipUncontributingPrefix(window->Name));
if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc);
return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", ImHashSkipUncontributingPrefix(&tool->ResultPathsBuf.Buf[info->DescOffset]));
if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
return (*buf = 0);
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label);
return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", ImHashSkipUncontributingPrefix(label));
#endif
return ImFormatString(buf, buf_size, "???");
}
@ -23962,38 +24017,47 @@ void ImGui::ShowIDStackToolWindow(bool* p_open)
ImGuiIDStackTool* tool = &g.DebugIDStackTool;
// Build and display path
tool->ResultPathBuf.resize(0);
tool->ResultTempBuf.resize(0);
for (int stack_n = 0; stack_n < tool->Results.Size; stack_n++)
{
char level_desc[256];
StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc));
tool->ResultPathBuf.append(stack_n == 0 ? "//" : "/");
for (int n = 0; level_desc[n]; n++)
tool->ResultTempBuf.append(stack_n == 0 ? "//" : "/");
for (const char* p = level_desc; *p != 0; )
{
if (level_desc[n] == '/')
tool->ResultPathBuf.append("\\");
tool->ResultPathBuf.append(level_desc + n, level_desc + n + 1);
unsigned int c;
const char* p_next = p + ImTextCharFromUtf8(&c, p, NULL);
if (c == '/')
tool->ResultTempBuf.append("\\");
if (c < 256 || !tool->OptHexEncodeNonAsciiChars)
tool->ResultTempBuf.append(p, p_next);
else for (; p < p_next; p++)
tool->ResultTempBuf.appendf("\\x%02x", (unsigned char)*p);
p = p_next;
}
}
Text("0x%08X", tool->QueryId);
Text("0x%08X", tool->QueryMainId);
SameLine();
MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
// CTRL+C to copy path
const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime;
PushStyleVarY(ImGuiStyleVar_FramePadding, 0.0f);
Checkbox("Hex-encode non-ASCII", &tool->OptHexEncodeNonAsciiChars);
SameLine();
PushStyleVarY(ImGuiStyleVar_FramePadding, 0.0f); Checkbox("Ctrl+C: copy path", &tool->CopyToClipboardOnCtrlC); PopStyleVar();
Checkbox("Ctrl+C: copy path", &tool->OptCopyToClipboardOnCtrlC);
PopStyleVar();
SameLine();
TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*");
if (tool->CopyToClipboardOnCtrlC && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused))
if (tool->OptCopyToClipboardOnCtrlC && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused))
{
tool->CopyToClipboardLastTime = (float)g.Time;
SetClipboardText(tool->ResultPathBuf.c_str());
SetClipboardText(tool->ResultTempBuf.c_str());
}
Text("- Path \"%s\"", tool->ResultPathBuf.c_str());
Text("- Path \"%s\"", tool->ResultTempBuf.c_str());
#ifdef IMGUI_ENABLE_TEST_ENGINE
Text("- Label \"%s\"", tool->QueryId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryId) : "");
Text("- Label \"%s\"", tool->QueryMainId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryMainId) : "");
#endif
Separator();
@ -24060,7 +24124,7 @@ void ImGui::ShowFontSelector(const char* label)
for (ImFont* font : io.Fonts->Fonts)
{
PushID((void*)font);
if (Selectable(font->GetDebugName(), font == font_current))
if (Selectable(font->GetDebugName(), font == font_current, ImGuiSelectableFlags_SelectOnNav))
io.FontDefault = font;
if (font == font_current)
SetItemDefaultFocus();