diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 6f68bf4d2..e5e3096a6 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -32,6 +32,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) // 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683) // 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10. // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. @@ -122,6 +123,15 @@ #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #endif +#if defined(__has_include) +#if !__has_include() || !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_X11 +#endif +#if !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_WAYLAND +#endif +#endif + // GLFW #if !defined(IMGUI_IMPL_GLFW_DISABLE_X11) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) #define GLFW_HAS_X11 1 diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index b625961b1..c3dcfa79a 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -50,7 +50,7 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* wi IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); -// GFLW callbacks options: +// GLFW callbacks options: // - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user) IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows); diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index f001bc729..091de1b15 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -338,7 +338,7 @@ void MyImGuiBackend_UpdateTexture(ImTextureData* tex) { // Create texture based on tex->Width, tex->Height. // - Most backends only support tex->Format == ImTextureFormat_RGBA32. - // - Backends for particularly memory constrainted platforms may support tex->Format == ImTextureFormat_Alpha8. + // - Backends for particularly memory constrained platforms may support tex->Format == ImTextureFormat_Alpha8. // Upload all texture pixels // - Read from our CPU-side copy of the texture and copy to your graphics API. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1fa07fe2a..4bbd6d4f3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,9 @@ Breaking Changes: has already been rendered. (#9162) [@ocornut, @cyfewlp] - Removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. + - Fixed an issue where using PushFont() from the implicit/fallback "Debug" window when + its recorded state is collapsed would incorrectly early out. This would break e.g. using + direct draw-list calls such as GetForegroundDrawList() with current font. (#9210, #8865) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). The default value has same meaning before and after. (#9157, #9146) @@ -176,6 +179,7 @@ Other Changes: used io.DisplayFramebufferScale (very old code), effectively making those actions faster on macOS/iOS retina screens. (changed this to use a style scale factor that's not fully formalized yet) + - Fixed an UBSan warning when using in a ListClipper region . (#9160) - Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - InvisibleButton: allow calling with size (0,0) to fit to available content @@ -215,6 +219,7 @@ Other Changes: Lowers overhead for very high framerates (e.g. 10k+ FPS). [@maxliani] - GLFW: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. (#9109, #9116) + Try to set them automatically if headers are not accessible. (#9225) - OpenGL3: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) - SDL2, SDL3: changed `GetClipboardText()` handler to return NULL on error aka @@ -373,7 +378,7 @@ Other Changes: debug/metrics window is not in the same viewport as the table. - Backends: - NULL: added imgui_impl_null platform/renderer backend. - This is designed if you need to run e.g. context with no input or no ouput. + This is designed if you need to run e.g. context with no input or no output. - GLFW: fixed building on Linux platforms where Wayland headers are not available. (#9024, #8969, #8921, #8920) [@jagot] - GLFW: lower minimum requirement from GLFW 3.1 to GLFW 3.0. Though @@ -958,7 +963,7 @@ Breaking changes: which font input is providing which glyph. - Fonts: **IMPORTANT** on Thread Safety: - A few functions such as font->CalcTextSizeA() were by sheer luck (== accidentally) - thread-safe even thou we had never provided that guarantee before. They are + thread-safe even though we had never provided that guarantee before. They are definitively not thread-safe anymore as new glyphs may be loaded. - Textures: diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt index 11248df26..86291f9e2 100644 --- a/examples/example_glfw_wgpu/CMakeLists.txt +++ b/examples/example_glfw_wgpu/CMakeLists.txt @@ -102,7 +102,7 @@ else() # Native/Desktop build option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 # Dawn builds many things by default - disable things we don't need option(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" OFF) diff --git a/examples/example_glfw_wgpu/README.md b/examples/example_glfw_wgpu/README.md index 119647211..04320d22c 100644 --- a/examples/example_glfw_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt index c4c3eee86..ae0d626a1 100644 --- a/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/examples/example_sdl2_wgpu/CMakeLists.txt @@ -92,7 +92,7 @@ else() # Native/Desktop build else() set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") diff --git a/examples/example_sdl2_wgpu/README.md b/examples/example_sdl2_wgpu/README.md index cdfd032da..afba7b857 100644 --- a/examples/example_sdl2_wgpu/README.md +++ b/examples/example_sdl2_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt index 0b8dc48e9..2f3d48f62 100644 --- a/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/examples/example_sdl3_wgpu/CMakeLists.txt @@ -95,7 +95,7 @@ else() # Native/Desktop build else() set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") diff --git a/examples/example_sdl3_wgpu/README.md b/examples/example_sdl3_wgpu/README.md index bd7c33652..35857be9e 100644 --- a/examples/example_sdl3_wgpu/README.md +++ b/examples/example_sdl3_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/imgui.cpp b/imgui.cpp index eebffff22..51aa02f25 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -498,7 +498,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate understanding which font input is providing which glyph. - Fonts: **IMPORTANT** on Thread Safety: - - A few functions such as font->CalcTextSizeA() were, by sheer luck (== accidentally) thread-safe even thou we had never provided that guarantee. They are definitively not thread-safe anymore as new glyphs may be loaded. + - A few functions such as font->CalcTextSizeA() were, by sheer luck (== accidentally) thread-safe even though we had never provided that guarantee. They are definitively not thread-safe anymore as new glyphs may be loaded. - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font". - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. @@ -1496,7 +1496,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) + ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axes) 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. @@ -3466,7 +3466,8 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) if (is_nav_request) { data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringRect.Min.y, g.NavScoringRect.Max.y, nav_off_min, nav_off_max)); - data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, nav_off_min, nav_off_max)); + if (!g.NavScoringNoClipRect.IsInverted()) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, nav_off_min, nav_off_max)); } if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1) data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); @@ -4046,6 +4047,9 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl return; if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) return; + + // We don't early out on 'window->Flags & ImGuiWindowFlags_NoNavInputs' because it would be inconsistent with + // other code directly checking NavCursorVisible. Instead we aim for NavCursorVisible to always be false. ImGuiWindow* window = g.CurrentWindow; if (window->DC.NavHideHighlightOneFrame) return; @@ -4675,13 +4679,13 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; if (window) { - bool backup_skip_items = window->SkipItems; - window->SkipItems = false; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) { ImGuiViewport* viewport = window->Viewport; g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() } + const bool backup_skip_items = window->SkipItems; + window->SkipItems = false; ImGui::UpdateCurrentFontSize(0.0f); window->SkipItems = backup_skip_items; ImGui::NavUpdateCurrentWindowIsScrollPushableX(); @@ -5350,7 +5354,7 @@ void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* nod StartMouseMovingWindow(window); } -// This is not 100% symetric with StartMouseMovingWindow(). +// This is not 100% symmetric with StartMouseMovingWindow(). // We do NOT clear ActiveID, because: // - It would lead to rather confusing recursive code paths. Caller can call ClearActiveID() if desired. // - Some code intentionally cancel moving but keep the ActiveID to lock inputs (e.g. code path taken when clicking a disabled item). @@ -5458,7 +5462,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() StartMouseMovingWindow(hovered_window); //-V595 // FIXME: In principle we might be able to call StopMouseMovingWindow() below. - // Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symetrical, at the later doesn't clear ActiveId. + // Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symmetrical, at the later doesn't clear ActiveId. // Cancel moving if clicked outside of title bar if ((hovered_window->BgClickFlags & ImGuiWindowBgClickFlags_Move) == 0) // set by io.ConfigWindowsMoveFromTitleBarOnly @@ -7006,7 +7010,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont size_desired[ImGuiAxis_Y] = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y; // Determine maximum window size - // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction + // Child windows are laid within their parent (unless they are also popups/menus) and thus have no restriction ImVec2 size_max = ImVec2(FLT_MAX, FLT_MAX); if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || (window->Flags & ImGuiWindowFlags_Popup) != 0) { @@ -8572,7 +8576,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Set default BgClickFlags - // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overriden by user code. + // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overridden by user code. // FIXME: The general intent is that we will later expose config options to default to enable scrolling + select scrolling mouse button. window->BgClickFlags = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->BgClickFlags : (g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move); @@ -9629,16 +9633,6 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) g.Style.FontSizeBase = g.FontSizeBase; - // Early out to avoid hidden window keeping bakes referenced and out of GC reach. - // However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching. - // FIXME: perhaps g.FontSize should be updated? - if (window != NULL && window->SkipItems) - { - ImGuiTable* table = g.CurrentTable; - if (table == NULL || (table->CurrentColumn != -1 && table->Columns[table->CurrentColumn].IsSkipItems == false)) // See 8465#issuecomment-2951509561 and #8865. Ideally the SkipItems=true in tables would be amended with extra data. - return; - } - // Restoring is pretty much only used by PopFont() float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; if (final_size == 0.0f) @@ -9668,10 +9662,24 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) final_size = ImClamp(final_size, 1.0f, IMGUI_FONT_SIZE_MAX); if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; + g.FontSize = final_size; + g.DrawListSharedData.FontSize = g.FontSize; + + // Early out to avoid hidden window keeping bakes referenced and out of GC reach. + // - However this leave a pretty subtle and damning error surface area if g.FontBaked was mismatching. + // Probably needs to be reevaluated into e.g. setting g.FontBaked = nullptr to mark it as dirty. + // - Note that 'PushFont(); Begin(); End(); PopFont()' from within any collapsed window is not compromised, because Begin() calls SetCurrentWindow()->...->UpdateCurrentSize() + if (window != NULL && window->SkipItems) + { + ImGuiTable* table = g.CurrentTable; + const bool allow_early_out = table == NULL || (table->CurrentColumn != -1 && table->Columns[table->CurrentColumn].IsSkipItems == false); // See 8465#issuecomment-2951509561 and #8865. Ideally the SkipItems=true in tables would be amended with extra data. + if (allow_early_out) + return; + } + g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; - g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontBakedScale; } @@ -13663,7 +13671,9 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind void ImGui::SetNavCursorVisible(bool visible) { ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAlways) + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + visible = false; + else if (g.IO.ConfigNavCursorVisibleAlways) visible = true; g.NavCursorVisible = visible; } @@ -13672,7 +13682,9 @@ void ImGui::SetNavCursorVisible(bool visible) void ImGui::SetNavCursorVisibleAfterMove() { ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAuto) + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavCursorVisible = false; + else if (g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = true; g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; } @@ -14622,7 +14634,7 @@ void ImGui::NavUpdateCreateMoveRequest() IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitResult.ID = 0; - if (g.IO.ConfigNavCursorVisibleAuto) + if (g.IO.ConfigNavCursorVisibleAuto) // NO check for _NoNavInputs here as we assume MoveRequests cannot be created. g.NavCursorVisible = true; } @@ -23245,7 +23257,7 @@ void ImGui::DebugNodeFont(ImFont* font) ImFontBaked* baked = &atlas->Builder->BakedPool[baked_n]; if (baked->OwnerFont != font) continue; - PushID(baked_n); + PushID(baked->BakedId); if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.2f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) { if (SmallButton("Load all")) diff --git a/imgui.h b/imgui.h index 1d511bf1c..a194b59e1 100644 --- a/imgui.h +++ b/imgui.h @@ -3947,7 +3947,7 @@ struct ImFontBaked unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) unsigned int WantDestroy:1; // 0 // // Queued for destroy unsigned int LoadNoFallback:1; // 0 // // Disable loading fallback in lower-level calls. - unsigned int LoadNoRenderOnLayout:1;// 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantagous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw. + unsigned int LoadNoRenderOnLayout:1;// 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantageous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw. int LastUsedFrame; // 4 // // Record of that time this was bounds ImGuiID BakedId; // 4 // // Unique ID for this baked storage ImFont* OwnerFont; // 4-8 // in // Parent font diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8018d2c69..9bdce3c70 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8002,6 +8002,11 @@ static void DemoWindowInputs() ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat); ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive); ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused); + ImGui::Indent(); + ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteFocused); + ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", &route_options, ImGuiInputFlags_RouteOverActive); + ImGui::EndDisabled(); + ImGui::Unindent(); ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal); ImGui::Indent(); ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2b5f3311e..486ac3e65 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3701,7 +3701,7 @@ void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src) IM_UNUSED(atlas); // IF YOU GET A CRASH IN THE IM_FREE() CALL HERE AND USED AddFontFromMemoryTTF(): // - DUE TO LEGACY REASON AddFontFromMemoryTTF() TRANSFERS MEMORY OWNERSHIP BY DEFAULT. - // - IT WILL THEREFORE CRASH WHEN PASSED DATA WHICH MAY NOT BE FREEED BY IMGUI. + // - IT WILL THEREFORE CRASH WHEN PASSED DATA WHICH MAY NOT BE FREED BY IMGUI. // - USE `ImFontConfig font_cfg; font_cfg.FontDataOwnedByAtlas = false; io.Fonts->AddFontFromMemoryTTF(....., &cfg);` to disable passing ownership/ // WE WILL ADDRESS THIS IN A FUTURE REWORK OF THE API. if (src->FontDataOwnedByAtlas) diff --git a/imgui_internal.h b/imgui_internal.h index e3954bd68..adea4c4b0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2558,7 +2558,7 @@ struct ImGuiContext ImGuiDir NavMoveDirForDebug; ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. - ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted + ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted. Unset/invalid if inverted. int NavScoringDebugCount; // Metrics for debugging int NavTabbingDir; // Generally -1 or +1, 0 when tabbing without a nav id int NavTabbingCounter; // >0 when counting items for tabbing @@ -3835,6 +3835,7 @@ namespace ImGui IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); IMGUI_API void TableRemove(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index d4e57e831..6eaa973af 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -699,7 +699,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) } // Handle reordering request - // Note: we don't clear ReorderColumn after handling the request. + // Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test). if (table->InstanceCurrent == 0) { if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) @@ -711,24 +711,12 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) // In the configuration below, moving C to the right of E will lead to: // ... C [D] E ---> ... [D] E C (Column name/index) // ... 2 3 4 ... 2 3 4 (Display order) - const int reorder_dir = table->ReorderColumnDir; - IM_ASSERT(reorder_dir == -1 || reorder_dir == +1); + IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1); IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable); ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn]; - ImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; - IM_UNUSED(dst_column); - const int src_order = src_column->DisplayOrder; - const int dst_order = dst_column->DisplayOrder; - src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; - for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) - table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; - IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); - - // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; + ImGuiTableColumn* dst_column = &table->Columns[(table->ReorderColumnDir < 0) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; + TableSetColumnDisplayOrder(table, table->ReorderColumn, dst_column->DisplayOrder); table->ReorderColumnDir = 0; - table->IsSettingsDirty = true; } } @@ -742,6 +730,31 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) } } +// Note that TableSetupScrollFreeze() enforce a display order range for frozen columns. +// So reordering a column across the frozen column barrier is illegal and will be undone. +void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + IM_ASSERT(dst_order >= 0 && dst_order < table->ColumnsCount); + + ImGuiTableColumn* src_column = &table->Columns[column_n]; + const int src_order = src_column->DisplayOrder; + if (src_order == dst_order) + return; + const int reorder_dir = (dst_order < src_order) ? -1 : +1; + + src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; + for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) + table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; + //IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); + + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. + // FIXME-OPT: If this is called multiple times we'd effectively have a O(N^2) thing going on. + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[table->Columns[n].DisplayOrder] = (ImGuiTableColumnIdx)n; + table->IsSettingsDirty = true; +} + // Adjust flags: default width mode + stretch columns are not allowed when auto extending static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) {