From 064b94721e20caf05b7cb56dc51060e4b2ede333 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 19 Apr 2015 23:28:57 +0100 Subject: [PATCH 01/28] Added DragFloat2, DragFloat3, DragFloat4, DragInt2, DragInt3, DragInt4. --- imgui.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++- imgui.h | 10 ++++- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 06e42ab8..272f5817 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5416,7 +5416,7 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, } // Add multiple sliders on 1 line for compact edition of multiple components -static bool SliderFloatN(const char* label, float v[3], int components, float v_min, float v_max, const char* display_format, float power) +static bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -5468,7 +5468,7 @@ bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max return SliderFloatN(label, v, 4, v_min, v_max, display_format, power); } -static bool SliderIntN(const char* label, int v[3], int components, int v_min, int v_max, const char* display_format) +static bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -5663,6 +5663,58 @@ bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, f return value_changed; } +static bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const float w_full = ImGui::CalcItemWidth(); + const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); + + bool value_changed = false; + ImGui::BeginGroup(); + ImGui::PushID(label); + ImGui::PushItemWidth(w_item_one); + for (int i = 0; i < components; i++) + { + ImGui::PushID(i); + if (i + 1 == components) + { + ImGui::PopItemWidth(); + ImGui::PushItemWidth(w_item_last); + } + value_changed |= ImGui::DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power); + ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::PopID(); + + ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); + + return value_changed; +} + +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power) +{ + return DragFloatN(label, v, 2, v_speed, v_min, v_max, display_format, power); +} + +bool ImGui::DragFloat3(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power) +{ + return DragFloatN(label, v, 3, v_speed, v_min, v_max, display_format, power); +} + +bool ImGui::DragFloat4(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power) +{ + return DragFloatN(label, v, 4, v_speed, v_min, v_max, display_format, power); +} + // NB: v_speed is float to allow adjusting the drag speed with more precision bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format) { @@ -5674,6 +5726,58 @@ bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_m return value_changed; } +static bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const float w_full = ImGui::CalcItemWidth(); + const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); + + bool value_changed = false; + ImGui::BeginGroup(); + ImGui::PushID(label); + ImGui::PushItemWidth(w_item_one); + for (int i = 0; i < components; i++) + { + ImGui::PushID(i); + if (i + 1 == components) + { + ImGui::PopItemWidth(); + ImGui::PushItemWidth(w_item_last); + } + value_changed |= ImGui::DragInt("##v", &v[i], v_speed, v_min, v_max, display_format); + ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::PopID(); + + ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); + + return value_changed; +} + +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* display_format) +{ + return DragIntN(label, v, 2, v_speed, v_min, v_max, display_format); +} + +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* display_format) +{ + return DragIntN(label, v, 3, v_speed, v_min, v_max, display_format); +} + +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* display_format) +{ + return DragIntN(label, v, 4, v_speed, v_min, v_max, display_format); +} + enum ImGuiPlotType { ImGuiPlotType_Lines, @@ -9953,18 +10057,24 @@ void ImGui::ShowTestWindow(bool* opened) static int vec4i[4] = { 1, 5, 100, 255 }; ImGui::InputFloat2("input float2", vec4f); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::InputInt2("input int2", vec4i); ImGui::SliderInt2("slider int2", vec4i, 0, 255); ImGui::InputFloat3("input float3", vec4f); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::InputInt3("input int3", vec4i); ImGui::SliderInt3("slider int3", vec4i, 0, 255); ImGui::InputFloat4("input float4", vec4f); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); ImGui::InputInt4("input int4", vec4i); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); ImGui::SliderInt4("slider int4", vec4i, 0, 255); ImGui::Indent(); diff --git a/imgui.h b/imgui.h index a337e959..7338f5be 100644 --- a/imgui.h +++ b/imgui.h @@ -318,8 +318,14 @@ namespace ImGui // Widgets: Drags (tip: ctrl+click on a drag box to input text) // ImGui 1.38+ work-in-progress, may change name or API. - IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); // If v_max >= v_max we have no bound - IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); // If v_max >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // Widgets: Input IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); From 37d8d78fc261578c939d8115ae1496b13b6f4905 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 19 Apr 2015 23:37:50 +0100 Subject: [PATCH 02/28] Selectable() render into AutoFitPadding only when full-fitting (fix aac99819d67079c4aa5b5ba64c6f946df704e8e7) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 272f5817..ca53c4a7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6980,7 +6980,8 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); - bb.Max.x += style.AutoFitPadding.x; + if (size_arg.x == 0.0f) + bb.Max.x += style.AutoFitPadding.x; // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. ImRect bb_with_spacing = bb; From 0123fc8c0f3f9b9d55b31d7403dea32d568032fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 19 Apr 2015 23:56:35 +0100 Subject: [PATCH 03/28] Removed comment --- imgui.h | 1 - 1 file changed, 1 deletion(-) diff --git a/imgui.h b/imgui.h index 7338f5be..4b241676 100644 --- a/imgui.h +++ b/imgui.h @@ -317,7 +317,6 @@ namespace ImGui IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); // Widgets: Drags (tip: ctrl+click on a drag box to input text) - // ImGui 1.38+ work-in-progress, may change name or API. IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); // If v_max >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); From 9119f58ce5bd86b3ad4b7453ce7732bb339bf578 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2015 10:09:20 +0100 Subject: [PATCH 04/28] Version number 1.39 WIP --- imgui.cpp | 2 +- imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ca53c4a7..a4f0e423 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.38 +// ImGui library v1.39 WIP // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui diff --git a/imgui.h b/imgui.h index 4b241676..da80152b 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.38 +// ImGui library v1.39 WIP // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -13,7 +13,7 @@ #include // NULL, malloc, free, qsort, atoi #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.38" +#define IMGUI_VERSION "1.39 WIP" // Define assertion handler. #ifndef IM_ASSERT From c93a562b06d9980b1798b9615daabcf82fc79684 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2015 10:12:17 +0100 Subject: [PATCH 05/28] Added ImGuiStorage::GetVoidPtrRef() --- imgui.cpp | 8 ++++++++ imgui.h | 1 + 2 files changed, 9 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index a4f0e423..a0f0fe4a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1415,6 +1415,14 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) return &it->val_f; } +void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) +{ + ImVector::iterator it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, Pair(key, default_val)); + return &it->val_p; +} + // FIXME-OPT: Wasting CPU because all SetInt() are preceeded by GetInt() calls so we should have the result from lower_bound already in place. // However we only use SetInt() on explicit user action (so that's maximum once a frame) so the optimisation isn't much needed. void ImGuiStorage::SetInt(ImU32 key, int val) diff --git a/imgui.h b/imgui.h index da80152b..bb9af931 100644 --- a/imgui.h +++ b/imgui.h @@ -804,6 +804,7 @@ struct ImGuiStorage // - You can also use this to quickly create temporary editable values during a session of using Edit&Continue, without restarting your application. IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0); + IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); // Use on your own storage if you know only integer are being stored (open/close all tree nodes) IMGUI_API void SetAllInt(int val); From 18a00c70609193c9ded2d69e87e5f839ed6c3511 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Apr 2015 09:18:56 +0200 Subject: [PATCH 06/28] Examples: DirectX9/11: Fixed key mapping for down arrow. --- examples/directx11_example/imgui_impl_dx11.cpp | 2 +- examples/directx9_example/imgui_impl_dx9.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index a18ba09e..0934e08a 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -390,7 +390,7 @@ bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContex io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; io.KeyMap[ImGuiKey_UpArrow] = VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; io.KeyMap[ImGuiKey_Home] = VK_HOME; io.KeyMap[ImGuiKey_End] = VK_END; io.KeyMap[ImGuiKey_Delete] = VK_DELETE; diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index c55ffebb..cc5f31a9 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -168,7 +168,7 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; io.KeyMap[ImGuiKey_UpArrow] = VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; io.KeyMap[ImGuiKey_Home] = VK_HOME; io.KeyMap[ImGuiKey_End] = VK_END; io.KeyMap[ImGuiKey_Delete] = VK_DELETE; From 6844952d566eed6f0ebf64425e647baf29bd328c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Apr 2015 09:22:29 +0200 Subject: [PATCH 07/28] Fixed build with Visual Studio 2008 or earlier (via PR #203) --- imgui.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a0f0fe4a..c2f42ebc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -400,9 +400,13 @@ #include "imgui.h" #include // toupper, isprint #include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf -#include // intptr_t #include // vsnprintf, sscanf #include // new (ptr) +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif #ifdef _MSC_VER #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) From 1d90f099bd3b7795c14835cfd2208b6e55a1be41 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 26 Apr 2015 13:17:56 +0200 Subject: [PATCH 08/28] Tidying up We still have an issue with ImVec4 vs ImRect --- imgui.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c2f42ebc..86ad7466 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2831,6 +2831,14 @@ int ImGui::GetFrameCount() return GImGui->FrameCount; } +static ImVec4 GetVisibleRect() +{ + ImGuiState& g = *GImGui; + if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) + return ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y); + return ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); +} + void ImGui::BeginTooltip() { ImGuiState& g = *GImGui; @@ -3145,10 +3153,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Setup outer clipping rectangle if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) PushClipRect(parent_window->ClipRectStack.back()); - else if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) - PushClipRect(ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y)); else - PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); + PushClipRect(GetVisibleRect()); // Setup and draw window if (first_begin_of_the_frame) @@ -7890,10 +7896,7 @@ void ImDrawList::PushClipRectFullScreen() // This would be more correct but we're not supposed to access ImGuiState from here? //ImGuiState& g = *GImGui; - //if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) - // PushClipRect(ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y)); - //else - // PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); + //PushClipRect(GetVisibleRect()); } void ImDrawList::PopClipRect() From bd23c11a937ca25c911c287ccad77bf2e82c82b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Apr 2015 22:19:14 +0200 Subject: [PATCH 09/28] Separator() within group start on group horizontal offset #205 --- imgui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 86ad7466..101fc249 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7330,7 +7330,12 @@ void ImGui::Separator() if (window->DC.ColumnsCount > 1) PopClipRect(); - const ImRect bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y)); + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + if (!window->DC.GroupStack.empty()) + x1 += window->DC.ColumnsStartX; + + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y)); ItemSize(ImVec2(0.0f, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit if (!ItemAdd(bb, NULL)) { From 2440a3044403a1e1e16b6b8def2673e998991c2d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Apr 2015 18:09:38 +0200 Subject: [PATCH 10/28] Columns() distinguish columns-set ID from other widgets as a convenience, added asserts, added more sailors --- imgui.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 101fc249..8435f98d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7575,6 +7575,7 @@ static float GetDraggedColumnOffset(int column_index) // window creates a feedback loop because we store normalized positions/ So while dragging we enforce absolute positioning ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets. IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index)); float x = g.IO.MousePos.x + g.ActiveClickDeltaToCenter.x; @@ -7699,7 +7700,9 @@ void ImGui::Columns(int columns_count, const char* id, bool border) } // Set state for first column + ImGui::PushID(0x11223344); // Differentiate column ID with an arbitrary/random prefix for cases where users name their columns set the same as another non-scope widget window->DC.ColumnsSetID = window->GetID(id ? id : ""); + ImGui::PopID(); window->DC.ColumnsCurrent = 0; window->DC.ColumnsCount = columns_count; window->DC.ColumnsShowBorders = border; @@ -10251,12 +10254,12 @@ void ImGui::ShowTestWindow(bool* opened) // Text ImGui::Text("Two items: Hello"); ImGui::SameLine(); - ImGui::TextColored(ImVec4(1,1,0,1), "World"); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Adjust spacing ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); - ImGui::TextColored(ImVec4(1,1,0,1), "World"); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Button ImGui::AlignFirstTextHeightToWidgets(); @@ -10499,7 +10502,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Text("An extra line here."); ImGui::NextColumn(); - ImGui::Text("World!"); + ImGui::Text("Sailor"); ImGui::Button("Corniflower"); ImGui::RadioButton("radio c", &e, 2); static float bar = 1.0f; @@ -10518,8 +10521,8 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Text("Tree items:"); ImGui::Columns(2, "tree items"); ImGui::Separator(); - if (ImGui::TreeNode("Hello")) { ImGui::BulletText("World"); ImGui::TreePop(); } ImGui::NextColumn(); - if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Monde"); ImGui::TreePop(); } ImGui::NextColumn(); + if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn(); + if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn(); ImGui::Columns(1); ImGui::Separator(); From 8fbb42cc6f0d3a3b0f475902409676c663f9c3f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Apr 2015 18:12:24 +0200 Subject: [PATCH 11/28] Added IsKeyDown() IsMouseDown() as convenience instead of reading into IO structures Also their existence serves as implicit documentation of what IsKeyPressed(), IsMouseClicked() does --- imgui.cpp | 14 ++++++++++++++ imgui.h | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8435f98d..9ce9ec52 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2657,6 +2657,13 @@ static bool IsKeyPressedMap(ImGuiKey key, bool repeat) return ImGui::IsKeyPressed(key_index, repeat); } +bool ImGui::IsKeyDown(int key_index) +{ + ImGuiState& g = *GImGui; + IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDown[key_index]; +} + bool ImGui::IsKeyPressed(int key_index, bool repeat) { ImGuiState& g = *GImGui; @@ -2675,6 +2682,13 @@ bool ImGui::IsKeyPressed(int key_index, bool repeat) return false; } +bool ImGui::IsMouseDown(int button) +{ + ImGuiState& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + bool ImGui::IsMouseClicked(int button, bool repeat) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index bb9af931..5d358f00 100644 --- a/imgui.h +++ b/imgui.h @@ -386,7 +386,9 @@ namespace ImGui IMGUI_API bool IsRootWindowFocused(); // is current root window focused IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRectClipped(const ImVec2& size); // test if rectangle of given size starting from cursor pos is out of clipping region. to perform coarse clipping on user's side (as an optimization) - IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry + IMGUI_API bool IsKeyDown(int key_index); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry + IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // " + IMGUI_API bool IsMouseDown(int button); IMGUI_API bool IsMouseClicked(int button, bool repeat = false); IMGUI_API bool IsMouseDoubleClicked(int button); IMGUI_API bool IsMouseHoveringWindow(); // is mouse hovering current window ("window" in API names always refer to current window) From 68ccdc4fb86ef82f84ffa31b06a48d19a6a14459 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 1 May 2015 11:07:30 +0200 Subject: [PATCH 12/28] Comments --- imgui.cpp | 1 + imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9ce9ec52..0a4ea19b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -344,6 +344,7 @@ - popup: border options. richer api like BeginChild() perhaps? (github issue #197) - combo: turn child handling code into pop up helper - combo: contents should extends to fit label if combo widget is small + - combo/listbox: keyboard control. need inputtext like non-active focus + key handling. considering keybord for custom listbox (see github pr #203) - listbox: multiple selection - listbox: user may want to initial scroll to focus on the one selected value? ! menubar, menus (github issue #126) diff --git a/imgui.h b/imgui.h index 5d358f00..b04411ec 100644 --- a/imgui.h +++ b/imgui.h @@ -166,7 +166,7 @@ namespace ImGui IMGUI_API bool Begin(const char* name = "Debug", bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // this is the older/longer API. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! maybe obsolete this API eventually. IMGUI_API void End(); - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). on each axis. + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " IMGUI_API void EndChild(); IMGUI_API ImVec2 GetContentRegionMax(); // window or current column boundaries, in windows coordinates @@ -237,7 +237,7 @@ namespace ImGui IMGUI_API void Spacing(); // add vertical spacing IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) - IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns. use an identifier to distinguish multiple column sets. close with Columns(1). IMGUI_API void NextColumn(); // next column IMGUI_API int GetColumnIndex(); // get current column index IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this From ad7f600e0db5f26e4ea7da5afea34815dfa924a3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 1 May 2015 11:25:15 +0200 Subject: [PATCH 13/28] Examples: DirectX9/11: hide os curosr if ImGui is drawing it (#155) --- examples/directx11_example/imgui_impl_dx11.cpp | 3 +++ examples/directx9_example/imgui_impl_dx9.cpp | 3 +++ examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 +- examples/opengl_example/imgui_impl_glfw.cpp | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 0934e08a..ee111484 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -446,6 +446,9 @@ void ImGui_ImplDX11_NewFrame() // io.MouseDown : filled by WM_*BUTTON* events // io.MouseWheel : filled by WM_MOUSEWHEEL events + // Hide OS mouse cursor if ImGui is drawing it + SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW)); + // Start the frame ImGui::NewFrame(); } diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index cc5f31a9..3c14dc25 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -281,6 +281,9 @@ void ImGui_ImplDX9_NewFrame() // io.MouseDown : filled by WM_*BUTTON* events // io.MouseWheel : filled by WM_MOUSEWHEEL events + // Hide OS mouse cursor if ImGui is drawing it + SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW)); + // Start the frame ImGui::NewFrame(); } diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index dba7e13a..5796c04e 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -354,7 +354,7 @@ void ImGui_ImplGlfwGL3_NewFrame() io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; - // Hide/show hardware mouse cursor + // Hide OS mouse cursor if ImGui is drawing it glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); // Start the frame diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 0a0ee3e6..decf2529 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -259,7 +259,7 @@ void ImGui_ImplGlfw_NewFrame() io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; - // Hide/show hardware mouse cursor + // Hide OS mouse cursor if ImGui is drawing it glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); // Start the frame From 07ebb14ce2cf370fb278a6173a48fe6d74243ec9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 1 May 2015 20:35:44 +0100 Subject: [PATCH 14/28] Tooltip: fit within display. Added style.DisplayWindowPadding, style.DisplaySafeAreaPadding now strictly for popups/menus. --- imgui.cpp | 38 ++++++++++++++++++++++++++++++-------- imgui.h | 3 ++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0a4ea19b..689eadd5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -381,7 +381,6 @@ - keyboard: full keyboard navigation and focus. - input: rework IO to be able to pass actual events to fix temporal aliasing issues. - input: support track pad style scrolling & slider edit. - - tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen). - portability: big-endian test/support (github issue #81) - misc: mark printf compiler attributes on relevant functions - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) @@ -570,7 +569,8 @@ ImGuiStyle::ImGuiStyle() ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarWidth = 16.0f; // Width of the vertical scrollbar GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab - DisplaySafeAreaPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding + DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. + DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); @@ -963,6 +963,7 @@ struct ImRect // 2D axis aligned bounding-box void Add(const ImRect& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } void Expand(const ImVec2& amount) { Min -= amount; Max += amount; } + void Reduce(const ImVec2& amount) { Min += amount; Max -= amount; } void Clip(const ImRect& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); } ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const { @@ -2974,6 +2975,28 @@ void ImGui::EndChildFrame() ImGui::PopStyleColor(); } +static ImVec2 FindTooltipPos(const ImVec2& mouse_pos, const ImVec2& size) +{ + const ImGuiStyle& style = GImGui->Style; + + // Clamp into visible area while not overlapping the cursor + ImRect r_outer(GetVisibleRect()); + r_outer.Reduce(style.DisplaySafeAreaPadding); + ImRect r_inner(mouse_pos.x - 16, mouse_pos.y - 8, mouse_pos.x + 28, mouse_pos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? + ImVec2 mouse_pos_clamped = ImClamp(mouse_pos, r_outer.Min, r_outer.Max - size); + + for (int dir = 0; dir < 4; dir++) // right, down, up, left + { + ImRect rect(dir == 0 ? r_inner.Max.x : r_outer.Min.x, dir == 1 ? r_inner.Max.y : r_outer.Min.y, dir == 3 ? r_inner.Min.x : r_outer.Max.x, dir == 2 ? r_inner.Min.y : r_outer.Max.y); + if (rect.GetWidth() < size.x || rect.GetHeight() < size.y) + continue; + return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : mouse_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : mouse_pos_clamped.y); + } + + // Fallback + return mouse_pos + ImVec2(2,2); +} + static ImGuiWindow* FindWindowByName(const char* name) { // FIXME-OPT: Store sorted hashes -> pointers. @@ -3202,18 +3225,17 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Tooltips always follows mouse if (!window_pos_set_by_api && (window->Flags & ImGuiWindowFlags_Tooltip) != 0) { - window->PosFloat = g.IO.MousePos + ImVec2(32,16) - style.FramePadding*2; + window->PosFloat = FindTooltipPos(g.IO.MousePos, window->Size); } - // Clamp into view + // Clamp into display if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip)) { if (window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { - ImVec2 clip_min = style.DisplaySafeAreaPadding; - ImVec2 clip_max = g.IO.DisplaySize - style.DisplaySafeAreaPadding; - window->PosFloat = ImMax(window->PosFloat + window->Size, clip_min) - window->Size; - window->PosFloat = ImMin(window->PosFloat, clip_max); + ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size; + window->PosFloat = ImMin(window->PosFloat, g.IO.DisplaySize - padding); } window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); } diff --git a/imgui.h b/imgui.h index b04411ec..6c2b4a3f 100644 --- a/imgui.h +++ b/imgui.h @@ -604,7 +604,8 @@ struct ImGuiStyle float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarWidth; // Width of the vertical scrollbar float GrabMinSize; // Minimum width/height of a slider or scrollbar grab - ImVec2 DisplaySafeAreaPadding; // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. + ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); From 19f7bf90f86063dbbc59e93c3f5a973e75ec696b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 1 May 2015 21:01:54 +0100 Subject: [PATCH 15/28] Examples: AutoResize demo doesn't use TextWrapped() --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 689eadd5..2ddc52cb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3261,7 +3261,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImRect title_bar_rect = window->TitleBarRect(); - // Apply and ImClamp scrolling + // Apply scrolling window->ScrollY = window->NextScrollY; window->ScrollY = ImMax(window->ScrollY, 0.0f); if (!window->Collapsed && !window->SkipItems) @@ -10771,7 +10771,7 @@ static void ShowExampleAppAutoResize(bool* opened) } static int lines = 10; - ImGui::TextWrapped("Window will resize every-frame to the size of its content. Note that you don't want to query the window size to output your content because that would create a feedback loop."); + ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); ImGui::SliderInt("Number of lines", &lines, 1, 20); for (int i = 0; i < lines; i++) ImGui::Text("%*sThis is line %d", i*4, "", i); // Pad with space to extend size horizontally From 3f7f256752a63148d83340b3a3c6555a1a06428a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 10:32:32 +0100 Subject: [PATCH 16/28] Tidying up. Re-arranged the (first_begin_of_the_frame) blocks in Begin() for further changes. Being cautious. --- imgui.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2ddc52cb..46497215 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2215,12 +2215,12 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it + if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it if (window->Visible) continue; AddWindowToSortedBuffer(g.WindowsSortBuffer, window); } - IM_ASSERT(g.Windows.size() == g.WindowsSortBuffer.size()); // we done something wrong + IM_ASSERT(g.Windows.size() == g.WindowsSortBuffer.size()); // we done something wrong g.Windows.swap(g.WindowsSortBuffer); // Clear data for next frame @@ -2975,14 +2975,13 @@ void ImGui::EndChildFrame() ImGui::PopStyleColor(); } -static ImVec2 FindTooltipPos(const ImVec2& mouse_pos, const ImVec2& size) +static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, const ImRect& r_inner) { const ImGuiStyle& style = GImGui->Style; // Clamp into visible area while not overlapping the cursor ImRect r_outer(GetVisibleRect()); r_outer.Reduce(style.DisplaySafeAreaPadding); - ImRect r_inner(mouse_pos.x - 16, mouse_pos.y - 8, mouse_pos.x + 28, mouse_pos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? ImVec2 mouse_pos_clamped = ImClamp(mouse_pos, r_outer.Min, r_outer.Max - size); for (int dir = 0; dir < 4; dir++) // right, down, up, left @@ -3152,6 +3151,20 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (first_begin_of_the_frame) { window->DrawList->Clear(); + window->ClipRectStack.resize(0); + } + + // Setup texture + window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + + // Setup outer clipping rectangle + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) + PushClipRect(parent_window->ClipRectStack.back()); + else + PushClipRect(GetVisibleRect()); + + if (first_begin_of_the_frame) + { window->Visible = true; // New windows appears in front @@ -3171,7 +3184,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } window->LastFrameDrawn = current_frame; - window->ClipRectStack.resize(0); // Reset contents size for auto-fitting window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos; @@ -3183,20 +3195,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->Pos = window->PosFloat = parent_window->DC.CursorPos; window->SizeFull = size_on_first_use; } - } - // Setup texture - window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); - - // Setup outer clipping rectangle - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) - PushClipRect(parent_window->ClipRectStack.back()); - else - PushClipRect(GetVisibleRect()); - - // Setup and draw window - if (first_begin_of_the_frame) - { // Reset ID stack window->IDStack.resize(1); @@ -3225,7 +3224,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Tooltips always follows mouse if (!window_pos_set_by_api && (window->Flags & ImGuiWindowFlags_Tooltip) != 0) { - window->PosFloat = FindTooltipPos(g.IO.MousePos, window->Size); + ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 28, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? + window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, rect_to_avoid); } // Clamp into display From 46f55fe6f62a8cb3a05eaef66352c68861cc4a6a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 10:46:24 +0100 Subject: [PATCH 17/28] Tidying up Begin() --- imgui.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 46497215..808881cb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3148,16 +3148,17 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // When reusing window again multiple times a frame, just append content (don't need to setup again) const int current_frame = ImGui::GetFrameCount(); const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame); + const bool window_was_visible = (window->LastFrameDrawn == current_frame - 1); if (first_begin_of_the_frame) { + window->Visible = true; window->DrawList->Clear(); window->ClipRectStack.resize(0); + window->LastFrameDrawn = current_frame; } - // Setup texture + // Setup texture, outer clipping rectangle window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); - - // Setup outer clipping rectangle if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) PushClipRect(parent_window->ClipRectStack.back()); else @@ -3165,30 +3166,25 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (first_begin_of_the_frame) { - window->Visible = true; - // New windows appears in front - if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + if (!window_was_visible) { - if (window->LastFrameDrawn < current_frame - 1) + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { FocusWindow(window); // Popup position themselves when they first appear if (flags & ImGuiWindowFlags_Popup) - { if (!window_pos_set_by_api) window->PosFloat = g.IO.MousePos; - } } } - window->LastFrameDrawn = current_frame; - // Reset contents size for auto-fitting window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos; window->SizeContents.y += window->ScrollY; + // Child position follows drawing cursor if (flags & ImGuiWindowFlags_ChildWindow) { parent_window->DC.ChildWindows.push_back(window); @@ -3259,8 +3255,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; - ImRect title_bar_rect = window->TitleBarRect(); - // Apply scrolling window->ScrollY = window->NextScrollY; window->ScrollY = ImMax(window->ScrollY, 0.0f); @@ -3270,6 +3264,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // At this point we don't have a clipping rectangle setup yet, so we can test and draw in title bar // Collapse window by double-clicking on title bar + ImRect title_bar_rect = window->TitleBarRect(); if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) { if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect) && g.IO.MouseDoubleClicked[0]) From 376a6a5af0f7b6421c63ca7e0e07d133447d34e7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 12:08:24 +0100 Subject: [PATCH 18/28] Tidying up Begin() separated blocks needed for auto-resize so it can be moved above position calculation later Being cautious again. Hopefully didn't break anything. --- imgui.cpp | 93 ++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 808881cb..c0663f80 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3262,12 +3262,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y)); window->NextScrollY = window->ScrollY; - // At this point we don't have a clipping rectangle setup yet, so we can test and draw in title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing // Collapse window by double-clicking on title bar - ImRect title_bar_rect = window->TitleBarRect(); if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) { - if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect) && g.IO.MouseDoubleClicked[0]) + if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(window->TitleBarRect()) && g.IO.MouseDoubleClicked[0]) { window->Collapsed = !window->Collapsed; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) @@ -3294,17 +3293,35 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ size_auto_fit.x += style.ScrollbarWidth; } - const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; + // Update window size if (window->Collapsed) { // We still process initial auto-fit on collapsed windows to get a window width // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. if (window->AutoFitFrames > 0) - { window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; - title_bar_rect = window->TitleBarRect(); + } + else + { + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0 && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. + window->Size = window->SizeFull = size_auto_fit; } - + else if (window->AutoFitFrames > 0) + { + // Auto-fit only grows during the first few frames + window->Size = window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + MarkSettingsDirty(); + } + } + + // Draw window + handle manual resize + ImRect title_bar_rect = window->TitleBarRect(); + const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; + if (window->Collapsed) + { // Draw title bar only window->Size = title_bar_rect.GetSize(); window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); @@ -3317,55 +3334,33 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { ImU32 resize_col = 0; - if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + if (!(window->Flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFrames <= 0 && !(window->Flags & ImGuiWindowFlags_NoResize)) { - window->Size = window->SizeFull = size_auto_fit; - } - else - { - if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + // Manual resize grip + const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); + const ImGuiID resize_id = window->GetID("#RESIZE"); + bool hovered, held; + ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); + resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeNWSE; + + if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { - // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. - window->SizeFull = size_auto_fit; + // Manual auto-fit when double-clicking + window->Size = window->SizeFull = size_auto_fit; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + MarkSettingsDirty(); + SetActiveId(0); } - else if (window->AutoFitFrames > 0) + else if (held) { - // Auto-fit only grows during the first few frames - window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + // Resize + window->Size = window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } - else if (!(window->Flags & ImGuiWindowFlags_NoResize)) - { - // Manual resize grip - const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); - const ImGuiID resize_id = window->GetID("#RESIZE"); - bool hovered, held; - ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); - resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); - - if (hovered || held) - g.MouseCursor = ImGuiMouseCursor_ResizeNWSE; - - if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) - { - // Manual auto-fit when double-clicking - window->SizeFull = size_auto_fit; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); - SetActiveId(0); - } - else if (held) - { - // Resize - window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); - } - } - - // Update rectangle immediately so that rendering right below us isn't one frame late - window->Size = window->SizeFull; title_bar_rect = window->TitleBarRect(); } From 4e292bf67d445180f5136a30ee822ea8031e2ba2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 12:20:06 +0100 Subject: [PATCH 19/28] Tidying up Begin(): separated blocks needed for auto-resize so it can be moved above position calculation later --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c0663f80..290c0e6b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3293,13 +3293,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ size_auto_fit.x += style.ScrollbarWidth; } - // Update window size + // Handle automatic resize if (window->Collapsed) { // We still process initial auto-fit on collapsed windows to get a window width // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. if (window->AutoFitFrames > 0) window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + window->Size = title_bar_rect.GetSize(); } else { @@ -3323,7 +3324,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (window->Collapsed) { // Draw title bar only - window->Size = title_bar_rect.GetSize(); window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); if (window->Flags & ImGuiWindowFlags_ShowBorders) { From 7fac4013a468d80812d4dbcd38f94013873df47e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 12:22:52 +0100 Subject: [PATCH 20/28] Build fix --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 290c0e6b..d219e385 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3300,7 +3300,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. if (window->AutoFitFrames > 0) window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; - window->Size = title_bar_rect.GetSize(); + window->Size = window->TitleBarRect().GetSize(); } else { From 81bf614821edb5c7073530ec09ad5aa4e6ea2ce4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 12:35:34 +0100 Subject: [PATCH 21/28] Fix window size after collapsing (broken 376a6a5af0f7b6421c63ca7e0e07d133447d34e7) --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d219e385..5f541a0b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3349,7 +3349,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { // Manual auto-fit when double-clicking - window->Size = window->SizeFull = size_auto_fit; + window->SizeFull = size_auto_fit; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); SetActiveId(0); @@ -3357,10 +3357,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else if (held) { // Resize - window->Size = window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); + window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } + + window->Size = window->SizeFull; title_bar_rect = window->TitleBarRect(); } From 1b5795c96da069a8aa5231b2df50383ae95e7fe5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 12:45:53 +0100 Subject: [PATCH 22/28] InputText: fixed incorrect edit state after text buffer is modified by user through callback #206 --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 5f541a0b..fea4010b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6690,7 +6690,8 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); if (callback_data.BufDirty) { - ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), g.TempBuffer, NULL); + edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), g.TempBuffer, NULL); + edit_state.CurLenA = strlen(g.TempBuffer); edit_state.CursorAnimReset(); } } From a906738ba7866270d64650e5945af2d49fc073b9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 13:20:50 +0100 Subject: [PATCH 23/28] Renamed Visible->Active internally --- imgui.cpp | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fea4010b..a20dd138 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1262,8 +1262,8 @@ struct ImGuiWindow float ScrollY; float NextScrollY; bool ScrollbarY; - bool Visible; // Set to true on Begin() - bool WasVisible; + bool Active; // Set to true on Begin() + bool WasActive; bool Accessed; // Set to true when any widget access the current window bool Collapsed; // Set when collapsing window to become only title-bar bool SkipItems; // == Visible && !Collapsed @@ -1620,7 +1620,7 @@ ImGuiWindow::ImGuiWindow(const char* name) ScrollY = 0.0f; NextScrollY = 0.0f; ScrollbarY = false; - Visible = WasVisible = false; + Active = WasActive = false; Accessed = false; Collapsed = false; SkipItems = false; @@ -1717,7 +1717,7 @@ static void AddWindowToRenderList(ImVector& out_render_list, ImGuiW for (size_t i = 0; i < window->DC.ChildWindows.size(); i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - if (child->Visible) // clipped children may have been marked not Visible + if (child->Active) // clipped children may have been marked not active AddWindowToRenderList(out_render_list, child); } } @@ -2041,7 +2041,7 @@ void ImGui::NewFrame() // Pressing TAB activate widget focus // NB: Don't discard FocusedWindow if it isn't active, so that a window that go on/off programatically won't lose its keyboard focus. - if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Visible && IsKeyPressedMap(ImGuiKey_Tab, false)) + if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Active && IsKeyPressedMap(ImGuiKey_Tab, false)) { g.FocusedWindow->FocusIdxTabRequestNext = 0; } @@ -2050,8 +2050,8 @@ void ImGui::NewFrame() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - window->WasVisible = window->Visible; - window->Visible = false; + window->WasActive = window->Active; + window->Active = false; window->Accessed = false; } @@ -2136,7 +2136,7 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, ImGuiWindow* window) { out_sorted_windows.push_back(window); - if (window->Visible) + if (window->Active) { const size_t count = window->DC.ChildWindows.size(); if (count > 1) @@ -2144,7 +2144,7 @@ static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, for (size_t i = 0; i < count; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - if (child->Visible) + if (child->Active) AddWindowToSortedBuffer(out_sorted_windows, child); } } @@ -2189,7 +2189,7 @@ void ImGui::Render() // Hide implicit window if it hasn't been used IM_ASSERT(g.CurrentWindowStack.size() == 1); // Mismatched Begin/End if (g.CurrentWindow && !g.CurrentWindow->Accessed) - g.CurrentWindow->Visible = false; + g.CurrentWindow->Active = false; ImGui::End(); if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) @@ -2215,8 +2215,8 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it - if (window->Visible) + if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is active its parent will add it + if (window->Active) continue; AddWindowToSortedBuffer(g.WindowsSortBuffer, window); } @@ -2248,7 +2248,7 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) + if (window->Active && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) { // FIXME: Generalize this with a proper layering system so we can stack. if (window->Flags & ImGuiWindowFlags_Popup) @@ -2595,7 +2595,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) for (int i = (int)g.Windows.size()-1; i >= 0; i--) { ImGuiWindow* window = g.Windows[(size_t)i]; - if (!window->Visible) + if (!window->Active) continue; if (excluding_childs && (window->Flags & ImGuiWindowFlags_ChildWindow) != 0) continue; @@ -3148,10 +3148,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // When reusing window again multiple times a frame, just append content (don't need to setup again) const int current_frame = ImGui::GetFrameCount(); const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame); - const bool window_was_visible = (window->LastFrameDrawn == current_frame - 1); if (first_begin_of_the_frame) { - window->Visible = true; + window->Active = true; window->DrawList->Clear(); window->ClipRectStack.resize(0); window->LastFrameDrawn = current_frame; @@ -3167,7 +3166,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (first_begin_of_the_frame) { // New windows appears in front - if (!window_was_visible) + if (!window->WasActive) { if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { @@ -3518,13 +3517,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // We also hide the window from rendering because we've already added its border to the command list. // (we could perform the check earlier in the function but it is simpler at this point) if (window->Collapsed) - window->Visible = false; + window->Active = false; } if (style.Alpha <= 0.0f) - window->Visible = false; + window->Active = false; // Return false if we don't intend to display anything to allow user to perform an early out optimization - window->SkipItems = (window->Collapsed || !window->Visible) && window->AutoFitFrames <= 0; + window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFrames <= 0; return !window->SkipItems; } @@ -4420,7 +4419,7 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window) // An active popup disable hovering on other windows (apart from its own children) if (ImGuiWindow* focused_window = g.FocusedWindow) if (ImGuiWindow* focused_root_window = focused_window->RootWindow) - if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasVisible && focused_root_window != window->RootWindow) + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow) return false; return true; @@ -10732,7 +10731,7 @@ void ImGui::ShowMetricsWindow(bool* opened) static void NodeWindow(ImGuiWindow* window, const char* label) { - if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Visible, window)) + if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active, window)) return; NodeDrawList(window->DrawList, "DrawList"); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); From 6ca4b31bf8c0f97ba6eb9c5a986abf9a2b0461c9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 15:54:35 +0100 Subject: [PATCH 24/28] Fixed popup resizing (broken 376a6a5af0f7b6421c63ca7e0e07d133447d34e7) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a20dd138..ef2b4672 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3303,7 +3303,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } else { - if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0 && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. window->Size = window->SizeFull = size_auto_fit; From a3560b274ee4c04a86940b4d25415f9573dd0b20 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 17:45:54 +0100 Subject: [PATCH 25/28] Tidying up Begin(): using local copy of 'flags' for brevity --- imgui.cpp | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ef2b4672..9df10b3f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3200,10 +3200,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { if (g.IO.MouseDown[0]) { - if (!(window->Flags & ImGuiWindowFlags_NoMove)) + if (!(flags & ImGuiWindowFlags_NoMove)) { window->PosFloat += g.IO.MouseDelta; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } IM_ASSERT(g.MovedWindow != NULL); @@ -3217,14 +3217,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Tooltips always follows mouse - if (!window_pos_set_by_api && (window->Flags & ImGuiWindowFlags_Tooltip) != 0) + if (!window_pos_set_by_api && (flags & ImGuiWindowFlags_Tooltip) != 0) { ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 28, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, rect_to_avoid); } // Clamp into display - if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip)) + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { if (window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { @@ -3237,7 +3237,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); // Default item width. Make it proportional to window size if window manually resizes - if (window->Size.x > 0.0f && !(window->Flags & ImGuiWindowFlags_Tooltip) && !(window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); else window->ItemWidthDefault = 200.0f; @@ -3263,12 +3263,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing // Collapse window by double-clicking on title bar - if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!(flags & ImGuiWindowFlags_NoTitleBar)) { - if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(window->TitleBarRect()) && g.IO.MouseDoubleClicked[0]) + if (!(flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(window->TitleBarRect()) && g.IO.MouseDoubleClicked[0]) { window->Collapsed = !window->Collapsed; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); FocusWindow(window); } @@ -3280,7 +3280,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Calculate auto-fit size ImVec2 size_auto_fit; - if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + if ((flags & ImGuiWindowFlags_Tooltip) != 0) { // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); @@ -3303,7 +3303,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } else { - if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. window->Size = window->SizeFull = size_auto_fit; @@ -3312,19 +3312,19 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { // Auto-fit only grows during the first few frames window->Size = window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } } // Draw window + handle manual resize ImRect title_bar_rect = window->TitleBarRect(); - const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; + const float window_rounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; if (window->Collapsed) { // Draw title bar only window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); - if (window->Flags & ImGuiWindowFlags_ShowBorders) + if (flags & ImGuiWindowFlags_ShowBorders) { window->DrawList->AddRect(title_bar_rect.GetTL()+ImVec2(1,1), title_bar_rect.GetBR()+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); window->DrawList->AddRect(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border), window_rounding); @@ -3333,7 +3333,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { ImU32 resize_col = 0; - if (!(window->Flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFrames <= 0 && !(window->Flags & ImGuiWindowFlags_NoResize)) + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFrames <= 0 && !(flags & ImGuiWindowFlags_NoResize)) { // Manual resize grip const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); @@ -3349,7 +3349,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { // Manual auto-fit when double-clicking window->SizeFull = size_auto_fit; - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); SetActiveId(0); } @@ -3357,7 +3357,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { // Resize window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); - if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } @@ -3366,31 +3366,31 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Scrollbar - window->ScrollbarY = (window->SizeContents.y > window->Size.y) && !(window->Flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (window->SizeContents.y > window->Size.y) && !(flags & ImGuiWindowFlags_NoScrollbar); // Window background if (bg_alpha > 0.0f) { - if ((window->Flags & ImGuiWindowFlags_ComboBox) != 0) + if ((flags & ImGuiWindowFlags_ComboBox) != 0) window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_ComboBg, bg_alpha), window_rounding); - else if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + else if ((flags & ImGuiWindowFlags_Tooltip) != 0) window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_TooltipBg, bg_alpha), window_rounding); - else if ((window->Flags & ImGuiWindowFlags_ChildWindow) != 0) + else if ((flags & ImGuiWindowFlags_ChildWindow) != 0) window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollbarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF)); else window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding); } // Title bar - if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!(flags & ImGuiWindowFlags_NoTitleBar)) window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); // Borders - if (window->Flags & ImGuiWindowFlags_ShowBorders) + if (flags & ImGuiWindowFlags_ShowBorders) { window->DrawList->AddRect(window->Pos+ImVec2(1,1), window->Pos+window->Size+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); window->DrawList->AddRect(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_Border), window_rounding); - if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!(flags & ImGuiWindowFlags_NoTitleBar)) window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border)); } @@ -3400,7 +3400,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Render resize grip // (after the input handling so we don't have a frame of latency) - if (!(window->Flags & ImGuiWindowFlags_NoResize)) + if (!(flags & ImGuiWindowFlags_NoResize)) { const float r = window_rounding; const ImVec2 br = window->Rect().GetBR(); @@ -3448,13 +3448,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->AutoFitFrames--; // Title bar - if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!(flags & ImGuiWindowFlags_NoTitleBar)) { if (p_opened != NULL) CloseWindowButton(p_opened); ImVec2 text_min = window->Pos + style.FramePadding; - if (!(window->Flags & ImGuiWindowFlags_NoCollapse)) + if (!(flags & ImGuiWindowFlags_NoCollapse)) { RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); text_min.x += g.FontSize + style.ItemInnerSpacing.x; @@ -3464,7 +3464,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); RenderTextClipped(text_min, name, NULL, &text_size, text_max); } - if (window->Flags & ImGuiWindowFlags_Popup) + if (flags & ImGuiWindowFlags_Popup) { if (p_opened) { From 221f36e11690466a0e528d88bacda16cf43ce330 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 17:54:25 +0100 Subject: [PATCH 26/28] Comments, tweaks, metrics window tweak --- imgui.cpp | 9 +++------ imgui.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9df10b3f..115b5484 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3154,6 +3154,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DrawList->Clear(); window->ClipRectStack.resize(0); window->LastFrameDrawn = current_frame; + window->IDStack.resize(1); } // Setup texture, outer clipping rectangle @@ -3191,9 +3192,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->SizeFull = size_on_first_use; } - // Reset ID stack - window->IDStack.resize(1); - // Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. RegisterAliveId(window->MoveID); if (g.ActiveId == window->MoveID) @@ -3335,7 +3333,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImU32 resize_col = 0; if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFrames <= 0 && !(flags & ImGuiWindowFlags_NoResize)) { - // Manual resize grip + // Manual resize const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; @@ -3355,7 +3353,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } else if (held) { - // Resize window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); @@ -10731,7 +10728,7 @@ void ImGui::ShowMetricsWindow(bool* opened) static void NodeWindow(ImGuiWindow* window, const char* label) { - if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active, window)) + if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) return; NodeDrawList(window->DrawList, "DrawList"); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); diff --git a/imgui.h b/imgui.h index 6c2b4a3f..2357dd40 100644 --- a/imgui.h +++ b/imgui.h @@ -159,7 +159,7 @@ namespace ImGui IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window, demonstrate ImGui features - IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window + IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window for debugging imgui // Window // See implementation in .cpp for details From 99e315d2b22659ca439ad5723d34f7ebdf6ac39e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 18:14:24 +0100 Subject: [PATCH 27/28] Fix for width of child windows with scrollbar (broken 376a6a5af0f7b6421c63ca7e0e07d133447d34e7) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 115b5484..d8f4099f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3304,15 +3304,16 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. - window->Size = window->SizeFull = size_auto_fit; + window->SizeFull = size_auto_fit; } else if (window->AutoFitFrames > 0) { // Auto-fit only grows during the first few frames - window->Size = window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } + window->Size = window->SizeFull; } // Draw window + handle manual resize From d84b5737a6526a6ecce40ed8d1fc35d0f5a0a9a6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 May 2015 18:22:46 +0100 Subject: [PATCH 28/28] Popups, Tooltips: fit within display. Hidden during size calculation. Fixed popups flicker when changing size. Big change, needed reorder of Begin(). May trigger new bugs. --- imgui.cpp | 184 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 76 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d8f4099f..6825a91c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1269,6 +1269,8 @@ struct ImGuiWindow bool SkipItems; // == Visible && !Collapsed int AutoFitFrames; bool AutoFitOnlyGrows; + int AutoPosLastDirection; + int HiddenFrames; int SetWindowPosAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowPos() call will succeed with this particular flag. int SetWindowSizeAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowSize() call will succeed with this particular flag. int SetWindowCollapsedAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowCollapsed() call will succeed with this particular flag. @@ -1626,6 +1628,8 @@ ImGuiWindow::ImGuiWindow(const char* name) SkipItems = false; AutoFitFrames = -1; AutoFitOnlyGrows = false; + AutoPosLastDirection = -1; + HiddenFrames = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiSetCond_Always | ImGuiSetCond_Once | ImGuiSetCond_FirstUseEver; LastFrameDrawn = -1; @@ -2248,7 +2252,7 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Active && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) + if (window->Active && window->HiddenFrames <= 0 && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) { // FIXME: Generalize this with a proper layering system so we can stack. if (window->Flags & ImGuiWindowFlags_Popup) @@ -2975,7 +2979,7 @@ void ImGui::EndChildFrame() ImGui::PopStyleColor(); } -static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, const ImRect& r_inner) +static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, int* last_dir, const ImRect& r_inner) { const ImGuiStyle& style = GImGui->Style; @@ -2984,15 +2988,18 @@ static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, con r_outer.Reduce(style.DisplaySafeAreaPadding); ImVec2 mouse_pos_clamped = ImClamp(mouse_pos, r_outer.Min, r_outer.Max - size); - for (int dir = 0; dir < 4; dir++) // right, down, up, left + for (int n = (*last_dir != -1) ? -1 : 0; n < 4; n++) // Right, down, up, left. Favor last used direction. { + const int dir = (n == -1) ? *last_dir : n; ImRect rect(dir == 0 ? r_inner.Max.x : r_outer.Min.x, dir == 1 ? r_inner.Max.y : r_outer.Min.y, dir == 3 ? r_inner.Min.x : r_outer.Max.x, dir == 2 ? r_inner.Min.y : r_outer.Max.y); if (rect.GetWidth() < size.x || rect.GetHeight() < size.y) continue; + *last_dir = dir; return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : mouse_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : mouse_pos_clamped.y); } // Fallback + *last_dir = -1; return mouse_pos + ImVec2(2,2); } @@ -3169,30 +3176,120 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // New windows appears in front if (!window->WasActive) { + window->AutoPosLastDirection = -1; + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { FocusWindow(window); - // Popup position themselves when they first appear - if (flags & ImGuiWindowFlags_Popup) - if (!window_pos_set_by_api) - window->PosFloat = g.IO.MousePos; + // Popup first latch mouse position, will position itself when it appears next frame + if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) + window->PosFloat = g.IO.MousePos; } } - // Reset contents size for auto-fitting + // Collapse window by double-clicking on title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) + { + if (g.HoveredWindow == window && IsMouseHoveringRect(window->TitleBarRect()) && g.IO.MouseDoubleClicked[0]) + { + window->Collapsed = !window->Collapsed; + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + MarkSettingsDirty(); + FocusWindow(window); + } + } + else + { + window->Collapsed = false; + } + + const bool window_appearing_after_being_hidden = (window->HiddenFrames == 1); + if (window->HiddenFrames > 0) + window->HiddenFrames--; + + // SIZE + + // Save contents size from last frame for auto-fitting window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos; window->SizeContents.y += window->ScrollY; - // Child position follows drawing cursor + // Hide popup/tooltip window when first appearing while we measure size (because we recycle them) + if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window->WasActive) + { + window->HiddenFrames = 1; + window->Size = window->SizeFull = window->SizeContents = ImVec2(0.f, 0.f); // TODO: We don't support SetNextWindowSize() for tooltips or popups yet + } + + // Calculate auto-fit size + ImVec2 size_auto_fit; + if ((flags & ImGuiWindowFlags_Tooltip) != 0) + { + // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. + size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); + } + else + { + size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); + if (size_auto_fit.y < window->SizeContents.y + style.AutoFitPadding.y) + size_auto_fit.x += style.ScrollbarWidth; + } + + // Handle automatic resize + if (window->Collapsed) + { + // We still process initial auto-fit on collapsed windows to get a window width, + // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (window->AutoFitFrames > 0) + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + window->Size = window->TitleBarRect().GetSize(); + } + else + { + if (flags & ImGuiWindowFlags_AlwaysAutoResize) + { + window->SizeFull = size_auto_fit; + } + else if (window->AutoFitFrames > 0) + { + // Auto-fit only grows during the first few frames + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + MarkSettingsDirty(); + } + window->Size = window->SizeFull; + } + + // Minimum window size + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); + + // POSITION + + // Position child window if (flags & ImGuiWindowFlags_ChildWindow) { parent_window->DC.ChildWindows.push_back(window); window->Pos = window->PosFloat = parent_window->DC.CursorPos; - window->SizeFull = size_on_first_use; + window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user. } - // Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. + // Position popup + if ((flags & ImGuiWindowFlags_Popup) != 0 && window_appearing_after_being_hidden && !window_pos_set_by_api) + { + ImRect rect_to_avoid(window->PosFloat.x - 1, window->PosFloat.y - 1, window->PosFloat.x + 1, window->PosFloat.y + 1); + window->PosFloat = FindBestWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid); + } + + // Position tooltip (always follows mouse) + if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api) + { + ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 24, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? + window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, &window->AutoPosLastDirection, rect_to_avoid); + } + + // User moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. RegisterAliveId(window->MoveID); if (g.ActiveId == window->MoveID) { @@ -3214,13 +3311,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } } - // Tooltips always follows mouse - if (!window_pos_set_by_api && (flags & ImGuiWindowFlags_Tooltip) != 0) - { - ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 28, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? - window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, rect_to_avoid); - } - // Clamp into display if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { @@ -3230,7 +3320,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size; window->PosFloat = ImMin(window->PosFloat, g.IO.DisplaySize - padding); } - window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); } window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); @@ -3259,63 +3348,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y)); window->NextScrollY = window->ScrollY; - // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing - // Collapse window by double-clicking on title bar - if (!(flags & ImGuiWindowFlags_NoTitleBar)) - { - if (!(flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(window->TitleBarRect()) && g.IO.MouseDoubleClicked[0]) - { - window->Collapsed = !window->Collapsed; - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); - FocusWindow(window); - } - } - else - { - window->Collapsed = false; - } - - // Calculate auto-fit size - ImVec2 size_auto_fit; - if ((flags & ImGuiWindowFlags_Tooltip) != 0) - { - // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); - } - else - { - size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); - if (size_auto_fit.y < window->SizeContents.y + style.AutoFitPadding.y) - size_auto_fit.x += style.ScrollbarWidth; - } - - // Handle automatic resize - if (window->Collapsed) - { - // We still process initial auto-fit on collapsed windows to get a window width - // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. - if (window->AutoFitFrames > 0) - window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; - window->Size = window->TitleBarRect().GetSize(); - } - else - { - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) - { - // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. - window->SizeFull = size_auto_fit; - } - else if (window->AutoFitFrames > 0) - { - // Auto-fit only grows during the first few frames - window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); - } - window->Size = window->SizeFull; - } - // Draw window + handle manual resize ImRect title_bar_rect = window->TitleBarRect(); const float window_rounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding;