mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-04 15:11:05 +01: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:
		@@ -33,6 +33,12 @@ HOW TO UPDATE?
 | 
			
		||||
 VERSION 1.73 (In Progress)
 | 
			
		||||
-----------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Other Changes:
 | 
			
		||||
 | 
			
		||||
- 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------
 | 
			
		||||
 VERSION 1.72 (Released 2019-07-27)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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();
 | 
			
		||||
 
 | 
			
		||||
@@ -2066,8 +2066,14 @@ static void ShowDemoWindowLayout()
 | 
			
		||||
 | 
			
		||||
        static int track_item = 50;
 | 
			
		||||
        static bool enable_track = true;
 | 
			
		||||
        static bool enable_extra_decorations = false;
 | 
			
		||||
        static float scroll_to_off_px = 0.0f;
 | 
			
		||||
        static float scroll_to_pos_px = 200.0f;
 | 
			
		||||
 | 
			
		||||
        ImGui::Checkbox("Decoration", &enable_extra_decorations);
 | 
			
		||||
        ImGui::SameLine();
 | 
			
		||||
        HelpMarker("We expose this for testing because scrolling sometimes had issues with window decoration such as menu-bars.");
 | 
			
		||||
 | 
			
		||||
        ImGui::Checkbox("Track", &enable_track);
 | 
			
		||||
        ImGui::PushItemWidth(100);
 | 
			
		||||
        ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
 | 
			
		||||
@@ -2076,7 +2082,7 @@ static void ShowDemoWindowLayout()
 | 
			
		||||
        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", &scroll_to_pos_px, 1.00f, 0, 9999, "X/Y = %.0f px");
 | 
			
		||||
        ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, 9999, "X/Y = %.0f px");
 | 
			
		||||
        ImGui::PopItemWidth();
 | 
			
		||||
 | 
			
		||||
        if (scroll_to_off || scroll_to_pos)
 | 
			
		||||
@@ -2094,7 +2100,13 @@ static void ShowDemoWindowLayout()
 | 
			
		||||
            const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
 | 
			
		||||
            ImGui::TextUnformatted(names[i]);
 | 
			
		||||
 | 
			
		||||
            ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, ImGuiWindowFlags_None);
 | 
			
		||||
            ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
 | 
			
		||||
            ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags);
 | 
			
		||||
            if (ImGui::BeginMenuBar())
 | 
			
		||||
            {
 | 
			
		||||
                ImGui::TextUnformatted("abc");
 | 
			
		||||
                ImGui::EndMenuBar();
 | 
			
		||||
            }
 | 
			
		||||
            if (scroll_to_off)
 | 
			
		||||
                ImGui::SetScrollY(scroll_to_off_px);
 | 
			
		||||
            if (scroll_to_pos)
 | 
			
		||||
@@ -2126,7 +2138,8 @@ static void ShowDemoWindowLayout()
 | 
			
		||||
        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);
 | 
			
		||||
            ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
 | 
			
		||||
            ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags);
 | 
			
		||||
            if (scroll_to_off)
 | 
			
		||||
                ImGui::SetScrollX(scroll_to_off_px);
 | 
			
		||||
            if (scroll_to_pos)
 | 
			
		||||
 
 | 
			
		||||
@@ -1499,7 +1499,9 @@ namespace ImGui
 | 
			
		||||
    // Scrolling
 | 
			
		||||
    IMGUI_API void          SetScrollX(ImGuiWindow* window, float new_scroll_x);
 | 
			
		||||
    IMGUI_API void          SetScrollY(ImGuiWindow* window, float new_scroll_y);
 | 
			
		||||
    IMGUI_API void          ScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect);
 | 
			
		||||
    IMGUI_API void          SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f);
 | 
			
		||||
    IMGUI_API void          SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f);
 | 
			
		||||
    IMGUI_API void          ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
 | 
			
		||||
 | 
			
		||||
    // Basic Accessors
 | 
			
		||||
    inline ImGuiID          GetItemID()     { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user