Merge branch 'master' into docking w/ custom fix in Scrollbar()

# Conflicts:
#	backends/imgui_impl_win32.cpp
#	imgui.cpp
This commit is contained in:
ocornut
2026-01-29 17:50:41 +01:00
8 changed files with 76 additions and 29 deletions
+1
View File
@@ -639,6 +639,7 @@ void ImGui_ImplSDLGPU3_DestroyDeviceObjects()
if (bd->VertexShader) { SDL_ReleaseGPUShader(v->Device, bd->VertexShader); bd->VertexShader = nullptr; }
if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->Device, bd->FragmentShader); bd->FragmentShader = nullptr; }
if (bd->TexSamplerLinear) { SDL_ReleaseGPUSampler(v->Device, bd->TexSamplerLinear); bd->TexSamplerLinear = nullptr; }
if (bd->TexSamplerNearest) { SDL_ReleaseGPUSampler(v->Device, bd->TexSamplerNearest); bd->TexSamplerNearest = nullptr; }
if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; }
}
+8
View File
@@ -23,6 +23,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-01-28: Inputs: Minor optimization not submitting gamepad input if packet number has not changed (reworked from 2025-09-23 attempt). (#9202, #8556)
// 2026-01-26: [Docking] Fixed an issue from 1.90.5 where newly appearing windows that are not parented to the main viewport don't have task bar icon appear before the windows was explicited refocused. (#7354, #8669)
// 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961)
// 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state.
@@ -142,6 +143,7 @@ struct ImGui_ImplWin32_Data
HMODULE XInputDLL;
PFN_XInputGetCapabilities XInputGetCapabilities;
PFN_XInputGetState XInputGetState;
DWORD XInputPacketNumber;
#endif
ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); }
@@ -423,6 +425,9 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io)
if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
if (bd->XInputPacketNumber != 0 && bd->XInputPacketNumber == xinput_state.dwPacketNumber)
return;
bd->XInputPacketNumber = xinput_state.dwPacketNumber;
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
@@ -877,6 +882,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA
case WM_SETFOCUS:
case WM_KILLFOCUS:
io.AddFocusEvent(msg == WM_SETFOCUS);
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
bd->XInputPacketNumber = 0; // FIXME: Technically, calling io.ClearInputKeys() directly would require this as well.
#endif
return 0;
case WM_INPUTLANGCHANGE:
ImGui_ImplWin32_UpdateKeyboardCodePage(io);
+10
View File
@@ -172,6 +172,10 @@ Other Changes:
- Fixed remote/shortcut InputText() not teleporting mouse cursor when
nav cursor is visible and `io.ConfigNavMoveSetMousePos` is enabled.
- Fixed a looping/wrapping issue when done in menu layer. (#9178)
- Fixed speed scale for resizing/moving with keyboard/gamepad. We incorrectly
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)
- 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
@@ -180,6 +184,8 @@ Other Changes:
nesting a tooltip in a disabled block. (#9180, #7640) [@RegimantasSimkus]
- Added GetItemFlags() in public API for consistency and to expose generic
flags of last submitted item. (#9127)
- Log/Capture: fixed erroneously injecting extra carriage returns in output
buffer when ItemSpacing.y > FramePadding.y + 1.
- Images:
- Added style.ImageRounding, ImGuiStyleVar_ImageRounding to configure
rounding of Image() widgets. (#2942, #845)
@@ -198,6 +204,8 @@ Other Changes:
- Debug Log: fixed incorrectly printing characters in IO log when submitting
non-ASCII values to `io.AddInputCharacter()`. (#9099)
- Debug Log: can output to debugger on Windows. (#5855)
- Demo:
- Slightly improve Selectable() demos. (#9193)
- Backends:
- DirectX10: added `SamplerNearest` in `ImGui_ImplDX10_RenderState`.
(+renamed `SamplerDefault` to `SamplerLinear`, which was tagged as beta API)
@@ -221,6 +229,8 @@ Other Changes:
devices. (#8784) [@FelixStach]
- Win32: handle `WM_IME_CHAR`/`WM_IME_COMPOSITION` to support Unicode inputs on
MBCS (non-Unicode) Windows. (#9099, #3653, #5961) [@ulhc, @ocornut, @Othereum]
- Win32: minor optimization not submitting gamepad input if packet number has not
changed (reworked previous 1.92.4). (#9202, #8556) [@AhmedSamyMousa, @MidTerm-CN]
- Examples:
- Win32+DirectX12: ignore seemingly incorrect `D3D12_MESSAGE_ID_FENCE_ZERO_WAIT`
warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron]
+9 -4
View File
@@ -7330,7 +7330,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, int* border_hove
if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f)
{
const float NAV_RESIZE_SPEED = 600.0f;
const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y);
const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * GetScale();
g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step;
g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size
g.NavWindowingToggleLayer = false;
@@ -7486,10 +7486,12 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
bg_col = 0;
if (bg_col & IM_COL32_A_MASK)
{
ImRect bg_rect(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size);
ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom;
ImDrawList* bg_draw_list = window->DockIsActive ? window->DockNode->HostWindow->DrawList : window->DrawList;
if (window->DockIsActive)
bg_draw_list->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG);
bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
bg_draw_list->AddRectFilled(bg_rect.Min, bg_rect.Max, bg_col, window_rounding, bg_rounding_flags);
if (window->DockIsActive)
bg_draw_list->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_FG);
}
@@ -11121,6 +11123,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
#endif
// Remaining events will be processed on the next frame
// FIXME-MULTITHREADING: io.AddKeyEvent() etc. calls are mostly thread-safe apart from the fact they push to this
// queue which may be resized here. Could potentially rework this to narrow down the section needing a mutex? (#5772)
if (event_n == g.InputEventsQueue.Size)
g.InputEventsQueue.resize(0);
else
@@ -13477,6 +13481,7 @@ void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
}
// Note technically focus related but rather adjacent and close to BringWindowToFocusFront()
// FIXME-FOCUS: Could opt-in/opt-out enable modal check like in FocusWindow().
void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
@@ -15245,7 +15250,7 @@ static void ImGui::NavUpdateWindowing()
if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f)
{
const float NAV_MOVE_SPEED = 800.0f;
const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
const float move_step = NAV_MOVE_SPEED * io.DeltaTime * GetScale();
g.NavWindowingAccumDeltaPos += nav_move_dir * move_step;
g.NavHighlightItemUnderNav = true;
ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos);
@@ -15800,7 +15805,7 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char*
if (!text_end)
text_end = FindRenderedTextEnd(text, text_end);
const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);
const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + ImMax(g.Style.FramePadding.y, g.Style.ItemSpacing.y) + 1);
if (ref_pos)
g.LogLinePosY = ref_pos->y;
if (log_new_line)
+1 -1
View File
@@ -1966,7 +1966,7 @@ enum ImGuiColorEditFlags_
ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview.
ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker).
ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead.
ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source.
ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target/source. ColorButton: disable drag and drop source.
ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default)
ImGuiColorEditFlags_NoColorMarkers = 1 << 11, // // ColorEdit: disable rendering R/G/B/A color marker. May also be disabled globally by setting style.ColorMarkerSize = 0.
+43 -10
View File
@@ -2395,15 +2395,45 @@ static void DemoWindowWidgetsSelectables()
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
if (ImGui::TreeNode("Rendering more items on the same line"))
IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line");
if (ImGui::TreeNode("Multiple items on the same line"))
{
// (1) Using SetNextItemAllowOverlap()
// (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
static bool selected[3] = { false, false, false };
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
// (1)
// - Using SetNextItemAllowOverlap()
// - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
{
static bool selected[3] = {};
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
}
// (2)
// - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap()
// - No visible label, display contents inside the selectable bounds.
// - We don't maintain actual selection in this example to keep things simple.
ImGui::Spacing();
{
static bool checked[5] = {};
static int selected_n = 0;
const float color_marker_w = ImGui::CalcTextSize("x").x;
for (int n = 0; n < 5; n++)
{
ImGui::PushID(n);
ImGui::AlignTextToFramePadding();
if (ImGui::Selectable("##selectable", selected_n == n, ImGuiSelectableFlags_AllowOverlap))
selected_n = n;
ImGui::SameLine(0, 0);
ImGui::Checkbox("##check", &checked[n]);
ImGui::SameLine();
ImVec4 color((n & 1) ? 1.0f : 0.2f, (n & 2) ? 1.0f : 0.2f, 0.2f, 1.0f);
ImGui::ColorButton("##color", color, ImGuiColorEditFlags_NoTooltip, ImVec2(color_marker_w, 0));
ImGui::SameLine();
ImGui::Text("Some label");
ImGui::PopID();
}
}
ImGui::TreePop();
}
@@ -2454,13 +2484,14 @@ static void DemoWindowWidgetsSelectables()
if (winning_state)
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
const float size = ImGui::CalcTextSize("Sailor").x;
for (int y = 0; y < 4; y++)
for (int x = 0; x < 4; x++)
{
if (x > 0)
ImGui::SameLine();
ImGui::PushID(y * 4 + x);
if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(size, size)))
{
// Toggle clicked cell + toggle neighbors
selected[y][x] ^= 1;
@@ -2483,7 +2514,9 @@ static void DemoWindowWidgetsSelectables()
"By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
"basis using PushStyleVar(). You'll probably want to always keep your default situation to "
"left-align otherwise it becomes difficult to layout multiple items on a same line");
static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
const float size = ImGui::CalcTextSize("(1.0,1.0)").x;
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
@@ -2493,7 +2526,7 @@ static void DemoWindowWidgetsSelectables()
sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
if (x > 0) ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(size, size));
ImGui::PopStyleVar();
}
}
+1
View File
@@ -3384,6 +3384,7 @@ namespace ImGui
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx);
IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx);
inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: I don't want to formalize this just yet. Because reasons. Please don't use.
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
+3 -14
View File
@@ -988,20 +988,8 @@ void ImGui::Scrollbar(ImGuiAxis axis)
// Calculate scrollbar bounding box
ImRect bb = GetWindowScrollbarRect(window, axis);
ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone;
if (axis == ImGuiAxis_X)
{
rounding_corners |= ImDrawFlags_RoundCornersBottomLeft;
if (!window->ScrollbarY)
rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
}
else
{
if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar))
rounding_corners |= ImDrawFlags_RoundCornersTopRight;
if (!window->ScrollbarX)
rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
}
ImRect host_rect = (window->DockIsActive ? window->DockNode->HostWindow : window)->Rect();
ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, host_rect, g.Style.WindowBorderSize);
float size_visible = window->InnerRect.Max[axis] - window->InnerRect.Min[axis];
float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f;
ImS64 scroll = (ImS64)window->Scroll[axis];
@@ -6491,6 +6479,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
}
// Initialize/override default color options
// FIXME: Could be moved to a simple IO field.
void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags)
{
ImGuiContext& g = *GImGui;