diff --git a/src/spice2x/overlay/windows/config.cpp b/src/spice2x/overlay/windows/config.cpp index b8eb143..ab716a7 100644 --- a/src/spice2x/overlay/windows/config.cpp +++ b/src/spice2x/overlay/windows/config.cpp @@ -406,19 +406,18 @@ namespace overlay::windows { // content: only the options belonging to the selected group. ImGui::BeginChild("OptionsContent", ImVec2(0, content_height), false); - if (this->options_scroll_top) { - ImGui::SetScrollY(0.0f); - this->options_scroll_top = false; - } + + const bool scroll_to_top = this->options_scroll_top; + this->options_scroll_top = false; + float scroll_to_category_y = -1.0f; // breathing room at the top of the content area ImGui::Dummy(ImVec2(0.0f, overlay::apply_scaling(4))); - // when a category was clicked in the nav, scroll the content to its section - auto scroll_anchor = [this](const std::string &category) { + // when a category was clicked in the nav, record its Y for deferred scroll + auto scroll_anchor = [this, &scroll_to_category_y](const std::string &category) { if (this->options_scroll_pending && this->options_category_selected == category) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - ImGui::SetScrollHereY(0.0f); + scroll_to_category_y = ImGui::GetCursorPosY(); this->options_scroll_pending = false; } }; @@ -474,6 +473,23 @@ namespace overlay::windows { } } + // apply scroll after content layout to avoid mid-layout jitter + ImGuiWindow *content_window = ImGui::GetCurrentWindow(); + if (scroll_to_top) { + if (content_window->Scroll.y > 0.0f) { + content_window->Scroll.y = 0.0f; + } + content_window->ScrollTarget.y = FLT_MAX; + } else if (scroll_to_category_y >= 0.0f) { + const float spacing_y = ImMax( + content_window->WindowPadding.y, ImGui::GetStyle().ItemSpacing.y); + const float desired_scroll = ImMax(0.0f, scroll_to_category_y - spacing_y); + if (fabsf(content_window->Scroll.y - desired_scroll) > 0.5f) { + content_window->Scroll.y = desired_scroll; + } + content_window->ScrollTarget.y = FLT_MAX; + } + ImGui::EndChild(); }