diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp
index ccb1396d..43b04f6b 100644
--- a/backends/imgui_impl_allegro5.cpp
+++ b/backends/imgui_impl_allegro5.cpp
@@ -174,7 +174,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp
index 9d6fe88e..ab78faf9 100644
--- a/backends/imgui_impl_dx10.cpp
+++ b/backends/imgui_impl_dx10.cpp
@@ -262,7 +262,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp
index c0161016..4c690722 100644
--- a/backends/imgui_impl_dx11.cpp
+++ b/backends/imgui_impl_dx11.cpp
@@ -272,7 +272,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp
index 661ada3a..31fd48f3 100644
--- a/backends/imgui_impl_dx12.cpp
+++ b/backends/imgui_impl_dx12.cpp
@@ -340,7 +340,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp
index f40ad89e..c27836ca 100644
--- a/backends/imgui_impl_dx9.cpp
+++ b/backends/imgui_impl_dx9.cpp
@@ -259,7 +259,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm
index 6027a3a2..df0725b4 100644
--- a/backends/imgui_impl_metal.mm
+++ b/backends/imgui_impl_metal.mm
@@ -515,7 +515,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp
index 8a1d58dd..deed470a 100644
--- a/backends/imgui_impl_opengl2.cpp
+++ b/backends/imgui_impl_opengl2.cpp
@@ -214,7 +214,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp
index 19d79b23..bab232d8 100644
--- a/backends/imgui_impl_opengl3.cpp
+++ b/backends/imgui_impl_opengl3.cpp
@@ -456,7 +456,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
diff --git a/backends/imgui_impl_sdlrenderer.cpp b/backends/imgui_impl_sdlrenderer.cpp
index cd2d3dfb..08a2bb95 100644
--- a/backends/imgui_impl_sdlrenderer.cpp
+++ b/backends/imgui_impl_sdlrenderer.cpp
@@ -1,14 +1,17 @@
// dear imgui: Renderer Backend for SDL_Renderer
// (Requires: SDL 2.0.17+)
-// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer
-// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness.
+// Important to understand: SDL_Renderer is an _optional_ component of SDL.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
+// If your application will want to render any non trivial amount of graphics other than UI,
+// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
+// be difficult to step out of those boundaries.
+// However, we understand it is a convenient choice to get an app started easily.
// Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
// Missing features:
-// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices (SDL_RenderGeometryRaw() is missing a vertex offset).
// [ ] Renderer: Multi-viewport support (multiple windows).
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@@ -162,7 +165,7 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
diff --git a/backends/imgui_impl_sdlrenderer.h b/backends/imgui_impl_sdlrenderer.h
index 269e7d8c..27c054e4 100644
--- a/backends/imgui_impl_sdlrenderer.h
+++ b/backends/imgui_impl_sdlrenderer.h
@@ -1,14 +1,17 @@
// dear imgui: Renderer Backend for SDL_Renderer
// (Requires: SDL 2.0.17+)
-// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer
-// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness.
+// Important to understand: SDL_Renderer is an _optional_ component of SDL.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
+// If your application will want to render any non trivial amount of graphics other than UI,
+// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
+// be difficult to step out of those boundaries.
+// However, we understand it is a convenient choice to get an app started easily.
// Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
// Missing features:
-// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices (SDL_RenderGeometryRaw() is missing a vertex offset).
// [ ] Renderer: Multi-viewport support (multiple windows).
#pragma once
diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp
index 2f151b99..c9de3256 100644
--- a/backends/imgui_impl_vulkan.cpp
+++ b/backends/imgui_impl_vulkan.cpp
@@ -552,7 +552,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp
index 2f621ed8..072f2549 100644
--- a/backends/imgui_impl_wgpu.cpp
+++ b/backends/imgui_impl_wgpu.cpp
@@ -13,6 +13,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2021-11-29: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer()/wgpuRenderPassEncoderSetIndexBuffer().
// 2021-08-24: Fix for latest specs.
// 2021-05-24: Add support for draw_data->FramebufferScale.
// 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
@@ -313,8 +314,8 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
// Bind shader and vertex buffers
- wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, 0);
- wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, 0);
+ wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize);
+ wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize);
wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState);
wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL);
@@ -446,7 +447,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
- if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md
index c878132b..f061d70c 100644
--- a/docs/BACKENDS.md
+++ b/docs/BACKENDS.md
@@ -128,7 +128,10 @@ Once it works, if you really need it you can replace parts of backends with your
and you have high-level systems everywhere.
Suggestion: try using a non-portable backend first (e.g. win32 + underlying graphics API) to get
your desktop builds working first. This will get you running faster and get your acquainted with
-how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API.
+how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API...
+
+Generally:
+It is unlikely you will add value to your project by creating your own backend.
Also:
The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 682bd019..d31e753a 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -125,8 +125,10 @@ Other Changes:
Home/End leads to scrolling. Fixed not setting mouse position when a failed move request (e.g. when
already at edge) reactivates the navigation highlight.
- InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682)
+- Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761)
- InputText: made double-click select word, triple-line select line. Word delimitation logic differs
slightly from the one used by CTRL+arrows. (#2244)
+- InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) [@actondev]
- Clipper: currently focused item is automatically included in clipper range.
Fixes issue where e.g. drag and dropping an item and scrolling ensure the item source location is
still submitted. (#3841, #1725) [@GamingMinds-DanielC, @ocornut]
@@ -136,11 +138,20 @@ Other Changes:
by the clipper to display. (#3841)
- Clipper: fixed content height declaration slightly mismatching the value of when not using a clipper.
(an additional ItemSpacing.y was declared, affecting scrollbar range).
+- Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose
+ tooltip when scrolling. (#143)
+- Metrics: Added a node showing windows in submission order and showing the Begin() stack.
+- Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the
+ io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666]
+- Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups]
+- CI: Add MinGW DLL build to test suite. [@rokups]
- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce
likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling
vkCmdSetScissor() explicitly every frame. (#4644)
-- Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups]
-- CI: Add MinGW DLL build to test suite. [@rokups]
+- Backends: DX12: Fixed DRAW_EMPTY_SCISSOR_RECTANGLE warnings. (#4775)
+- Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and
+ wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the
+ in-flux specs says. (#4766) [@meshula]
Docking+Viewports Branch:
diff --git a/imgui.cpp b/imgui.cpp
index fd1e563b..39905874 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1982,7 +1982,7 @@ void ImGuiStorage::BuildSortByKey()
{
struct StaticFunc
{
- static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
+ static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
{
// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
@@ -1990,8 +1990,7 @@ void ImGuiStorage::BuildSortByKey()
return 0;
}
};
- if (Data.Size > 1)
- ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
+ ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);
}
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
@@ -3169,7 +3168,7 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
{
ImGuiID seed = IDStack.back();
- const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
+ ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
ImGui::KeepAliveID(id);
return id;
@@ -3332,42 +3331,46 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
{
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
- return IsItemFocused();
+ if (!IsItemFocused())
+ return false;
+ }
+ else
+ {
+ // Test for bounding box overlap, as updated as ItemAdd()
+ ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
+ if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
+ return false;
+ IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
+
+ // Test if we are hovering the right window (our window could be behind another window)
+ // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
+ // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
+ // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
+ // the test that has been running for a long while.
+ if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
+ if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
+ return false;
+
+ // Test if another item is active (e.g. being dragged)
+ if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
+ if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
+ return false;
+
+ // Test if interactions on this window are blocked by an active popup or modal.
+ // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
+ if (!IsWindowContentHoverable(window, flags))
+ return false;
+
+ // Test if the item is disabled
+ if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
+ return false;
+
+ // Special handling for calling after Begin() which represent the title bar or tab.
+ // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
+ if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
+ return false;
}
- // Test for bounding box overlap, as updated as ItemAdd()
- ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
- if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
- return false;
- IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
-
- // Test if we are hovering the right window (our window could be behind another window)
- // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
- // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
- // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
- // the test that has been running for a long while.
- if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
- if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
- return false;
-
- // Test if another item is active (e.g. being dragged)
- if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
- if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
- return false;
-
- // Test if interactions on this window are blocked by an active popup or modal.
- // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
- if (!IsWindowContentHoverable(window, flags))
- return false;
-
- // Test if the item is disabled
- if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
- return false;
-
- // Special handling for calling after Begin() which represent the title bar or tab.
- // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
- if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
- return false;
return true;
}
@@ -4474,8 +4477,7 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im
if (window->Active)
{
int count = window->DC.ChildWindows.Size;
- if (count > 1)
- ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
+ ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
for (int i = 0; i < count; i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
@@ -6276,7 +6278,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Update ->RootWindow and others pointers (before any possible call to FocusWindow)
if (first_begin_of_the_frame)
+ {
UpdateWindowParentAndRootLinks(window, flags, parent_window);
+ window->ParentWindowInBeginStack = parent_window_in_stack;
+ }
// Process SetNextWindow***() calls
// (FIXME: Consider splitting the HasXXX flags into X/Y components
@@ -8562,7 +8567,7 @@ void ImGui::EndGroup()
window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize(group_bb.GetSize());
- ItemAdd(group_bb, 0);
+ ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
@@ -8851,10 +8856,10 @@ void ImGui::SetScrollHereY(float center_y_ratio)
void ImGui::BeginTooltip()
{
- BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
+ BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None);
}
-void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
+void ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
{
ImGuiContext& g = *GImGui;
@@ -8883,7 +8888,7 @@ void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags toolt
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
}
ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking;
- Begin(window_name, NULL, flags | extra_flags);
+ Begin(window_name, NULL, flags | extra_window_flags);
}
void ImGui::EndTooltip()
@@ -8894,7 +8899,7 @@ void ImGui::EndTooltip()
void ImGui::SetTooltipV(const char* fmt, va_list args)
{
- BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
+ BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None);
TextV(fmt, args);
EndTooltip();
}
@@ -10930,16 +10935,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
return false;
// If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
- // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
+ // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag.
if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
{
IM_ASSERT(0);
return false;
}
- // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
+ // Magic fallback to handle items with no assigned ID, e.g. Text(), Image()
// We build a throwaway ID based on current ID stack + relative AABB of items in window.
- // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
+ // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
// We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
// Rely on keeping other window->LastItemXXX fields intact.
source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
@@ -16659,6 +16664,7 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
// - DebugNodeWindow() [Internal]
// - DebugNodeWindowSettings() [Internal]
// - DebugNodeWindowsList() [Internal]
+// - DebugNodeWindowsListByBeginStackParent() [Internal]
//-----------------------------------------------------------------------------
#ifndef IMGUI_DISABLE_METRICS_WINDOW
@@ -16890,8 +16896,27 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// Windows
- DebugNodeWindowsList(&g.Windows, "Windows");
- //DebugNodeWindowsList(&g.WindowsFocusOrder, "WindowsFocusOrder");
+ if (TreeNode("Windows", "Windows (%d)", g.Windows.Size))
+ {
+ //SetNextItemOpen(true, ImGuiCond_Once);
+ DebugNodeWindowsList(&g.Windows, "By display order");
+ DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)");
+ if (TreeNode("By submission order (begin stack)"))
+ {
+ // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
+ ImVector& temp_buffer = g.WindowsTempSortBuffer;
+ temp_buffer.resize(0);
+ for (int i = 0; i < g.Windows.Size; i++)
+ if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount)
+ temp_buffer.push_back(g.Windows[i]);
+ struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
+ ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
+ DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
+ TreePop();
+ }
+
+ TreePop();
+ }
// DrawLists
int drawlist_count = 0;
@@ -17704,7 +17729,6 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la
{
if (!TreeNode(label, "%s (%d)", label, windows->Size))
return;
- Text("(In front-to-back order:)");
for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back
{
PushID((*windows)[i]);
@@ -17714,6 +17738,24 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la
TreePop();
}
+// FIXME-OPT: This is technically suboptimal, but it is simpler this way.
+void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack)
+{
+ for (int i = 0; i < windows_size; i++)
+ {
+ ImGuiWindow* window = windows[i];
+ if (window->ParentWindowInBeginStack != parent_in_begin_stack)
+ continue;
+ char buf[20];
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext);
+ //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name);
+ DebugNodeWindow(window, buf);
+ Indent();
+ DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window);
+ Unindent();
+ }
+}
+
//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//-----------------------------------------------------------------------------
diff --git a/imgui.h b/imgui.h
index f922fc0e..b045757c 100644
--- a/imgui.h
+++ b/imgui.h
@@ -65,7 +65,7 @@ Index of this file:
// Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.86 WIP"
-#define IMGUI_VERSION_NUM 18510
+#define IMGUI_VERSION_NUM 18512
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
@@ -1019,7 +1019,7 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
// [Internal]
- ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
+ ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index c14bda5c..ffb3894e 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -2343,7 +2343,7 @@ static void ShowDemoWindowWidgets()
// Select an item type
const char* item_names[] =
{
- "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat",
+ "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
"InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
};
static int item_type = 4;
@@ -2366,15 +2366,16 @@ static void ShowDemoWindowWidgets()
if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
- if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
- if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
- if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
- if (item_type == 9) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
- if (item_type == 10){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
- if (item_type == 11){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
- if (item_type == 12){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
- if (item_type == 13){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); }
- if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
+ if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
+ if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
+ if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
+ if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
+ if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
+ if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
+ if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); }
+ if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
// Display the values of IsItemHovered() and other common item state functions.
// Note that the ImGuiHoveredFlags_XXX flags can be combined.
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 0854b1a9..cc3e45af 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -1925,37 +1925,38 @@ ImFontConfig::ImFontConfig()
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
-const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing.
+// (This is used when io.MouseDrawCursor = true)
+const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
{
- "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX "
- "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X "
- "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X "
- "X - X.X - X.....X - X.....X -X...X - X...X- X..X "
- "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X "
- "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX "
- "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX "
- "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX "
- "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X "
- "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X"
- "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X"
- "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X"
- "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X"
- "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X"
- "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X"
- "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X"
- "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X "
- "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X "
- "X.X X..X - -X.......X- X.......X - XX XX - - X..........X "
- "XX X..X - - X.....X - X.....X - X.X X.X - - X........X "
- " X..X - X...X - X...X - X..X X..X - - X........X "
- " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX "
- "------------ - X - X -X.....................X- ------------------"
- " ----------------------------------- X...XXXXXXXXXXXXX...X - "
- " - X..X X..X - "
- " - X.X X.X - "
- " - XX XX - "
+ "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX "
+ "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X"
+ "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X"
+ "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X "
+ "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X "
+ "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X "
+ "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X "
+ "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X "
+ "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X "
+ "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X "
+ "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X "
+ "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X "
+ "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X"
+ "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X"
+ "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX "
+ "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------"
+ "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - "
+ "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - "
+ "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - "
+ "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - "
+ " X..X - - X...X - X...X - X..X X..X - - X........X - "
+ " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - "
+ "------------- - X - X -X.....................X- ------------------- "
+ " ----------------------------------- X...XXXXXXXXXXXXX...X - "
+ " - X..X X..X - "
+ " - X.X X.X - "
+ " - XX XX - "
};
static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
@@ -1969,6 +1970,7 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
+ { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
};
ImFontAtlas::ImFontAtlas()
@@ -3914,10 +3916,10 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect
const bool fill_R = (inner.Max.x < outer.Max.x);
const bool fill_U = (inner.Min.y > outer.Min.y);
const bool fill_D = (inner.Max.y < outer.Max.y);
- if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
- if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
- if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
- if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
+ if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
+ if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
+ if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
+ if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
diff --git a/imgui_internal.h b/imgui_internal.h
index 446b7ae8..0a2b3c4a 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -265,12 +265,19 @@ namespace ImStb
#endif
// Debug Tools
-// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item.
+// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item.
+// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference.
#ifndef IM_DEBUG_BREAK
-#if defined(__clang__)
-#define IM_DEBUG_BREAK() __builtin_debugtrap()
-#elif defined (_MSC_VER)
+#if defined (_MSC_VER)
#define IM_DEBUG_BREAK() __debugbreak()
+#elif defined(__clang__)
+#define IM_DEBUG_BREAK() __builtin_debugtrap()
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define IM_DEBUG_BREAK() __asm__ volatile("int $0x03")
+#elif defined(__GNUC__) && defined(__thumb__)
+#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01")
+#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__)
+#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0");
#else
#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger!
#endif
@@ -307,7 +314,9 @@ static inline ImGuiID ImHash(const void* data, int size, ImU32 seed = 0) { ret
#endif
// Helpers: Sorting
-#define ImQsort qsort
+#ifndef ImQsort
+static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); }
+#endif
// Helpers: Color Blending
IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
@@ -414,8 +423,8 @@ static inline double ImLog(double x) { return log(x); }
static inline int ImAbs(int x) { return x < 0 ? -x : x; }
static inline float ImAbs(float x) { return fabsf(x); }
static inline double ImAbs(double x) { return fabs(x); }
-static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument
-static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); }
+static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument
+static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; }
#ifdef IMGUI_ENABLE_SSE
static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }
#else
@@ -1032,8 +1041,6 @@ struct IMGUI_API ImGuiInputTextState
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
ImGuiInputTextFlags Flags; // copy of InputText() flags
- ImGuiInputTextCallback UserCallback; // "
- void* UserCallbackData; // "
ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
@@ -2226,6 +2233,7 @@ struct IMGUI_API ImGuiWindow
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
ImDrawList DrawListInst;
ImGuiWindow* ParentWindow; // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL.
+ ImGuiWindow* ParentWindowInBeginStack;
ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes.
ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child.
ImGuiWindow* RootWindowDockTree; // Point to ourself or first ancestor that is not a child window. Cross through dock nodes.
@@ -2760,7 +2768,7 @@ namespace ImGui
IMGUI_API void ClosePopupsExceptModals();
IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
- IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags);
+ IMGUI_API void BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window);
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
@@ -3063,6 +3071,7 @@ namespace ImGui
IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label);
IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings);
IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label);
+ IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack);
IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport);
IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb);
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index d67fa3f4..8fa3a109 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3972,7 +3972,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_resizable)
IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!
- if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
+ if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar)
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
@@ -3985,6 +3985,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ImGuiWindow* draw_window = window;
ImVec2 inner_size = frame_size;
ImGuiItemStatusFlags item_status_flags = 0;
+ ImGuiLastItemData item_data_backup;
if (is_multiline)
{
ImVec2 backup_pos = window->DC.CursorPos;
@@ -3995,6 +3996,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
return false;
}
item_status_flags = g.LastItemData.StatusFlags;
+ item_data_backup = g.LastItemData;
window->DC.CursorPos = backup_pos;
// We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.
@@ -4171,8 +4173,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Edited = false;
state->BufCapacityA = buf_size;
state->Flags = flags;
- state->UserCallback = callback;
- state->UserCallbackData = callback_user_data;
// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
// Down the line we should have a cleaner library-wide concept of Selected vs Active.
@@ -4410,11 +4410,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
// Process callbacks and apply result back to user's buffer.
+ const char* apply_new_text = NULL;
+ int apply_new_text_length = 0;
if (g.ActiveId == id)
{
IM_ASSERT(state != NULL);
- const char* apply_new_text = NULL;
- int apply_new_text_length = 0;
if (cancel_edit)
{
// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
@@ -4490,8 +4490,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
callback_data.Flags = flags;
callback_data.UserData = callback_user_data;
+ char* callback_buf = is_readonly ? buf : state->TextA.Data;
callback_data.EventKey = event_key;
- callback_data.Buf = state->TextA.Data;
+ callback_data.Buf = callback_buf;
callback_data.BufTextLen = state->CurLenA;
callback_data.BufSize = state->BufCapacityA;
callback_data.BufDirty = false;
@@ -4506,7 +4507,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
callback(&callback_data);
// Read back what user may have modified
- IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields
+ IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields
IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
IM_ASSERT(callback_data.Flags == flags);
const bool buf_dirty = callback_data.BufDirty;
@@ -4533,39 +4534,37 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
}
- // Copy result to user buffer
- if (apply_new_text)
- {
- // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
- // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
- // without any storage on user's side.
- IM_ASSERT(apply_new_text_length >= 0);
- if (is_resizable)
- {
- ImGuiInputTextCallbackData callback_data;
- callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
- callback_data.Flags = flags;
- callback_data.Buf = buf;
- callback_data.BufTextLen = apply_new_text_length;
- callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1);
- callback_data.UserData = callback_user_data;
- callback(&callback_data);
- buf = callback_data.Buf;
- buf_size = callback_data.BufSize;
- apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1);
- IM_ASSERT(apply_new_text_length <= buf_size);
- }
- //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length);
-
- // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.
- ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
- value_changed = true;
- }
-
// Clear temporary user storage
state->Flags = ImGuiInputTextFlags_None;
- state->UserCallback = NULL;
- state->UserCallbackData = NULL;
+ }
+
+ // Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
+ if (apply_new_text != NULL)
+ {
+ // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
+ // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
+ // without any storage on user's side.
+ IM_ASSERT(apply_new_text_length >= 0);
+ if (is_resizable)
+ {
+ ImGuiInputTextCallbackData callback_data;
+ callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
+ callback_data.Flags = flags;
+ callback_data.Buf = buf;
+ callback_data.BufTextLen = apply_new_text_length;
+ callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1);
+ callback_data.UserData = callback_user_data;
+ callback(&callback_data);
+ buf = callback_data.Buf;
+ buf_size = callback_data.BufSize;
+ apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1);
+ IM_ASSERT(apply_new_text_length <= buf_size);
+ }
+ //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length);
+
+ // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.
+ ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
+ value_changed = true;
}
// Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
@@ -4782,9 +4781,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_multiline)
{
+ // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)...
Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y));
+ ImGuiItemFlags backup_item_flags = g.CurrentItemFlags;
+ g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;
EndChild();
+ item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow);
+ g.CurrentItemFlags = backup_item_flags;
+
+ // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active...
+ // FIXME: This quite messy/tricky, should attempt to get rid of the child window.
EndGroup();
+ if (g.LastItemData.ID == 0)
+ {
+ g.LastItemData.ID = id;
+ g.LastItemData.InFlags = item_data_backup.InFlags;
+ g.LastItemData.StatusFlags = item_data_backup.StatusFlags;
+ }
}
// Log as text
@@ -5589,7 +5602,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags
{
ImGuiContext& g = *GImGui;
- BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
+ BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None);
const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
if (text_end > text)
{
@@ -7251,7 +7264,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
// Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable
if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
- if (tab_bar->Tabs.Size > 1 && (flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid
+ if ((flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
tab_bar->TabsAddedNew = false;