From 14f575ff76839b88e2d32cc3261cf7a616438dd5 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 May 2018 14:02:28 +0200 Subject: [PATCH] Scrolling: Fixed a case where using SetScrollHere(1.0f) at the bottom of a window on the same frame the window height has been growing would have the scroll clamped using the previous height. (#1804) --- CHANGELOG.txt | 1 + imgui.cpp | 33 +++++++++++++++++++-------------- imgui_demo.cpp | 8 ++++---- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c3e12a03..3b0f5902 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -55,6 +55,7 @@ Other Changes: - Settings: Fixed saving an empty .ini file if CreateContext/DestroyContext are called without a single call to NewFrame(). (#1741) - Settings: Added LoadIniSettingsFromDisk(), LoadIniSettingsFromMemory(), SaveIniSettingsToDisk(), SaveIniSettingsToMemory() to manually load/save .ini settings. (#923, #993) - Settings: Added io.WantSaveIniSettings flag, which is set to notify the application that e.g. SaveIniSettingsToMemory() should be called. (#923, #993) +- Scrolling: Fixed a case where using SetScrollHere(1.0f) at the bottom of a window on the same frame the window height has been growing would have the scroll clamped using the previous height. (#1804) - MenuBar: Made BeginMainMenuBar() honor style.DisplaySafeAreaPadding so the text can be made visible on TV settings that don't display all pixels. (#1439) [@dougbinks] - InputText: On Mac OS X, filter out characters when the CMD modifier is held. (#1747) [@sivu] - InputText: On Mac OS X, support CMD+SHIFT+Z for Redo. CMD+Y is also supported as major apps seems to default to support both. (#1765) [@lfnoise] diff --git a/imgui.cpp b/imgui.cpp index bd71db23..5c4ba80f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -725,7 +725,7 @@ static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, static ImGuiWindow* FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); static void CheckStacksSize(ImGuiWindow* window, bool write); -static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); static void AddWindowToDrawData(ImVector* out_list, ImGuiWindow* window); @@ -2996,8 +2996,8 @@ static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_ window->ScrollTargetCenterRatio.y = 1.0f; } - // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately (under this block) - ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately after in NavUpdate() + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false); item_rect_rel.Translate(window->Scroll - next_scroll); } @@ -5503,15 +5503,26 @@ static float GetScrollMaxY(ImGuiWindow* window) return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y)); } -static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) { + ImGuiContext& g = *GImGui; ImVec2 scroll = window->Scroll; - float cr_x = window->ScrollTargetCenterRatio.x; - float cr_y = window->ScrollTargetCenterRatio.y; if (window->ScrollTarget.x < FLT_MAX) + { + float cr_x = window->ScrollTargetCenterRatio.x; scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); + } if (window->ScrollTarget.y < FLT_MAX) - scroll.y = window->ScrollTarget.y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); + { + // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding. + float cr_y = window->ScrollTargetCenterRatio.y; + float target_y = window->ScrollTarget.y; + if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) + target_y = 0.0f; + if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y) + target_y = window->SizeContents.y; + scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); + } scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); if (!window->Collapsed && !window->SkipItems) { @@ -5965,7 +5976,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX; // Apply scrolling - window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); // Apply focus, new windows appears in front @@ -7292,12 +7303,6 @@ void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio) IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y); window->ScrollTargetCenterRatio.y = center_y_ratio; - - // Minor hack to to make scrolling to top/bottom of window take account of WindowPadding, it looks more right to the user this way - if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y) - window->ScrollTarget.y = 0.0f; - else if (center_y_ratio >= 1.0f && window->ScrollTarget.y >= window->SizeContents.y - window->WindowPadding.y + GImGui->Style.ItemSpacing.y) - window->ScrollTarget.y = window->SizeContents.y; } // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2960d371..ec6b8747 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2656,7 +2656,7 @@ struct ExampleAppConsole Commands.push_back("HISTORY"); Commands.push_back("CLEAR"); Commands.push_back("CLASSIFY"); // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches. - AddLog("Welcome to ImGui!"); + AddLog("Welcome to Dear ImGui!"); } ~ExampleAppConsole() { @@ -2669,6 +2669,7 @@ struct ExampleAppConsole static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } + static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } void ClearLog() { @@ -2767,7 +2768,7 @@ struct ExampleAppConsole if (copy_to_clipboard) ImGui::LogFinish(); if (ScrollToBottom) - ImGui::SetScrollHere(); + ImGui::SetScrollHere(1.0f); ScrollToBottom = false; ImGui::PopStyleVar(); ImGui::EndChild(); @@ -2777,8 +2778,7 @@ struct ExampleAppConsole bool reclaim_focus = false; if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) { - char* input_end = InputBuf+strlen(InputBuf); - while (input_end > InputBuf && input_end[-1] == ' ') { input_end--; } *input_end = 0; + Strtrim(InputBuf); if (InputBuf[0]) ExecCommand(InputBuf); strcpy(InputBuf, "");