Respect disabled physical scrolling in Scroll

Make wxScrollHelper::DoScroll() use ScrollWindow() only for axes whose
physical scrolling is enabled. Disabled axes still update their logical
scroll position and invalidate the target window so it repaints.

Add a regression test covering fully disabled physical scrolling and a
mixed horizontal-enabled, vertical-disabled scroll.

This commit is best viewed ignoring whitespace-only changes.

Fixes #4433.

Closes #26900.
This commit is contained in:
Richard
2026-09-04 15:10:24 +02:00
committed by Vadim Zeitlin
parent 6cb5a785ad
commit 5daf1beb9c
3 changed files with 117 additions and 10 deletions
+33 -7
View File
@@ -1587,29 +1587,55 @@ void wxScrollHelper::DoScroll( int x_pos, int y_pos )
if ( new_x == m_xScrollPosition && new_y == m_yScrollPosition )
return; // nothing to do, the position didn't change
const bool scrollX = m_xScrollPosition != new_x;
const bool scrollY = m_yScrollPosition != new_y;
const bool scrollWindow =
(scrollX && m_xScrollingEnabled) ||
(scrollY && m_yScrollingEnabled);
// flush all pending repaints before we change m_{x,y}ScrollPosition, as
// otherwise invalidated area could be updated incorrectly later when
// ScrollWindow() makes sure they're repainted before scrolling them
m_targetWindow->Update();
if ( scrollWindow )
m_targetWindow->Update();
bool needsRefresh = false;
// update the position and scroll the window now:
if (m_xScrollPosition != new_x)
if ( scrollX )
{
int old_x = m_xScrollPosition;
m_xScrollPosition = new_x;
m_win->SetScrollPos( wxHORIZONTAL, new_x );
m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0,
GetScrollRect() );
if ( m_xScrollingEnabled )
{
m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0,
GetScrollRect() );
}
else
{
needsRefresh = true;
}
}
if (m_yScrollPosition != new_y)
if ( scrollY )
{
int old_y = m_yScrollPosition;
m_yScrollPosition = new_y;
m_win->SetScrollPos( wxVERTICAL, new_y );
m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine,
GetScrollRect() );
if ( m_yScrollingEnabled )
{
m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine,
GetScrollRect() );
}
else
{
needsRefresh = true;
}
}
if ( needsRefresh )
m_targetWindow->Refresh(true, GetScrollRect());
}
#endif // wxHAS_GENERIC_SCROLLWIN
+14 -3
View File
@@ -147,9 +147,20 @@ void wxScrollHelper::DoScrollOneDir(int orient,
m_win->SetScrollPos(orient, pos);
pos = m_win->GetScrollPos(orient);
int diff = (*posOld - pos)*pixelsPerLine;
m_targetWindow->ScrollWindow(orient == wxHORIZONTAL ? diff : 0,
orient == wxHORIZONTAL ? 0 : diff);
const bool scrollingEnabled =
orient == wxHORIZONTAL ? m_xScrollingEnabled : m_yScrollingEnabled;
if ( scrollingEnabled )
{
int diff = (*posOld - pos)*pixelsPerLine;
m_targetWindow->ScrollWindow(orient == wxHORIZONTAL ? diff : 0,
orient == wxHORIZONTAL ? 0 : diff);
}
else
{
// Logical scrolling still changes the view position; only the
// physical move of the pixels is disabled.
m_targetWindow->Refresh(true, GetScrollRect());
}
*posOld = pos;
}
+70
View File
@@ -30,6 +30,10 @@
#include "wx/tooltip.h"
#include "wx/wupdlock.h"
#if wxUSE_SCROLLBAR
#include "wx/scrolwin.h"
#endif // wxUSE_SCROLLBAR
#ifdef __WXGTK__
#include "wx/gtk/private/backend.h"
#endif // __WXGTK__
@@ -132,6 +136,45 @@ private:
};
#endif // wxUSE_HELP
#if wxUSE_SCROLLBAR
class ScrollCountingWindow : public wxScrolledWindow
{
public:
ScrollCountingWindow(wxWindow* parent)
: wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(100, 100))
{
SetScrollRate(10, 10);
SetVirtualSize(1000, 1000);
ResetScrollWindowCalls();
}
virtual void ScrollWindow(int dx, int dy,
const wxRect* rect = nullptr) override
{
wxUnusedVar(rect);
m_scrollWindowCallCount++;
m_lastScrollWindowDelta = wxPoint(dx, dy);
}
void ResetScrollWindowCalls()
{
m_scrollWindowCallCount = 0;
m_lastScrollWindowDelta = wxPoint();
}
int GetScrollWindowCallCount() const { return m_scrollWindowCallCount; }
wxPoint GetLastScrollWindowDelta() const { return m_lastScrollWindowDelta; }
private:
int m_scrollWindowCallCount = 0;
wxPoint m_lastScrollWindowDelta;
};
#endif // wxUSE_SCROLLBAR
static void DoTestShowHideEvent(wxWindow* window)
{
EventCounter show(window, wxEVT_SHOW);
@@ -149,6 +192,33 @@ static void DoTestShowHideEvent(wxWindow* window)
CHECK( show.GetCount() == 2 );
}
#if wxUSE_SCROLLBAR
TEST_CASE_METHOD(WindowTestCase, "Window::ScrolledWindowPhysicalScrolling",
"[window][scroll]")
{
std::unique_ptr<ScrollCountingWindow>
win(new ScrollCountingWindow(wxTheApp->GetTopWindow()));
win->EnableScrolling(false, false);
win->Scroll(1, 2);
CHECK( win->GetViewStart() == wxPoint(1, 2) );
CHECK( win->GetScrollWindowCallCount() == 0 );
win->Scroll(0, 0);
win->EnableScrolling(true, false);
win->ResetScrollWindowCalls();
win->Scroll(1, 2);
CHECK( win->GetViewStart() == wxPoint(1, 2) );
REQUIRE( win->GetScrollWindowCallCount() == 1 );
CHECK( win->GetLastScrollWindowDelta() == wxPoint(-10, 0) );
}
#endif // wxUSE_SCROLLBAR
TEST_CASE_METHOD(WindowTestCase, "Window::ShowHideEvent", "[window]")
{
SECTION("Normal window")