mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-04 12:08:47 +02:00
Scrolling, Nav: Fixed programmatic scroll leading to a slightly incorrect scroll offset when the window has decorations or a menu-bar (broken in 1.71). This was mostly noticeable when a keyboard/gamepad movement led to scrolling the view, or using e.g. SetScrollHereY() function. Fix/amend a0994d74
.
This commit is contained in:
56
imgui.cpp
56
imgui.cpp
@ -5692,7 +5692,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
// Inner rectangle
|
||||
// Not affected by window border size. Used by:
|
||||
// - InnerClipRect
|
||||
// - NavScrollToBringItemIntoView()
|
||||
// - ScrollToBringRectIntoView()
|
||||
// - NavUpdatePageUpPageDown()
|
||||
// - Scrollbar()
|
||||
window->InnerRect.Min.x = window->Pos.x;
|
||||
@ -7141,18 +7141,19 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
|
||||
target_x = 0.0f;
|
||||
else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + g.Style.ItemSpacing.x)
|
||||
target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f;
|
||||
scroll.x = target_x - cr_x * window->InnerRect.GetWidth();
|
||||
scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
|
||||
}
|
||||
if (window->ScrollTarget.y < FLT_MAX)
|
||||
{
|
||||
// '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 decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
|
||||
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->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y)
|
||||
target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f;
|
||||
scroll.y = target_y - cr_y * window->InnerRect.GetHeight();
|
||||
scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
|
||||
}
|
||||
scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
|
||||
if (!window->Collapsed && !window->SkipItems)
|
||||
@ -7164,7 +7165,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
|
||||
}
|
||||
|
||||
// Scroll to keep newly navigated item fully into view
|
||||
void ImGui::ScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect)
|
||||
void ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
|
||||
{
|
||||
ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
|
||||
//GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
|
||||
@ -7173,25 +7174,13 @@ void ImGui::ScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_re
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
|
||||
{
|
||||
window->ScrollTarget.x = item_rect.Min.x - window->Pos.x + window->Scroll.x - g.Style.ItemSpacing.x;
|
||||
window->ScrollTargetCenterRatio.x = 0.0f;
|
||||
}
|
||||
SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f);
|
||||
else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
|
||||
{
|
||||
window->ScrollTarget.x = item_rect.Max.x - window->Pos.x + window->Scroll.x + g.Style.ItemSpacing.x;
|
||||
window->ScrollTargetCenterRatio.x = 1.0f;
|
||||
}
|
||||
SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
|
||||
if (item_rect.Min.y < window_rect.Min.y)
|
||||
{
|
||||
window->ScrollTarget.y = item_rect.Min.y - window->Pos.y + window->Scroll.y - g.Style.ItemSpacing.y;
|
||||
window->ScrollTargetCenterRatio.y = 0.0f;
|
||||
}
|
||||
SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
|
||||
else if (item_rect.Max.y >= window_rect.Max.y)
|
||||
{
|
||||
window->ScrollTarget.y = item_rect.Max.y - window->Pos.y + window->Scroll.y + g.Style.ItemSpacing.y;
|
||||
window->ScrollTargetCenterRatio.y = 1.0f;
|
||||
}
|
||||
SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
|
||||
}
|
||||
|
||||
float ImGui::GetScrollX()
|
||||
@ -7244,26 +7233,37 @@ void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y)
|
||||
window->ScrollTargetCenterRatio.y = 0.0f;
|
||||
}
|
||||
|
||||
void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
|
||||
|
||||
void ImGui::SetScrollFromPosX(ImGuiWindow* window, 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
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
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;
|
||||
}
|
||||
|
||||
void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
|
||||
void ImGui::SetScrollFromPosY(ImGuiWindow* window, 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
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
|
||||
const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
|
||||
local_y -= decoration_up_height;
|
||||
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)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
|
||||
}
|
||||
|
||||
void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetScrollFromPosY(g.CurrentWindow, local_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)
|
||||
{
|
||||
@ -8484,7 +8484,7 @@ static void ImGui::NavUpdateMoveResult()
|
||||
if (g.NavLayer == 0)
|
||||
{
|
||||
ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
|
||||
ScrollToBringItemIntoView(result->Window, rect_abs);
|
||||
ScrollToBringRectIntoView(result->Window, rect_abs);
|
||||
|
||||
// Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate()
|
||||
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false);
|
||||
@ -8493,7 +8493,7 @@ static void ImGui::NavUpdateMoveResult()
|
||||
|
||||
// Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy).
|
||||
if (result->Window->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
ScrollToBringItemIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll));
|
||||
ScrollToBringRectIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll));
|
||||
}
|
||||
|
||||
ClearActiveID();
|
||||
|
Reference in New Issue
Block a user