diff --git a/src/generic/scrlwing.cpp b/src/generic/scrlwing.cpp index 74fa136eb4..38ad09a5fd 100644 --- a/src/generic/scrlwing.cpp +++ b/src/generic/scrlwing.cpp @@ -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 diff --git a/src/gtk/scrolwin.cpp b/src/gtk/scrolwin.cpp index 65918be366..1a6e941bb7 100644 --- a/src/gtk/scrolwin.cpp +++ b/src/gtk/scrolwin.cpp @@ -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; } diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp index c063fe6ed2..3e52956058 100644 --- a/tests/controls/windowtest.cpp +++ b/tests/controls/windowtest.cpp @@ -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 + 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")