diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 53af3098d..01ad4e6dc 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -2,7 +2,7 @@ // This needs to be used along with the SDL3 Platform Backend // Implemented features: -// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. +// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. @@ -24,6 +24,8 @@ // CHANGELOG // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988) +// 2025-08-08: Expose SamplerDefault and SamplerCurrent in ImGui_ImplSDLGPU3_RenderState. Allow callback to change sampler. // 2025-06-25: Mapping transfer buffer for texture update use cycle=true. Fixes artifacts e.g. on Metal backend. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture(). // 2025-04-28: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. @@ -38,11 +40,6 @@ #include "imgui_impl_sdlgpu3_shaders.h" // SDL_GPU Data -struct ImGui_ImplSDLGPU3_Texture -{ - SDL_GPUTexture* Texture = nullptr; - SDL_GPUTextureSamplerBinding TextureSamplerBinding = { nullptr, nullptr }; -}; // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData() struct ImGui_ImplSDLGPU3_FrameData @@ -86,12 +83,13 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } -static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass * render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) +static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplSDLGPU3_RenderState* render_state, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) { - //ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + render_state->SamplerCurrent = render_state->SamplerCurrent = bd->TexSampler; // Bind graphics pipeline - SDL_BindGPUGraphicsPipeline(render_pass,pipeline); + SDL_BindGPUGraphicsPipeline(render_pass, pipeline); // Bind Vertex And Index Buffers if (draw_data->TotalVtxCount > 0) @@ -229,12 +227,19 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe if (pipeline == nullptr) pipeline = bd->Pipeline; - ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); - // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + // Setup render state structure (for callbacks and custom texture bindings) + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + ImGui_ImplSDLGPU3_RenderState render_state; + render_state.Device = bd->InitInfo.Device; + render_state.SamplerDefault = render_state.SamplerCurrent = bd->TexSampler; + platform_io.Renderer_RenderState = &render_state; + + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); + // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; @@ -249,7 +254,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); else pcmd->UserCallback(draw_list, pcmd); } @@ -276,9 +281,14 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe SDL_SetGPUScissor(render_pass,&scissor_rect); // Bind DescriptorSet with font or user texture - SDL_BindGPUFragmentSamplers(render_pass, 0, (SDL_GPUTextureSamplerBinding*)pcmd->GetTexID(), 1); + SDL_GPUTextureSamplerBinding texture_sampler_binding; + texture_sampler_binding.texture = (SDL_GPUTexture*)(intptr_t)pcmd->GetTexID(); + texture_sampler_binding.sampler = render_state.SamplerCurrent; + SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_sampler_binding, 1); // Draw + // **IF YOU GET A CRASH HERE** In 1.92.2 on 2025/08/08 we have changed ImTextureID to store 'SDL_GPUTexture*' instead of storing 'SDL_GPUTextureSamplerBinding'. + // Any code loading custom texture using this backend needs to be updated. SDL_DrawGPUIndexedPrimitives(render_pass, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } } @@ -297,18 +307,13 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; - SDL_GPUTextureSamplerBinding* binding = (SDL_GPUTextureSamplerBinding*)(intptr_t)tex->BackendUserData; - IM_ASSERT(backend_tex->Texture == binding->texture); - SDL_ReleaseGPUTexture(bd->InitInfo.Device, backend_tex->Texture); - IM_DELETE(backend_tex); + SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID(); + if (raw_tex != nullptr) + SDL_ReleaseGPUTexture(bd->InitInfo.Device, raw_tex); // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) tex->SetTexID(ImTextureID_Invalid); tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) @@ -322,7 +327,6 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); - ImGui_ImplSDLGPU3_Texture* backend_tex = IM_NEW(ImGui_ImplSDLGPU3_Texture)(); // Create texture SDL_GPUTextureCreateInfo texture_info = {}; @@ -335,19 +339,16 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) texture_info.num_levels = 1; texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; - backend_tex->Texture = SDL_CreateGPUTexture(v->Device, &texture_info); - backend_tex->TextureSamplerBinding.texture = backend_tex->Texture; - backend_tex->TextureSamplerBinding.sampler = bd->TexSampler; - IM_ASSERT(backend_tex->Texture && "Failed to create font texture, call SDL_GetError() for more info"); + SDL_GPUTexture* raw_tex = SDL_CreateGPUTexture(v->Device, &texture_info); + IM_ASSERT(raw_tex != nullptr && "Failed to create font texture, call SDL_GetError() for more info"); // Store identifiers - tex->SetTexID((ImTextureID)(intptr_t)&backend_tex->TextureSamplerBinding); - tex->BackendUserData = backend_tex; + tex->SetTexID((ImTextureID)(intptr_t)raw_tex); } if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) { - ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData; + SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID(); IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! @@ -385,7 +386,7 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) transfer_info.transfer_buffer = bd->TexTransferBuffer; SDL_GPUTextureRegion texture_region = {}; - texture_region.texture = backend_tex->Texture; + texture_region.texture = raw_tex; texture_region.x = (Uint32)upload_x; texture_region.y = (Uint32)upload_y; texture_region.w = (Uint32)upload_w; diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 439dba233..39eb7216e 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -2,7 +2,7 @@ // This needs to be used along with the SDL3 Platform Backend // Implemented features: -// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. +// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. @@ -50,4 +50,14 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); // (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); +// [BETA] Selected render state data shared with callbacks. +// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLGPU3_RenderDrawData() call. +// (Please open an issue if you feel you need access to more data) +struct ImGui_ImplSDLGPU3_RenderState +{ + SDL_GPUDevice* Device; + SDL_GPUSampler* SamplerDefault; // Default sampler (bilinear filtering) + SDL_GPUSampler* SamplerCurrent; // Current sampler (may be changed by callback) +}; + #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 4e185dfdd..73aba8221 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -617,6 +617,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) + VkDescriptorSet last_desc_set = VK_NULL_HANDLE; int global_vtx_offset = 0; int global_idx_offset = 0; for (const ImDrawList* draw_list : draw_data->CmdLists) @@ -632,6 +633,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); else pcmd->UserCallback(draw_list, pcmd); + last_desc_set = VK_NULL_HANDLE; } else { @@ -657,7 +659,9 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Bind DescriptorSet with font or user texture VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID(); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); + if (desc_set != last_desc_set) + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); + last_desc_set = desc_set; // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4a2683e6e..f5308a8fa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,12 +43,24 @@ Breaking Changes: - Tabs: Renamed ImGuiTabBarFlags_FittingPolicyResizeDown to ImGuiTabBarFlags_FittingPolicyShrink. Kept inline redirection enum (will obsolete). (#261, #351) +- Backends: SDL_GPU3: changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, + which is more natural and easier for user to manage. If you need to change the current sampler, + you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988) Other Changes: +- Fonts: fixed an issue when a font using MergeMode has a reference size + specified but the target font doesn't. Usually either all fonts should + have a reference size (only required when specifying e.g. GlyphOffset), + or none should have a reference size. +- Fonts: fixed a crash when changing texture format when using a legacy + backend. Most commonly would happen when calling GetTexDataAsRGBA32() + then immediately GetTexDataAsAlpha8(). (#8824) - Windows: fixed an issue where resizable child windows would emit border logic when hidden/non-visible (e.g. when in a docked window that is not selected), impacting code not checking for BeginChild() return value. (#8815) +- Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: + ImFontAtlas() was incorrectly cleared with zeroes. (#8860, #8745) [@cfillion] - Tables: fixed TableGetRowIndex() which never correctly worked when using a clipper (it exists for consistency but is almost never used, as it is often more convenient to use index in caller-code, whereas TableGetRowIndex() @@ -68,6 +80,9 @@ Other Changes: any potential shrinking is applied. - Tabs: fixed tab bar underline not drawing below scroll buttons, when they are enabled (minor regression from 1.90). (#6820, #4859, #5022, #5239) +- Tabs: made scrolling buttons never keyboard/gamepad navigation candidates. +- Nav: fixed a bug where GamepadMenu button couldn't toggle between main and + menu layers while navigating a Modal window. (#8834) - Error Handling: minor improvements to error handling for TableGetSortSpecs() and TableSetBgColor() calls. (#1651, #8499) - Misc: fixed building with IMGUI_DISABLE_DEBUG_TOOLS only. (#8796) @@ -77,12 +92,18 @@ Other Changes: - CI: Added SDL3 builds to MacOS and Windows. (#8819, #8778) [@scribam] - CI: Updated Windows CI to use a more recent SDL2. (#8819, #8778) [@scribam] - Examples: SDL3+Metal: added SDL3+Metal example. (#8827, #8825) [@shi-yan] +- Examples: SDL3+SDL_GPU: use SDL_WaitAndAcquireGPUSwapchainTexture() instead + of SDL_AcquireGPUSwapchainTexture(). (#8830) [@itsdanott] - Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) [@tim-rex] - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) [@Daandelange] +- Backends: SDL_GPU3: expose current SDL_GPUSampler* in the ImGui_ImplSDLGPU3_RenderState + struct. (#8866, #8163, #7998, #7988) - Backends: Vulkan: Fixed texture update corruption introduced in 1.92.0, affecting some drivers/setups. (#8801, #8755, #8840) [@Retro52, @Miolith] +- Backends: Vulkan: Avoid calling vkCmdBindDescriptorSets() when texture + has not changed. (#8666) [@micb25] Docking+Viewports Branch: @@ -113,6 +134,8 @@ Changes: to pass full range of information into e.g. FreeType's face_index, as higher bits are used from FreeType 2.6.1. (#8775) [@Valakor] (the field has been erroneously reduced from 32-bits to 8-bit in 1.92.0) +- Fonts, Tables: fixed PushFont() having no effect when called after submitting + a hidden column. (#8865) - Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 8af57e1cd..d64407bd5 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -60,7 +60,7 @@ int main(int, char**) printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError()); return -1; } - SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_MAILBOX); + SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC); // Setup Dear ImGui context IMGUI_CHECKVERSION(); @@ -195,7 +195,7 @@ int main(int, char**) SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpu_device); // Acquire a GPU command buffer SDL_GPUTexture* swapchain_texture; - SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture + SDL_WaitAndAcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture if (swapchain_texture != nullptr && !is_minimized) { diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 083c2af3a..a0c21d9ea 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -15,7 +15,7 @@ #define WIN32_LEAN_AND_MEAN #endif #include -#include +#include #include // Data stored per platform window diff --git a/imgui.cpp b/imgui.cpp index af369dab0..95f0c2b47 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -400,6 +400,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - 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. + - 2025/08/08 (1.92.2) - Backends: SDL_GPU3: Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988) - 2025/07/31 (1.92.2) - Tabs: Renamed ImGuiTabBarFlags_FittingPolicyResizeDown to ImGuiTabBarFlags_FittingPolicyShrink. Kept inline redirection enum (will obsolete). - 2025/06/25 (1.92.0) - Layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM to extend parent window/cell boundaries. Replaced with assert/tooltip that would already happens if previously using IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#5548, #4510, #3355, #1760, #1490, #4152, #150) @@ -9447,11 +9448,14 @@ 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, so for now we null it. + // 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) - if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data. + { + 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; @@ -14907,9 +14911,16 @@ static void ImGui::NavUpdateWindowing() const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); - const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id); + const bool start_toggling_with_gamepad = nav_gamepad_active && !g.NavWindowingTarget && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id); + const bool start_windowing_with_gamepad = allow_windowing && start_toggling_with_gamepad; const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! bool just_started_windowing_from_null_focus = false; + if (start_toggling_with_gamepad) + { + g.NavWindowingToggleLayer = true; // Gamepad starts toggling layer + g.NavWindowingToggleKey = ImGuiKey_NavGamepadMenu; + 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)) { @@ -14917,7 +14928,6 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); - g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer g.NavWindowingInputSource = g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; if (g.NavWindow == NULL) just_started_windowing_from_null_focus = true; @@ -22805,8 +22815,8 @@ void ImGui::DebugNodeFont(ImFont* font) for (int src_n = 0; src_n < font->Sources.Size; src_n++) { ImFontConfig* src = font->Sources[src_n]; - if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", - src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y)) + if (TreeNode(src, "Input %d: \'%s\' [%d], Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", + src_n, src->Name, src->FontNo, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y)) { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; Text("Loader: '%s'", loader->Name ? loader->Name : "N/A"); diff --git a/imgui.h b/imgui.h index 1b73a3686..895cce4ff 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.2 WIP" -#define IMGUI_VERSION_NUM 19213 +#define IMGUI_VERSION_NUM 19214 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. @@ -4228,24 +4228,24 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.92.0 (from June 2025) - static inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); } + inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); } IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFont(NULL, style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. // OBSOLETED in 1.91.9 (from February 2025) IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) - static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } - static inline void PopButtonRepeat() { PopItemFlag(); } - static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } - static inline void PopTabStop() { PopItemFlag(); } + inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } + inline void PopButtonRepeat() { PopItemFlag(); } + inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } + inline void PopTabStop() { PopItemFlag(); } IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! // OBSOLETED in 1.90.0 (from September 2023) - static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } - static inline void EndChildFrame() { EndChild(); } + inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } + inline void EndChildFrame() { EndChild(); } //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } + inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); // OBSOLETED in 1.89.7 (from June 2023) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ef4459e55..9aa05bf32 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2637,6 +2637,7 @@ ImFontAtlas::ImFontAtlas() TexMinHeight = 128; TexMaxWidth = 8192; TexMaxHeight = 8192; + TexRef._TexID = ImTextureID_Invalid; RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. TexNextUniqueID = 1; FontNextUniqueID = 1; @@ -3368,11 +3369,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat) - { - ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); - ImFontAtlasBuildDestroy(atlas); - ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y); - } + ImFontAtlasBuildClear(atlas); if (atlas->Builder == NULL) ImFontAtlasBuildInit(atlas); @@ -4578,15 +4575,16 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* } src->FontLoaderData = bd_font_data; + const float ref_size = src->DstFont->Sources[0]->SizePixels; if (src->MergeMode && src->SizePixels == 0.0f) - src->SizePixels = src->DstFont->Sources[0]->SizePixels; + src->SizePixels = ref_size; if (src->SizePixels >= 0.0f) bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); - if (src->MergeMode && src->SizePixels != 0.0f) - bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit + if (src->MergeMode && src->SizePixels != 0.0f && ref_size != 0.0f) + bd_font_data->ScaleFactor *= src->SizePixels / ref_size; // FIXME-NEWATLAS: Should tidy up that a bit return true; } diff --git a/imgui_internal.h b/imgui_internal.h index 7cb3bc6ee..e8c237bb8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2533,8 +2533,8 @@ struct ImGuiContext float NavWindowingTimer; float NavWindowingHighlightAlpha; ImGuiInputSource NavWindowingInputSource; - bool NavWindowingToggleLayer; - ImGuiKey NavWindowingToggleKey; + bool NavWindowingToggleLayer; // Set while Alt or GamepadMenu is held, may be cleared by other operations, and processed when releasing the key. + ImGuiKey NavWindowingToggleKey; // Keyboard/gamepad key used when toggling to menu layer. ImVec2 NavWindowingAccumDeltaPos; ImVec2 NavWindowingAccumDeltaSize; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3f7f45f58..e7c9cda1b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1846,7 +1846,7 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc } ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); // Sort largest first, smallest last. int count_same_width = 1; - while (width_excess > 0.0f && count_same_width < count) + while (width_excess > 0.001f && count_same_width < count) { while (count_same_width < count && items[0].Width <= items[count_same_width].Width) count_same_width++; @@ -4950,7 +4950,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Determine if we turn Enter into a \n character bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; - if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line != io.KeyCtrl)) { validated = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) @@ -9703,7 +9703,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Horizontal scrolling buttons // Important: note that TabBarScrollButtons() will alter BarRect.Max.x. const bool can_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) || (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed); - tab_bar->ScrollButtonEnabled = ((width_all_tabs_after_min_width_shrink > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && can_scroll); + const float width_all_tabs_to_use_for_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) ? tab_bar->WidthAllTabs : width_all_tabs_after_min_width_shrink; + tab_bar->ScrollButtonEnabled = ((width_all_tabs_to_use_for_scroll > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && can_scroll); if (tab_bar->ScrollButtonEnabled) if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) { @@ -10101,7 +10102,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) PushStyleColor(ImGuiCol_Text, arrow_col); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); + PushItemFlag(ImGuiItemFlags_ButtonRepeat | ImGuiItemFlags_NoNav, true); const float backup_repeat_delay = g.IO.KeyRepeatDelay; const float backup_repeat_rate = g.IO.KeyRepeatRate; g.IO.KeyRepeatDelay = 0.250f;