From f563e1a50451fb1a61fd34a3d8c02b95dc983a94 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 19 Jun 2019 18:14:24 +0200 Subject: [PATCH 01/14] Internals: Renamed GetFrontMostPopupModal() to GetTopMostPopupModal() to be consistent. Renamed other locals to follow that terminology. --- imgui.cpp | 36 ++++++++++++++++++------------------ imgui.h | 6 +++--- imgui_internal.h | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 53289533..0df747f8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3298,7 +3298,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; } - else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) + else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL) { // Clicking on void disable focus FocusWindow(NULL); @@ -3310,9 +3310,9 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) if (g.IO.MouseClicked[1]) { - // Find the top-most window between HoveredWindow and the front most Modal Window. + // Find the top-most window between HoveredWindow and the top-most Modal Window. // This is where we can trim the popup stack. - ImGuiWindow* modal = GetFrontMostPopupModal(); + ImGuiWindow* modal = GetTopMostPopupModal(); bool hovered_window_above_modal = false; if (modal == NULL) hovered_window_above_modal = true; @@ -3458,7 +3458,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() FindHoveredWindow(); // Modal windows prevents cursor from hovering behind them. - ImGuiWindow* modal_window = GetFrontMostPopupModal(); + ImGuiWindow* modal_window = GetTopMostPopupModal(); if (modal_window) if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) g.HoveredRootWindow = g.HoveredWindow = NULL; @@ -3654,7 +3654,7 @@ void ImGui::NewFrame() UpdateMouseMovingWindowNewFrame(); // Background darkening/whitening - if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) + if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); else g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); @@ -4062,18 +4062,18 @@ void ImGui::Render() if (!g.BackgroundDrawList.VtxBuffer.empty()) AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); - ImGuiWindow* windows_to_render_front_most[2]; - windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; - windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL; + ImGuiWindow* windows_to_render_top_most[2]; + windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_top_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL; for (int n = 0; n != g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; - if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1]) + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) AddRootWindowToDrawData(window); } - for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++) - if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window - AddRootWindowToDrawData(windows_to_render_front_most[n]); + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) + if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window + AddRootWindowToDrawData(windows_to_render_top_most[n]); g.DrawDataBuilder.FlattenIntoSingleLayer(); // Draw software mouse cursor if requested @@ -5648,7 +5648,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) PushClipRect(host_rect.Min, host_rect.Max, false); // Draw modal window background (darkens what is behind them, all viewports) - const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; + const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); if (dim_bg_for_modal || dim_bg_for_window_list) { @@ -5893,7 +5893,7 @@ void ImGui::BringWindowToFocusFront(ImGuiWindow* window) ImGuiContext& g = *GImGui; if (g.WindowsFocusOrder.back() == window) return; - for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window + for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window if (g.WindowsFocusOrder[i] == window) { memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); @@ -5908,7 +5908,7 @@ void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) ImGuiWindow* current_front_window = g.Windows.back(); if (current_front_window == window || current_front_window->RootWindow == window) return; - for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window if (g.Windows[i] == window) { memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); @@ -7178,7 +7178,7 @@ bool ImGui::IsPopupOpen(const char* str_id) return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); } -ImGuiWindow* ImGui::GetFrontMostPopupModal() +ImGuiWindow* ImGui::GetTopMostPopupModal() { ImGuiContext& g = *GImGui; for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) @@ -8435,7 +8435,7 @@ static void ImGui::NavUpdateWindowing() ImGuiWindow* apply_focus_window = NULL; bool apply_toggle_layer = false; - ImGuiWindow* modal_window = GetFrontMostPopupModal(); + ImGuiWindow* modal_window = GetTopMostPopupModal(); if (modal_window != NULL) { g.NavWindowingTarget = NULL; @@ -8477,7 +8477,7 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingHighlightAlpha = 1.0f; } - // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most) + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) if (!IsNavInputDown(ImGuiNavInput_Menu)) { g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. diff --git a/imgui.h b/imgui.h index 8131ac36..32b267e2 100644 --- a/imgui.h +++ b/imgui.h @@ -275,17 +275,17 @@ namespace ImGui IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() - IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() + IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). - IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state - IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. // Content region // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion) diff --git a/imgui_internal.h b/imgui_internal.h index 599f360f..67ee3b4d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -919,7 +919,7 @@ struct ImGuiContext ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. int NavScoringCount; // Metrics for debugging - ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most. + ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed top-most. ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f ImGuiWindow* NavWindowingList; float NavWindowingTimer; @@ -1520,7 +1520,7 @@ namespace ImGui IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); - IMGUI_API ImGuiWindow* GetFrontMostPopupModal(); + IMGUI_API ImGuiWindow* GetTopMostPopupModal(); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default); From 41e2d4b5ae156462fc1c74c3c0d7fd1525da3b62 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Jun 2019 16:09:31 +0200 Subject: [PATCH 02/14] ImDrawListSplitter: Fixed memory leak when using low-level split api (was not affecting ImDrawList api, also this type was added in 1.71 and not advertised as a public-facing feature). --- docs/CHANGELOG.txt | 4 +++- imgui.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d1e0b820..6d747304 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,8 +46,10 @@ Other Changes: - Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). - ImDrawList: Fixed CloneOutput() helper crashing. (#1860) [@gviot] -- ImDrawListSlitter, ImDrawList::ChannelsSplit(), : Fixed an issue with merging draw commands between +- ImDrawList::ChannelsSplit(), ImDrawListSplitter: Fixed an issue with merging draw commands between channel 0 and 1. (#2624) +- ImDrawListSplitter: Fixed memory leak when using low-level split api (was not affecting ImDrawList api, + also this type was added in 1.71 and not advertised as a public-facing feature). - Backends: SDL2: Added dummy ImGui_ImplSDL2_InitForD3D() function to make D3D support more visible. (#2482, #2632) [@josiahmanson] - Examples: Added SDL2+DirectX11 example application. (#2632, #2612, #2482) [@vincenthamm] diff --git a/imgui.h b/imgui.h index 32b267e2..101f4249 100644 --- a/imgui.h +++ b/imgui.h @@ -1822,7 +1822,8 @@ struct ImDrawListSplitter int _Count; // Number of active channels (1+) ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) - inline ImDrawListSplitter() { Clear(); } + inline ImDrawListSplitter() { Clear(); } + inline ~ImDrawListSplitter() { ClearFreeMemory(); } inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame IMGUI_API void ClearFreeMemory(); IMGUI_API void Split(ImDrawList* draw_list, int count); From eb3e271c24c25f668be02bbf25aeb46a46b9fc08 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Jun 2019 19:38:33 +0200 Subject: [PATCH 03/14] Demo: Using ImVec2(-FLT_MIN,0.0f) instead of ImVec2(-1.0f,0.0f) where it makes sense. (#2449) --- imgui_demo.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e4b89499..80c57771 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -968,7 +968,7 @@ static void ShowDemoWindowWidgets() ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); - ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), flags); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); ImGui::TreePop(); } @@ -1024,7 +1024,7 @@ static void ShowDemoWindowWidgets() static ImVector my_str; if (my_str.empty()) my_str.push_back(0); - Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16)); + Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); ImGui::TreePop(); } @@ -1085,7 +1085,8 @@ static void ShowDemoWindowWidgets() if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } } - // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, + // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f)); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::Text("Progress Bar"); @@ -1727,7 +1728,7 @@ static void ShowDemoWindowLayout() { char buf[32]; sprintf(buf, "%03d", i); - ImGui::Button(buf, ImVec2(-1.0f, 0.0f)); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); ImGui::NextColumn(); } ImGui::EndChild(); @@ -2519,7 +2520,7 @@ static void ShowDemoWindowColumns() char label[32]; sprintf(label, "Item %d", n); if (ImGui::Selectable(label)) {} - //if (ImGui::Button(label, ImVec2(-1,0))) {} + //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} ImGui::NextColumn(); } ImGui::Columns(1); @@ -2570,7 +2571,7 @@ static void ShowDemoWindowColumns() ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); ImGui::Text("Long text that is likely to clip"); - ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); + ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); ImGui::NextColumn(); } ImGui::Columns(1); From 4b95e7c2f3d5793bf73c7e8b4c130696010d2f19 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 26 Jun 2019 12:15:32 +0200 Subject: [PATCH 04/14] Doc: Tweak and extra mention of AddCustomRectFontGlyph + made the example register two rectangles. --- imgui.cpp | 2 ++ misc/fonts/README.txt | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0df747f8..79c2de90 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -844,6 +844,8 @@ CODE main font. Then you can refer to icons within your strings. You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment. (Read the 'misc/fonts/README.txt' file for more details about icons font loading.) + With some extra effort, you may use colorful icon by registering custom rectangle space inside the font atlas, + and copying your own graphics data into it. See misc/fonts/README.txt about using the AddCustomRectFontGlyph API. Q: How can I load multiple fonts? A: Use the font atlas to pack them into a single texture: diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index 010a7207..cf953cf6 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -212,9 +212,11 @@ texture, and blit/copy any graphics data of your choice into those rectangles. Pseudo-code: - // Add font, then register one custom 13x13 rectangle mapped to glyph 'a' of this font + // Add font, then register two custom 13x13 rectangles mapped to glyph 'a' and 'b' of this font ImFont* font = io.Fonts->AddFontDefault(); - int rect_id = io.Fonts->AddCustomRectFontGlyph(font, 'a', 13, 13, 13+1); + int rect_ids[2]; + rect_ids[0] = io.Fonts->AddCustomRectFontGlyph(font, 'a', 13, 13, 13+1); + rect_ids[1] = io.Fonts->AddCustomRectFontGlyph(font, 'b', 13, 13, 13+1); // Build atlas io.Fonts->Build(); @@ -224,14 +226,18 @@ Pseudo-code: int tex_width, tex_height; io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_width, &tex_height); - // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here) - if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) + for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) { - for (int y = 0; y < rect->Height; y++) + int rect_id = rects_ids[rect_n]; + if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) { - ImU32* p = (ImU32*)tex_pixels + (rect->Y + y) * tex_width + (rect->X); - for (int x = rect->Width; x > 0; x--) - *p++ = IM_COL32(255, 0, 0, 255); + // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here!) + for (int y = 0; y < rect->Height; y++) + { + ImU32* p = (ImU32*)tex_pixels + (rect->Y + y) * tex_width + (rect->X); + for (int x = rect->Width; x > 0; x--) + *p++ = IM_COL32(255, 0, 0, 255); + } } } From 1dd322c6fb700242b156f898862ec098fa88b633 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 27 Jun 2019 12:20:18 +0200 Subject: [PATCH 05/14] Style: Attenuated default opacity of ImGuiCol_Separator in Classic and Light styles. --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6d747304..bff027d3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,7 @@ Other Changes: - Window: Fixed InnerClipRect right-most coordinates using wrong padding setting (introduced in 1.71). - Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). +- Style: Attenuated default opacity of ImGuiCol_Separator in Classic and Light styles. - ImDrawList: Fixed CloneOutput() helper crashing. (#1860) [@gviot] - ImDrawList::ChannelsSplit(), ImDrawListSplitter: Fixed an issue with merging draw commands between channel 0 and 1. (#2624) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e54a5fdc..7b20f2b1 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -260,7 +260,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); - colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); @@ -316,7 +316,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); From 82711251b66a30b63a815ec6f9519c2cb6914cce Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 27 Jun 2019 18:03:19 +0200 Subject: [PATCH 06/14] Internals: ImGuiListClipper using absolute coordinate (instead of relative one). Minor no-op tweaks + ImDrawListSplitter assert --- imgui.cpp | 31 ++++++++++++++++++++----------- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79c2de90..6096f510 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2239,7 +2239,8 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) //----------------------------------------------------------------------------- // [SECTION] ImGuiListClipper -// This is currently not as flexible/powerful as it should be, needs some rework (see TODO) +// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed +// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) //----------------------------------------------------------------------------- static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) @@ -2247,12 +2248,14 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. // The clipper should probably have a 4th step to display the last item in a regular manner. - ImGui::SetCursorPosY(pos_y); - ImGuiWindow* window = ImGui::GetCurrentWindow(); - window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. - window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos.y = pos_y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. if (ImGuiColumns* columns = window->DC.CurrentColumns) - columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly + columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly } // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 @@ -2260,7 +2263,10 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) // FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. void ImGuiListClipper::Begin(int count, float items_height) { - StartPosY = ImGui::GetCursorPosY(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + StartPosY = window->DC.CursorPos.y; ItemsHeight = items_height; ItemsCount = count; StepNo = 0; @@ -2287,7 +2293,10 @@ void ImGuiListClipper::End() bool ImGuiListClipper::Step() { - if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (ItemsCount == 0 || window->SkipItems) { ItemsCount = -1; return false; @@ -2296,16 +2305,16 @@ bool ImGuiListClipper::Step() { DisplayStart = 0; DisplayEnd = 1; - StartPosY = ImGui::GetCursorPosY(); + StartPosY = window->DC.CursorPos.y; StepNo = 1; return true; } if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. { if (ItemsCount == 1) { ItemsCount = -1; return false; } - float items_height = ImGui::GetCursorPosY() - StartPosY; + float items_height = window->DC.CursorPos.y - StartPosY; IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically - Begin(ItemsCount-1, items_height); + Begin(ItemsCount - 1, items_height); DisplayStart++; DisplayEnd++; StepNo = 3; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 80c57771..afd2b894 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4022,7 +4022,7 @@ static void ShowExampleAppLongText(bool* p_open) static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7b20f2b1..51ff2cd9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1304,7 +1304,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) { - IM_ASSERT(idx < _Count); + IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) return; // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() From 401e05147cedbe50dd150b46f1a323e622929a9a Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 29 Jun 2019 18:55:06 +0200 Subject: [PATCH 07/14] Internals: Moved CalcListClipping close to ImGuiListClipper code (no-op) --- imgui.cpp | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6096f510..10538602 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2243,6 +2243,47 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) // the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) //----------------------------------------------------------------------------- +// Helper to calculate coarse clipping of large list of evenly sized items. +// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. +// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX +void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (window->SkipItems) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect + ImRect unclipped_rect = window->ClipRect; + if (g.NavMoveRequest) + unclipped_rect.Add(g.NavScoringRectScreen); + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); + int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); + + // When performing a navigation request, ensure we have one item extra in the direction we are moving to + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) + end++; + + start = ImClamp(start, 0, items_count); + end = ImClamp(end + 1, start, items_count); + *out_items_display_start = start; + *out_items_display_end = end; +} + static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) { // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. @@ -4130,47 +4171,6 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex return text_size; } -// Helper to calculate coarse clipping of large list of evenly sized items. -// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. -// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX -void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (g.LogEnabled) - { - // If logging is active, do not perform any clipping - *out_items_display_start = 0; - *out_items_display_end = items_count; - return; - } - if (window->SkipItems) - { - *out_items_display_start = *out_items_display_end = 0; - return; - } - - // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect - ImRect unclipped_rect = window->ClipRect; - if (g.NavMoveRequest) - unclipped_rect.Add(g.NavScoringRectScreen); - - const ImVec2 pos = window->DC.CursorPos; - int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); - int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); - - // When performing a navigation request, ensure we have one item extra in the direction we are moving to - if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) - start--; - if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) - end++; - - start = ImClamp(start, 0, items_count); - end = ImClamp(end + 1, start, items_count); - *out_items_display_start = start; - *out_items_display_end = end; -} - // Find window given position, search front-to-back // FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically // with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is From a89f05a10e80fc25f64dc32f0feff164bb1ede27 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 27 Jun 2019 16:35:56 +0200 Subject: [PATCH 08/14] Child windows inherit Hidden frames setting from parent more accurately, so HiddenFramesCannotSkipItems is honored by child windows. --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 10538602..5f402f74 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5832,9 +5832,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) window->HiddenFramesCanSkipItems = 1; - // Completely hide along with parent or if parent is collapsed - if (parent_window && (parent_window->Collapsed || parent_window->Hidden)) + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; } // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) From 2a3517a39983c4b7a2d4c1596b803e20d2137fc2 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 30 Jun 2019 12:03:09 +0200 Subject: [PATCH 09/14] Internals: Checkbox: Added undocumented mixed/indeterminate/tristate support via ImGuiItemFlags_MixedValue. (#2644) --- docs/TODO.txt | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 11 +++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index a918b9e1..cdd92383 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -65,7 +65,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: start exposing PushItemFlag() and ImGuiItemFlags - widgets: alignment options in style (e.g. center Selectable, Right-Align within Button, etc.) #1260 - widgets: activate by identifier (trigger button, focus given id) - - widgets: a way to represent "mixed" values, so e.g. all values replaced with **, including check-boxes, colors, etc. with support for multi-components widgets (e.g. SliderFloat3, make only "Y" mixed) + - widgets: a way to represent "mixed" values, so e.g. all values replaced with *, including check-boxes, colors, etc. with support for multi-components widgets (e.g. SliderFloat3, make only "Y" mixed) (#2644) - widgets: selectable: generic BeginSelectable()/EndSelectable() mechanism. - widgets: selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) - widgets: checkbox: checkbox with custom glyph inside frame. diff --git a/imgui_internal.h b/imgui_internal.h index 67ee3b4d..3b96116e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -384,6 +384,7 @@ enum ImGuiItemFlags_ ImGuiItemFlags_NoNav = 1 << 3, // false ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window + ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_Default_ = 0 }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3490586b..a5959c23 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1001,10 +1001,17 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); RenderNavHighlight(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); - if (*v) + ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); + if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue) + { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + ImVec2 pad(ImMax(1.0f, (float)(int)(square_sz / 3.6f)), ImMax(1.0f, (float)(int)(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } + else if (*v) { const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f)); - RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), square_sz - pad*2.0f); + RenderCheckMark(check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad*2.0f); } if (g.LogEnabled) From caf119a982dab93ab45a312be4f2d243f034b097 Mon Sep 17 00:00:00 2001 From: kevreco Date: Tue, 30 Jan 2018 21:51:28 +0100 Subject: [PATCH 10/14] Added 'SetScrollHereX' and 'SetScrollFromPosX' (#1580) --- imgui.cpp | 26 +++++++++++++++++++++++++- imgui.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 5f402f74..1f877961 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4841,7 +4841,12 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s if (window->ScrollTarget.x < FLT_MAX) { float cr_x = window->ScrollTargetCenterRatio.x; - scroll.x = window->ScrollTarget.x - cr_x * window->InnerRect.GetWidth(); + float target_x = window->ScrollTarget.x; + if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x) + target_x = 0.0f; + else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + GImGui->Style.ItemSpacing.x) + target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f; + scroll.x = target_x - cr_x * window->InnerRect.GetWidth(); } if (window->ScrollTarget.y < FLT_MAX) { @@ -6861,6 +6866,25 @@ void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) window->ScrollTargetCenterRatio.y = center_y_ratio; } +void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +{ + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); + window->ScrollTarget.x = (float)(int)(local_x + window->Scroll.x); + window->ScrollTargetCenterRatio.x = center_x_ratio; +} + +// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiWindow* window = GetCurrentWindow(); + float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space + float last_item_width = window->DC.LastItemRect.GetWidth(); + target_x += (last_item_width * center_x_ratio) + (GImGui->Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item. + SetScrollFromPosX(target_x, center_x_ratio); +} + // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. void ImGui::SetScrollHereY(float center_y_ratio) { diff --git a/imgui.h b/imgui.h index 101f4249..7b34c7c5 100644 --- a/imgui.h +++ b/imgui.h @@ -302,7 +302,9 @@ namespace ImGui IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] + IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. // Parameters stacks (shared) From da29d77253072ad16128e9c9104bf8ad71299822 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 Jul 2019 12:15:36 +0200 Subject: [PATCH 11/14] Added SetScrollXHere, SetScrollFromPosX: Changelog, demo, comments (#1580). --- docs/CHANGELOG.txt | 1 + docs/TODO.txt | 1 + imgui.cpp | 18 ++++++------ imgui_demo.cpp | 73 ++++++++++++++++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bff027d3..f1861aac 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,7 @@ Other Changes: - Window: Fixed InnerClipRect right-most coordinates using wrong padding setting (introduced in 1.71). - Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). +- Scrolling: Added SetScrollHereX(), SetScrollFromPosX() for completeness. (#1580) [@kevreco] - Style: Attenuated default opacity of ImGuiCol_Separator in Classic and Light styles. - ImDrawList: Fixed CloneOutput() helper crashing. (#1860) [@gviot] - ImDrawList::ChannelsSplit(), ImDrawListSplitter: Fixed an issue with merging draw commands between diff --git a/docs/TODO.txt b/docs/TODO.txt index cdd92383..d5291373 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -30,6 +30,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false. - window/child: the first draw command of a child window could be moved into the current draw command of the parent window (unless child+tooltip?). - window/child: border could be emitted in parent as well. + - window/child: allow SetNextWindowContentSize() to work on child windows. - window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. - window/tab: add a way to signify that a window or docked window requires attention (e.g. blinking title bar). - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) diff --git a/imgui.cpp b/imgui.cpp index 1f877961..5d37d08c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6857,15 +6857,6 @@ void ImGui::SetScrollY(float scroll_y) window->ScrollTargetCenterRatio.y = 0.0f; } -void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) -{ - // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size - ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y); - window->ScrollTargetCenterRatio.y = center_y_ratio; -} - void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) { // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size @@ -6875,6 +6866,15 @@ void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) window->ScrollTargetCenterRatio.x = center_x_ratio; } +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y); + window->ScrollTargetCenterRatio.y = center_y_ratio; +} + // center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. void ImGui::SetScrollHereX(float center_x_ratio) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index afd2b894..8d9337a5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1744,7 +1744,7 @@ static void ShowDemoWindowLayout() // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window) // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this. { - ImGui::SetCursorPosX(50); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10); ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None); for (int n = 0; n < 50; n++) @@ -1957,7 +1957,7 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Groups")) { - HelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it."); + HelpMarker("BeginGroup() basically locks the horizontal position for new line. EndGroup() bundles the whole group so that you can use \"item\" functions such as IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); ImGui::BeginGroup(); { ImGui::BeginGroup(); @@ -2056,21 +2056,22 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Scrolling")) { - HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position."); + // Vertical scroll functions + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); static bool track = true; - static int track_line = 50; + static int track_item = 50; static float scroll_to_off_px = 0.0f; static float scroll_to_pos_px = 200.0f; ImGui::Checkbox("Track", &track); ImGui::PushItemWidth(100); - ImGui::SameLine(140); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d"); + ImGui::SameLine(140); track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); bool scroll_to_off = ImGui::Button("Scroll Offset"); - ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off_y", &scroll_to_off_px, 1.00f, 0, 9999, "+%.0f px"); + ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, 9999, "+%.0f px"); bool scroll_to_pos = ImGui::Button("Scroll To Pos"); - ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos_y", &scroll_to_pos_px, 1.00f, 0, 9999, "Y = %.0f px"); + ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, 0, 9999, "X/Y = %.0f px"); ImGui::PopItemWidth(); if (scroll_to_off || scroll_to_pos) @@ -2078,28 +2079,31 @@ static void ShowDemoWindowLayout() ImGuiStyle& style = ImGui::GetStyle(); float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; + if (child_w < 20.0f) + child_w = 20.0f; + ImGui::PushID("##VerticalScrolling"); for (int i = 0; i < 5; i++) { if (i > 0) ImGui::SameLine(); ImGui::BeginGroup(); - ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); + const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; + ImGui::TextUnformatted(names[i]); - ImGuiWindowFlags child_flags = ImGuiWindowFlags_MenuBar; - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, ImGuiWindowFlags_None); if (scroll_to_off) ImGui::SetScrollY(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); - for (int line = 0; line < 100; line++) + for (int item = 0; item < 100; item++) { - if (track && line == track_line) + if (track && item == track_item) { - ImGui::TextColored(ImVec4(1,1,0,1), "Line %d", line); + ImGui::TextColored(ImVec4(1,1,0,1), "Item %d", item); ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom } else { - ImGui::Text("Line %d", line); + ImGui::Text("Item %d", item); } } float scroll_y = ImGui::GetScrollY(); @@ -2108,11 +2112,44 @@ static void ShowDemoWindowLayout() ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); ImGui::EndGroup(); } - ImGui::TreePop(); - } + ImGui::PopID(); - if (ImGui::TreeNode("Horizontal Scrolling")) - { + // Horizontal scroll functions + ImGui::Spacing(); + HelpMarker("Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\nUsing the \"Scroll To Pos\" button above will make the discontinuity at edges visible: scrolling to the top/bottom/left/right-most item will add an additional WindowPadding to reflect on reaching the edge of the list.\n\nBecause the clipping rectangle of most window hides half worth of WindowPadding on the left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the equivalent SetScrollFromPosY(+1) wouldn't."); + ImGui::PushID("##HorizontalScrolling"); + for (int i = 0; i < 5; i++) + { + float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, ImGuiWindowFlags_HorizontalScrollbar); + if (scroll_to_off) + ImGui::SetScrollX(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); + for (int item = 0; item < 100; item++) + { + if (track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + } + else + { + ImGui::Text("Item %d", item); + } + ImGui::SameLine(); + } + float scroll_x = ImGui::GetScrollX(); + float scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::SameLine(); + const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; + ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); + ImGui::Spacing(); + } + ImGui::PopID(); + + // Miscellaneous Horizontal Scrolling Demo HelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); static int lines = 7; ImGui::SliderInt("Lines", &lines, 1, 15); From 58c9f8a19450650088e92858f6df25a4a4237f97 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 Jul 2019 18:48:21 +0200 Subject: [PATCH 12/14] Misc: Added IMGUI_DISABLE_METRICS_WINDOW imconfig.h setting to explicitly compile out ShowMetricsWindow(). + Internals: Minor renaming. --- docs/CHANGELOG.txt | 1 + imconfig.h | 1 + imgui.cpp | 39 +++++++++++++++++++++++---------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f1861aac..3eaed626 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,7 @@ Other Changes: of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). - Scrolling: Added SetScrollHereX(), SetScrollFromPosX() for completeness. (#1580) [@kevreco] - Style: Attenuated default opacity of ImGuiCol_Separator in Classic and Light styles. +- Misc: Added IMGUI_DISABLE_METRICS_WINDOW imconfig.h setting to explicitly compile out ShowMetricsWindow(). - ImDrawList: Fixed CloneOutput() helper crashing. (#1860) [@gviot] - ImDrawList::ChannelsSplit(), ImDrawListSplitter: Fixed an issue with merging draw commands between channel 0 and 1. (#2624) diff --git a/imconfig.h b/imconfig.h index 4d7adf5d..5d9caecd 100644 --- a/imconfig.h +++ b/imconfig.h @@ -28,6 +28,7 @@ //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) // It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. //#define IMGUI_DISABLE_DEMO_WINDOWS +//#define IMGUI_DISABLE_METRICS_WINDOW //---- Don't implement some functions to reduce linkage requirements. //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. diff --git a/imgui.cpp b/imgui.cpp index 5d37d08c..f5602651 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9935,6 +9935,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} // [SECTION] METRICS/DEBUG WINDOW //----------------------------------------------------------------------------- +#ifndef IMGUI_DISABLE_METRICS_WINDOW void ImGui::ShowMetricsWindow(bool* p_open) { if (!ImGui::Begin("Dear ImGui Metrics", p_open)) @@ -9943,10 +9944,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count }; + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Contents, WRT_ContentsRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" }; + static bool show_windows_begin_order = false; static bool show_windows_rects = false; - static int show_windows_rect_type = RT_WorkRect; + static int show_windows_rect_type = WRT_WorkRect; static bool show_drawcmd_clip_rects = true; ImGuiIO& io = ImGui::GetIO(); @@ -9959,15 +9962,15 @@ void ImGui::ShowMetricsWindow(bool* p_open) struct Funcs { - static ImRect GetRect(ImGuiWindow* window, int rect_type) + static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) { - if (rect_type == RT_OuterRect) { return window->Rect(); } - else if (rect_type == RT_OuterRectClipped) { return window->OuterRectClipped; } - else if (rect_type == RT_InnerRect) { return window->InnerRect; } - else if (rect_type == RT_InnerClipRect) { return window->InnerClipRect; } - else if (rect_type == RT_WorkRect) { return window->WorkRect; } - else if (rect_type == RT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } - else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; } + if (rect_type == WRT_OuterRect) { return window->Rect(); } + else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } + else if (rect_type == WRT_InnerRect) { return window->InnerRect; } + else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == WRT_WorkRect) { return window->WorkRect; } + else if (rect_type == WRT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentsRegionRect) { return window->ContentsRegionRect; } IM_ASSERT(0); return ImRect(); } @@ -10174,16 +10177,15 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Checkbox("Show windows rectangles", &show_windows_rects); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); - const char* rects_names[RT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" }; - show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, rects_names, RT_Count); + show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count); if (show_windows_rects && g.NavWindow) { ImGui::BulletText("'%s':", g.NavWindow->Name); ImGui::Indent(); - for (int n = 0; n < RT_Count; n++) + for (int rect_n = 0; rect_n < WRT_Count; rect_n++) { - ImRect r = Funcs::GetRect(g.NavWindow, n); - ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), rects_names[n]); + ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); + ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); } ImGui::Unindent(); } @@ -10201,7 +10203,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImDrawList* draw_list = GetForegroundDrawList(window); if (show_windows_rects) { - ImRect r = Funcs::GetRect(window, show_windows_rect_type); + ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); } if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow)) @@ -10216,6 +10218,11 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::End(); } +#else +void ImGui::ShowMetricsWindow(bool*) +{ +} +#endif //----------------------------------------------------------------------------- From e16564e67a2e88d4cbe3afa6594650712790fba3 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 Jul 2019 20:57:15 +0200 Subject: [PATCH 13/14] Scrollbar: Avoid overlapping the opposite side when window (often a child window) is forcibly too small. --- docs/CHANGELOG.txt | 1 + imgui_demo.cpp | 4 ++-- imgui_widgets.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3eaed626..d8e96b4c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,7 @@ Breaking Changes: Other Changes: - Window: Fixed InnerClipRect right-most coordinates using wrong padding setting (introduced in 1.71). +- Scrollbar: Avoid overlapping the opposite side when window (often a child window) is forcibly too small. - Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). - Scrolling: Added SetScrollHereX(), SetScrollFromPosX() for completeness. (#1580) [@kevreco] diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8d9337a5..a8d72f2e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2079,8 +2079,8 @@ static void ShowDemoWindowLayout() ImGuiStyle& style = ImGui::GetStyle(); float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; - if (child_w < 20.0f) - child_w = 20.0f; + if (child_w < 1.0f) + child_w = 1.0f; ImGui::PushID("##VerticalScrolling"); for (int i = 0; i < 5; i++) { diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a5959c23..8af935c5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -895,13 +895,13 @@ void ImGui::Scrollbar(ImGuiAxis axis) ImRect bb; if (axis == ImGuiAxis_X) { - bb.Min = ImVec2(inner_rect.Min.x, outer_rect.Max.y - border_size - scrollbar_size); + bb.Min = ImVec2(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size)); bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y); rounding_corners |= ImDrawCornerFlags_BotLeft; } else { - bb.Min = ImVec2(outer_rect.Max.x - border_size - scrollbar_size, inner_rect.Min.y); + bb.Min = ImVec2(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y); bb.Max = ImVec2(outer_rect.Max.x, window->InnerRect.Max.y); rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; } From 54c49b5fb1371626f92853a2658cfe2d51d2e41d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 2 Jul 2019 18:28:53 +0200 Subject: [PATCH 14/14] Window: Mouse wheel scrolling while hovering a child window is automatically forwarded to parent window if ScrollMax is zero on the scrolling axis. Also still case if ImGuiWindowFlags_NoScrollWithMouse is set (not new), but previously the forwarding would be disabled if ImGuiWindowFlags_NoScrollbar was set on the child window, which is not the case any more (amend #1502, #1380). --- docs/CHANGELOG.txt | 5 +++++ imgui.cpp | 49 +++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d8e96b4c..331e9005 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,11 @@ Breaking Changes: Other Changes: - Window: Fixed InnerClipRect right-most coordinates using wrong padding setting (introduced in 1.71). +- Window: Mouse wheel scrolling while hovering a child window is automatically forwarded to parent window + if ScrollMax is zero on the scrolling axis. + Also still case if ImGuiWindowFlags_NoScrollWithMouse is set (not new), but previously the forwarding + would be disabled if ImGuiWindowFlags_NoScrollbar was set on the child window, which is not the case + any more. Forwarding can still be disabled by setting ImGuiWindowFlags_NoInputs. (amend #1502, #1380). - Scrollbar: Avoid overlapping the opposite side when window (often a child window) is forcibly too small. - Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d). diff --git a/imgui.cpp b/imgui.cpp index f5602651..4d7ff311 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3449,12 +3449,12 @@ void ImGui::UpdateMouseWheel() return; if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) return; - ImGuiWindow* window = g.HoveredWindow; // Zoom / Scale window // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. - if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling && !window->Collapsed) + if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling && !g.HoveredWindow->Collapsed) { + ImGuiWindow* window = g.HoveredWindow; const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); const float scale = new_font_scale / window->FontWindowScale; window->FontWindowScale = new_font_scale; @@ -3469,31 +3469,36 @@ void ImGui::UpdateMouseWheel() } // Mouse wheel scrolling - // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set). - while ((window->Flags & ImGuiWindowFlags_ChildWindow) && (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs) && window->ParentWindow) - window = window->ParentWindow; - const bool scroll_allowed = !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs); - if (scroll_allowed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f) && !g.IO.KeyCtrl) + // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent + // FIXME: Lock scrolling window while not moving (see #2604) + + // Vertical Mouse Wheel scrolling + const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_y != 0.0f && !g.IO.KeyCtrl) { - ImVec2 max_step = window->InnerRect.GetSize() * 0.67f; - - // Vertical Mouse Wheel Scrolling (hold Shift to scroll horizontally) - if (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) + ImGuiWindow* window = g.HoveredWindow; + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) { - float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step.y)); - SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * scroll_step); - } - else if (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) - { - float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x)); - SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheel * scroll_step); + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetWindowScrollY(window, window->Scroll.y - wheel_y * scroll_step); } + } - // Horizontal Mouse Wheel Scrolling (for hardware that supports it) - if (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) + // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held + const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_x != 0.0f && !g.IO.KeyCtrl) + { + ImGuiWindow* window = g.HoveredWindow; + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) { - float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x)); - SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_step); + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetWindowScrollX(window, window->Scroll.x - wheel_x * scroll_step); } } }