X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4bc6f7a06c494917409bbb673526f090bc51d2d2..64c70359a7ca399f47a07369f42818fc7949fac4:/src/generic/vscroll.cpp diff --git a/src/generic/vscroll.cpp b/src/generic/vscroll.cpp index d3eb9a3e5f..c1b5a4071a 100644 --- a/src/generic/vscroll.cpp +++ b/src/generic/vscroll.cpp @@ -2,7 +2,7 @@ // Name: src/generic/vscroll.cpp // Purpose: wxVScrolledWindow implementation // Author: Vadim Zeitlin -// Modified by: Brad Anderson +// Modified by: Brad Anderson, David Warkentin // Created: 30.05.03 // RCS-ID: $Id$ // Copyright: (c) 2003 Vadim Zeitlin @@ -24,350 +24,640 @@ #pragma hdrstop #endif +#ifndef WX_PRECOMP + #include "wx/dc.h" + #include "wx/sizer.h" +#endif + #include "wx/vscroll.h" -#include "wx/sizer.h" -#include "wx/dc.h" + +// ============================================================================ +// wxVarScrollHelperEvtHandler declaration +// ============================================================================ // ---------------------------------------------------------------------------- -// event tables +// wxScrollHelperEvtHandler: intercept the events from the window and forward +// them to wxVarScrollHelperBase // ---------------------------------------------------------------------------- -BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel) - EVT_SIZE(wxVScrolledWindow::OnSize) - EVT_SCROLLWIN(wxVScrolledWindow::OnScroll) -#if wxUSE_MOUSEWHEEL - EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel) -#endif -END_EVENT_TABLE() +class WXDLLEXPORT wxVarScrollHelperEvtHandler : public wxEvtHandler +{ +public: + wxVarScrollHelperEvtHandler(wxVarScrollHelperBase *scrollHelper) + { + m_scrollHelper = scrollHelper; + } + + virtual bool ProcessEvent(wxEvent& event); + +private: + wxVarScrollHelperBase *m_scrollHelper; + wxDECLARE_NO_COPY_CLASS(wxVarScrollHelperEvtHandler); +}; // ============================================================================ -// implementation +// wxVarScrollHelperEvtHandler implementation // ============================================================================ -IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel) +bool wxVarScrollHelperEvtHandler::ProcessEvent(wxEvent& event) +{ + wxEventType evType = event.GetEventType(); + + // pass it on to the real handler + bool processed = wxEvtHandler::ProcessEvent(event); + + // always process the size events ourselves, even if the user code handles + // them as well, as we need to AdjustScrollbars() + // + // NB: it is important to do it after processing the event in the normal + // way as HandleOnSize() may generate a wxEVT_SIZE itself if the + // scrollbar[s] (dis)appear and it should be seen by the user code + // after this one + if ( evType == wxEVT_SIZE ) + { + m_scrollHelper->HandleOnSize((wxSizeEvent &)event); + + return !event.GetSkipped(); + } + + if ( processed ) + { + // normally, nothing more to do here - except if we have a command + // event + if ( event.IsCommandEvent() ) + { + return true; + } + } + + // reset the skipped flag (which might have been set to true in + // ProcessEvent() above) to be able to test it below + bool wasSkipped = event.GetSkipped(); + if ( wasSkipped ) + event.Skip(false); + + if ( evType == wxEVT_SCROLLWIN_TOP || + evType == wxEVT_SCROLLWIN_BOTTOM || + evType == wxEVT_SCROLLWIN_LINEUP || + evType == wxEVT_SCROLLWIN_LINEDOWN || + evType == wxEVT_SCROLLWIN_PAGEUP || + evType == wxEVT_SCROLLWIN_PAGEDOWN || + evType == wxEVT_SCROLLWIN_THUMBTRACK || + evType == wxEVT_SCROLLWIN_THUMBRELEASE ) + { + m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event); + if ( !event.GetSkipped() ) + { + // it makes sense to indicate that we processed the message as we + // did scroll the window (and also notice that wxAutoScrollTimer + // relies on our return value for continuous scrolling) + processed = true; + wasSkipped = false; + } + } +#if wxUSE_MOUSEWHEEL + else if ( evType == wxEVT_MOUSEWHEEL ) + { + m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event); + } +#endif // wxUSE_MOUSEWHEEL + + event.Skip(wasSkipped); + + return processed; +} + + +// ============================================================================ +// wxVarScrollHelperBase implementation +// ============================================================================ // ---------------------------------------------------------------------------- -// initialization +// wxVarScrollHelperBase initialization // ---------------------------------------------------------------------------- -void wxVScrolledWindow::Init() +wxVarScrollHelperBase::wxVarScrollHelperBase(wxWindow *win) { - // we're initially empty - m_lineMax = - m_lineFirst = 0; - - // this one should always be strictly positive - m_nVisible = 1; - - m_heightTotal = 0; + wxASSERT_MSG( win, wxT("associated window can't be NULL in wxVarScrollHelperBase") ); #if wxUSE_MOUSEWHEEL m_sumWheelRotation = 0; #endif + + m_unitMax = 0; + m_sizeTotal = 0; + m_unitFirst = 0; + + m_win = + m_targetWindow = NULL; + + m_physicalScrolling = true; + m_handler = NULL; + + m_win = win; + + // by default, the associated window is also the target window + DoSetTargetWindow(win); + +} + +wxVarScrollHelperBase::~wxVarScrollHelperBase() +{ + DeleteEvtHandler(); } // ---------------------------------------------------------------------------- -// various helpers +// wxVarScrollHelperBase various helpers // ---------------------------------------------------------------------------- -wxCoord wxVScrolledWindow::EstimateTotalHeight() const +void +wxVarScrollHelperBase::AssignOrient(wxCoord& x, + wxCoord& y, + wxCoord first, + wxCoord second) +{ + if ( GetOrientation() == wxVERTICAL ) + { + x = first; + y = second; + } + else // horizontal + { + x = second; + y = first; + } +} + +void +wxVarScrollHelperBase::IncOrient(wxCoord& x, wxCoord& y, wxCoord inc) +{ + if ( GetOrientation() == wxVERTICAL ) + y += inc; + else + x += inc; +} + +wxCoord wxVarScrollHelperBase::DoEstimateTotalSize() const { // estimate the total height: it is impossible to call - // OnGetLineHeight() for every line because there may be too many of - // them, so we just make a guess using some lines in the beginning, + // OnGetUnitSize() for every unit because there may be too many of + // them, so we just make a guess using some units in the beginning, // some in the end and some in the middle - static const size_t NUM_LINES_TO_SAMPLE = 10; + static const size_t NUM_UNITS_TO_SAMPLE = 10; - wxCoord heightTotal; - if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE ) + wxCoord sizeTotal; + if ( m_unitMax < 3*NUM_UNITS_TO_SAMPLE ) { - // in this case calculating exactly is faster and more correct than + // in this case, full calculations are faster and more correct than // guessing - heightTotal = GetLinesHeight(0, m_lineMax); + sizeTotal = GetUnitsSize(0, m_unitMax); } - else // too many lines to calculate exactly + else // too many units to calculate exactly { - // look at some lines in the beginning/middle/end - heightTotal = - GetLinesHeight(0, NUM_LINES_TO_SAMPLE) + - GetLinesHeight(m_lineMax - NUM_LINES_TO_SAMPLE, m_lineMax) + - GetLinesHeight(m_lineMax/2 - NUM_LINES_TO_SAMPLE/2, - m_lineMax/2 + NUM_LINES_TO_SAMPLE/2); - - // use the height of the lines we looked as the average - heightTotal = (wxCoord) - (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_lineMax); + // look at some units in the beginning/middle/end + sizeTotal = + GetUnitsSize(0, NUM_UNITS_TO_SAMPLE) + + GetUnitsSize(m_unitMax - NUM_UNITS_TO_SAMPLE, + m_unitMax) + + GetUnitsSize(m_unitMax/2 - NUM_UNITS_TO_SAMPLE/2, + m_unitMax/2 + NUM_UNITS_TO_SAMPLE/2); + + // use the height of the units we looked as the average + sizeTotal = (wxCoord) + (((float)sizeTotal / (3*NUM_UNITS_TO_SAMPLE)) * m_unitMax); } - return heightTotal; + return sizeTotal; } -wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const +wxCoord wxVarScrollHelperBase::GetUnitsSize(size_t unitMin, size_t unitMax) const { - if ( lineMin == lineMax ) + if ( unitMin == unitMax ) return 0; - else if ( lineMin > lineMax ) - return -GetLinesHeight(lineMax, lineMin); - //else: lineMin < lineMax + else if ( unitMin > unitMax ) + return -GetUnitsSize(unitMax, unitMin); + //else: unitMin < unitMax - // let the user code know that we're going to need all these lines - OnGetLinesHint(lineMin, lineMax); + // let the user code know that we're going to need all these units + OnGetUnitsSizeHint(unitMin, unitMax); - // do sum up their heights - wxCoord height = 0; - for ( size_t line = lineMin; line < lineMax; line++ ) + // sum up their sizes + wxCoord size = 0; + for ( size_t unit = unitMin; unit < unitMax; ++unit ) { - height += OnGetLineHeight(line); + size += OnGetUnitSize(unit); } - return height; + return size; } -size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full) +size_t wxVarScrollHelperBase::FindFirstVisibleFromLast(size_t unitLast, bool full) const { - const wxCoord hWindow = GetClientSize().y; + const wxCoord sWindow = GetOrientationTargetSize(); - // go upwards until we arrive at a line such that lineLast is not visible + // go upwards until we arrive at a unit such that unitLast is not visible // any more when it is shown - size_t lineFirst = lineLast; - wxCoord h = 0; + size_t unitFirst = unitLast; + wxCoord s = 0; for ( ;; ) { - h += OnGetLineHeight(lineFirst); + s += OnGetUnitSize(unitFirst); - if ( h > hWindow ) + if ( s > sWindow ) { - // for this line to be fully visible we need to go one line + // for this unit to be fully visible we need to go one unit // down, but if it is enough for it to be only partly visible then - // this line will do as well + // this unit will do as well if ( full ) { - lineFirst++; + ++unitFirst; } break; } - if ( !lineFirst ) + if ( !unitFirst ) break; - lineFirst--; + --unitFirst; } - return lineFirst; + return unitFirst; } -void wxVScrolledWindow::UpdateScrollbar() +size_t wxVarScrollHelperBase::GetNewScrollPosition(wxScrollWinEvent& event) const { - // see how many lines can we fit on screen - const wxCoord hWindow = GetClientSize().y; + wxEventType evtType = event.GetEventType(); - wxCoord h = 0; - size_t line; - for ( line = m_lineFirst; line < m_lineMax; line++ ) + if ( evtType == wxEVT_SCROLLWIN_TOP ) + { + return 0; + } + else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) + { + return m_unitMax; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) + { + return m_unitFirst ? m_unitFirst - 1 : 0; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) + { + return m_unitFirst + 1; + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) + { + return FindFirstVisibleFromLast(m_unitFirst); + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) + { + if ( GetVisibleEnd() ) + return GetVisibleEnd() - 1; + else + return GetVisibleEnd(); + } + else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) + { + return event.GetPosition(); + } + else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) + { + return event.GetPosition(); + } + + // unknown scroll event? + wxFAIL_MSG( wxT("unknown scroll event type?") ); + return 0; +} + +void wxVarScrollHelperBase::UpdateScrollbar() +{ + // if there is nothing to scroll, remove the scrollbar + if ( !m_unitMax ) + { + RemoveScrollbar(); + return; + } + + // see how many units can we fit on screen + const wxCoord sWindow = GetOrientationTargetSize(); + + // do vertical calculations + wxCoord s = 0; + size_t unit; + for ( unit = m_unitFirst; unit < m_unitMax; ++unit ) { - if ( h > hWindow ) + if ( s > sWindow ) break; - h += OnGetLineHeight(line); + s += OnGetUnitSize(unit); } - m_nVisible = line - m_lineFirst; + m_nUnitsVisible = unit - m_unitFirst; - int pageSize = m_nVisible; - if ( h > hWindow ) + int unitsPageSize = m_nUnitsVisible; + if ( s > sWindow ) { - // last line is only partially visible, we still need the scrollbar and - // so we have to "fix" pageSize because if it is equal to m_lineMax the - // scrollbar is not shown at all under MSW - pageSize--; + // last unit is only partially visible, we still need the scrollbar and + // so we have to "fix" pageSize because if it is equal to m_unitMax + // the scrollbar is not shown at all under MSW + --unitsPageSize; } // set the scrollbar parameters to reflect this - SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax); + m_win->SetScrollbar(GetOrientation(), m_unitFirst, unitsPageSize, m_unitMax); +} + +void wxVarScrollHelperBase::RemoveScrollbar() +{ + m_unitFirst = 0; + m_nUnitsVisible = m_unitMax; + m_win->SetScrollbar(GetOrientation(), 0, 0, 0); +} + +void wxVarScrollHelperBase::DeleteEvtHandler() +{ + // search for m_handler in the handler list + if ( m_win && m_handler ) + { + if ( m_win->RemoveEventHandler(m_handler) ) + { + delete m_handler; + } + //else: something is very wrong, so better [maybe] leak memory than + // risk a crash because of double deletion + + m_handler = NULL; + } +} + +void wxVarScrollHelperBase::DoSetTargetWindow(wxWindow *target) +{ + m_targetWindow = target; +#ifdef __WXMAC__ + target->MacSetClipChildren( true ) ; +#endif + + // install the event handler which will intercept the events we're + // interested in (but only do it for our real window, not the target window + // which we scroll - we don't need to hijack its events) + if ( m_targetWindow == m_win ) + { + // if we already have a handler, delete it first + DeleteEvtHandler(); + + m_handler = new wxVarScrollHelperEvtHandler(this); + m_targetWindow->PushEventHandler(m_handler); + } } // ---------------------------------------------------------------------------- -// operations +// wxVarScrollHelperBase operations // ---------------------------------------------------------------------------- -void wxVScrolledWindow::SetLineCount(size_t count) +void wxVarScrollHelperBase::SetTargetWindow(wxWindow *target) +{ + wxCHECK_RET( target, wxT("target window must not be NULL") ); + + if ( target == m_targetWindow ) + return; + + DoSetTargetWindow(target); +} + +void wxVarScrollHelperBase::SetUnitCount(size_t count) { - // save the number of lines - m_lineMax = count; + // save the number of units + m_unitMax = count; // and our estimate for their total height - m_heightTotal = EstimateTotalHeight(); + m_sizeTotal = EstimateTotalSize(); - // recalculate the scrollbars parameters - m_lineFirst = 1; // make sure it is != 0 - ScrollToLine(0); + // ScrollToUnit() will update the scrollbar itself if it changes the unit + // we pass to it because it's out of [new] range + size_t oldScrollPos = m_unitFirst; + DoScrollToUnit(m_unitFirst); + if ( oldScrollPos == m_unitFirst ) + { + // but if it didn't do it, we still need to update the scrollbar to + // reflect the changed number of units ourselves + UpdateScrollbar(); + } } -void wxVScrolledWindow::RefreshLine(size_t line) +void wxVarScrollHelperBase::RefreshUnit(size_t unit) { - // is this line visible? - if ( !IsVisible(line) ) + // is this unit visible? + if ( !IsVisible(unit) ) { // no, it is useless to do anything return; } - // calculate the rect occupied by this line on screen + // calculate the rect occupied by this unit on screen wxRect rect; - rect.width = GetClientSize().x; - rect.height = OnGetLineHeight(line); - for ( size_t n = GetVisibleBegin(); n < line; n++ ) + AssignOrient(rect.width, rect.height, + GetNonOrientationTargetSize(), OnGetUnitSize(unit)); + + for ( size_t n = GetVisibleBegin(); n < unit; ++n ) { - rect.y += OnGetLineHeight(n); + IncOrient(rect.x, rect.y, OnGetUnitSize(n)); } // do refresh it - RefreshRect(rect); + m_targetWindow->RefreshRect(rect); } -void wxVScrolledWindow::RefreshLines(size_t from, size_t to) +void wxVarScrollHelperBase::RefreshUnits(size_t from, size_t to) { - wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") ); + wxASSERT_MSG( from <= to, wxT("RefreshUnits(): empty range") ); - // clump the range to just the visible lines -- it is useless to refresh + // clump the range to just the visible units -- it is useless to refresh // the other ones if ( from < GetVisibleBegin() ) from = GetVisibleBegin(); - if ( to >= GetVisibleEnd() ) + if ( to > GetVisibleEnd() ) to = GetVisibleEnd(); - else - to++; - // calculate the rect occupied by these lines on screen - wxRect rect; - rect.width = GetClientSize().x; - for ( size_t nBefore = GetVisibleBegin(); nBefore < from; nBefore++ ) + // calculate the rect occupied by these units on screen + int orient_size, nonorient_size, orient_pos; + orient_size = nonorient_size = orient_pos = 0; + + nonorient_size = GetNonOrientationTargetSize(); + + for ( size_t nBefore = GetVisibleBegin(); + nBefore < from; + nBefore++ ) { - rect.y += OnGetLineHeight(nBefore); + orient_pos += OnGetUnitSize(nBefore); } - for ( size_t nBetween = from; nBetween < to; nBetween++ ) + for ( size_t nBetween = from; nBetween <= to; nBetween++ ) { - rect.height += OnGetLineHeight(nBetween); + orient_size += OnGetUnitSize(nBetween); } + wxRect rect; + AssignOrient(rect.x, rect.y, 0, orient_pos); + AssignOrient(rect.width, rect.height, nonorient_size, orient_size); + // do refresh it - RefreshRect(rect); + m_targetWindow->RefreshRect(rect); } -void wxVScrolledWindow::RefreshAll() +void wxVarScrollHelperBase::RefreshAll() { UpdateScrollbar(); - Refresh(); + m_targetWindow->Refresh(); } -bool wxVScrolledWindow::Layout() +bool wxVarScrollHelperBase::ScrollLayout() { - if(GetSizer()) + if ( m_targetWindow->GetSizer() && m_physicalScrolling ) { // adjust the sizer dimensions/position taking into account the // virtual size and scrolled position of the window. - int y, w, h; // x is always 0 so no variable needed + int x, y; + AssignOrient(x, y, 0, -GetScrollOffset()); + + int w, h; + m_targetWindow->GetVirtualSize(&w, &h); - y = -GetLinesHeight(0, GetFirstVisibleLine()); - GetVirtualSize(&w, &h); - GetSizer()->SetDimension(0, y, w, h); + m_targetWindow->GetSizer()->SetDimension(x, y, w, h); return true; } // fall back to default for LayoutConstraints - return wxPanel::Layout(); + return m_targetWindow->wxWindow::Layout(); } -int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const +int wxVarScrollHelperBase::VirtualHitTest(wxCoord coord) const { - const size_t lineMax = GetVisibleEnd(); - for ( size_t line = GetVisibleBegin(); line < lineMax; line++ ) + const size_t unitMax = GetVisibleEnd(); + for ( size_t unit = GetVisibleBegin(); unit < unitMax; ++unit ) { - y -= OnGetLineHeight(line); - if ( y < 0 ) - return line; + coord -= OnGetUnitSize(unit); + if ( coord < 0 ) + return unit; } return wxNOT_FOUND; } // ---------------------------------------------------------------------------- -// scrolling +// wxVarScrollHelperBase scrolling // ---------------------------------------------------------------------------- -bool wxVScrolledWindow::ScrollToLine(size_t line) +bool wxVarScrollHelperBase::DoScrollToUnit(size_t unit) { - if ( !m_lineMax ) + if ( !m_unitMax ) { // we're empty, code below doesn't make sense in this case return false; } - // determine the real first line to scroll to: we shouldn't scroll beyond + // determine the real first unit to scroll to: we shouldn't scroll beyond // the end - size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true); - if ( line > lineFirstLast ) - line = lineFirstLast; + size_t unitFirstLast = FindFirstVisibleFromLast(m_unitMax - 1, true); + if ( unit > unitFirstLast ) + unit = unitFirstLast; // anything to do? - if ( line == m_lineFirst ) + if ( unit == m_unitFirst ) { // no return false; } - // remember the currently shown lines for the refresh code below - size_t lineFirstOld = GetVisibleBegin(); + // remember the currently shown units for the refresh code below + size_t unitFirstOld = GetVisibleBegin(), + unitLastOld = GetVisibleEnd(); - m_lineFirst = line; + m_unitFirst = unit; // the size of scrollbar thumb could have changed UpdateScrollbar(); - // finally, scroll the actual window - ScrollWindow(0, GetLinesHeight(GetVisibleBegin(), lineFirstOld)); + // finally refresh the display -- but only redraw as few units as possible + // to avoid flicker. We can't do this if we have children because they + // won't be scrolled + if ( m_targetWindow->GetChildren().empty() && + (GetVisibleBegin() >= unitLastOld || GetVisibleEnd() <= unitFirstOld) ) + { + // the simplest case: we don't have any old units left, just redraw + // everything + m_targetWindow->Refresh(); + } + else // scroll the window + { + // Avoid scrolling visible parts of the screen on Mac +#ifdef __WXMAC__ + if (m_physicalScrolling && m_targetWindow->IsShownOnScreen()) +#else + if ( m_physicalScrolling ) +#endif + { + wxCoord dx = 0, + dy = GetUnitsSize(GetVisibleBegin(), unitFirstOld); + + if ( GetOrientation() == wxHORIZONTAL ) + { + wxCoord tmp = dx; + dx = dy; + dy = tmp; + } + + m_targetWindow->ScrollWindow(dx, dy); + } + else // !m_physicalScrolling + { + // we still need to invalidate but we can't use ScrollWindow + // because physical scrolling is disabled (the user either didn't + // want children scrolled and/or doesn't want pixels to be + // physically scrolled). + m_targetWindow->Refresh(); + } + } return true; } -bool wxVScrolledWindow::ScrollLines(int lines) +bool wxVarScrollHelperBase::DoScrollUnits(int units) { - lines += m_lineFirst; - if ( lines < 0 ) - lines = 0; + units += m_unitFirst; + if ( units < 0 ) + units = 0; - return ScrollToLine(lines); + return DoScrollToUnit(units); } -bool wxVScrolledWindow::ScrollPages(int pages) +bool wxVarScrollHelperBase::DoScrollPages(int pages) { bool didSomething = false; while ( pages ) { - int line; + int unit; if ( pages > 0 ) { - line = GetVisibleEnd(); - if ( line ) - line--; - pages--; + unit = GetVisibleEnd(); + if ( unit ) + --unit; + --pages; } else // pages < 0 { - line = FindFirstFromBottom(GetVisibleBegin()); - pages++; + unit = FindFirstVisibleFromLast(GetVisibleEnd()); + ++pages; } - didSomething = ScrollToLine(line); + didSomething = DoScrollToUnit(unit); } return didSomething; @@ -377,71 +667,94 @@ bool wxVScrolledWindow::ScrollPages(int pages) // event handling // ---------------------------------------------------------------------------- -void wxVScrolledWindow::OnSize(wxSizeEvent& event) +void wxVarScrollHelperBase::HandleOnSize(wxSizeEvent& event) { + if ( m_unitMax ) + { + // sometimes change in varscrollable window's size can result in + // unused empty space after the last item. Fix it by decrementing + // first visible item position according to the available space. + + // determine free space + const wxCoord sWindow = GetOrientationTargetSize(); + wxCoord s = 0; + size_t unit; + for ( unit = m_unitFirst; unit < m_unitMax; ++unit ) + { + if ( s > sWindow ) + break; + + s += OnGetUnitSize(unit); + } + wxCoord freeSpace = sWindow - s; + + // decrement first visible item index as long as there is free space + size_t idealUnitFirst; + for ( idealUnitFirst = m_unitFirst; + idealUnitFirst > 0; + idealUnitFirst-- ) + { + wxCoord us = OnGetUnitSize(idealUnitFirst-1); + if ( freeSpace < us ) + break; + freeSpace -= us; + } + m_unitFirst = idealUnitFirst; + } + UpdateScrollbar(); event.Skip(); } -void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) +void wxVarScrollHelperBase::HandleOnScroll(wxScrollWinEvent& event) { - size_t lineFirstNew; - - const wxEventType evtType = event.GetEventType(); - - if ( evtType == wxEVT_SCROLLWIN_TOP ) - { - lineFirstNew = 0; - } - else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) - { - lineFirstNew = m_lineMax; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) - { - lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) - { - lineFirstNew = m_lineFirst + 1; - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) - { - lineFirstNew = FindFirstFromBottom(m_lineFirst); - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) - { - lineFirstNew = GetVisibleEnd(); - if ( lineFirstNew ) - lineFirstNew--; - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) - { - lineFirstNew = event.GetPosition(); - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) - { - lineFirstNew = event.GetPosition(); - } - - else // unknown scroll event? + if (GetOrientation() != event.GetOrientation()) { - wxFAIL_MSG( _T("unknown scroll event type?") ); + event.Skip(); return; } - ScrollToLine(lineFirstNew); + DoScrollToUnit(GetNewScrollPosition(event)); #ifdef __WXMAC__ - Update(); + UpdateMacScrollWindow(); #endif // __WXMAC__ } +void wxVarScrollHelperBase::DoPrepareDC(wxDC& dc) +{ + if ( m_physicalScrolling ) + { + wxPoint pt = dc.GetDeviceOrigin(); + + IncOrient(pt.x, pt.y, -GetScrollOffset()); + + dc.SetDeviceOrigin(pt.x, pt.y); + } +} + +int wxVarScrollHelperBase::DoCalcScrolledPosition(int coord) const +{ + return coord - GetScrollOffset(); +} + +int wxVarScrollHelperBase::DoCalcUnscrolledPosition(int coord) const +{ + return coord + GetScrollOffset(); +} + #if wxUSE_MOUSEWHEEL -void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event) +void wxVarScrollHelperBase::HandleOnMouseWheel(wxMouseEvent& event) { + // we only want to process wheel events for vertical implementations. + // There is no way to determine wheel orientation (and on MSW horizontal + // wheel rotation just fakes scroll events, rather than sending a MOUSEWHEEL + // event). + if ( GetOrientation() != wxVERTICAL ) + return; + m_sumWheelRotation += event.GetWheelRotation(); int delta = event.GetWheelDelta(); @@ -453,486 +766,88 @@ void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event) m_sumWheelRotation += units_to_scroll*delta; if ( !event.IsPageScroll() ) - ScrollLines( units_to_scroll*event.GetLinesPerAction() ); - else - // scroll pages instead of lines - ScrollPages( units_to_scroll ); + DoScrollUnits( units_to_scroll*event.GetLinesPerAction() ); + else // scroll pages instead of units + DoScrollPages( units_to_scroll ); } -#endif - - - - -// ---------------------------------------------------------------------------- -// wxVarScrolled Window event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxHVScrolledWindow, wxPanel) - EVT_SIZE(wxHVScrolledWindow::OnSize) - EVT_SCROLLWIN(wxHVScrolledWindow::OnScroll) -#if wxUSE_MOUSEWHEEL - EVT_MOUSEWHEEL(wxHVScrolledWindow::OnMouseWheel) -#endif -END_EVENT_TABLE() +#endif // wxUSE_MOUSEWHEEL // ============================================================================ -// wxVarScrolled implementation +// wxVarHVScrollHelper implementation // ============================================================================ -IMPLEMENT_ABSTRACT_CLASS(wxHVScrolledWindow, wxPanel) - // ---------------------------------------------------------------------------- -// initialization +// wxVarHVScrollHelper operations // ---------------------------------------------------------------------------- -void wxHVScrolledWindow::Init() +void wxVarHVScrollHelper::SetRowColumnCount(size_t rowCount, size_t columnCount) { - // we're initially empty - m_rowsMax = - m_columnsMax = - m_rowsFirst = - m_columnsFirst = 0; - - // these should always be strictly positive - m_nRowsVisible = - m_nColumnsVisible = 1; - - m_widthTotal = - m_heightTotal = 0; - - m_physicalScrolling = true; - -#if wxUSE_MOUSEWHEEL - m_sumWheelRotation = 0; -#endif + SetRowCount(rowCount); + SetColumnCount(columnCount); } -// ---------------------------------------------------------------------------- -// various helpers -// ---------------------------------------------------------------------------- - -wxCoord wxHVScrolledWindow::EstimateTotalHeight() const +bool wxVarHVScrollHelper::ScrollToRowColumn(size_t row, size_t column) { - // estimate the total height: it is impossible to call - // OnGetLineHeight() for every line because there may be too many of - // them, so we just make a guess using some lines in the beginning, - // some in the end and some in the middle - static const size_t NUM_LINES_TO_SAMPLE = 10; + bool result = false; + result |= ScrollToRow(row); + result |= ScrollToColumn(column); + return result; +} - wxCoord heightTotal; - if ( m_rowsMax < 3*NUM_LINES_TO_SAMPLE ) - { - // in this case calculating exactly is faster and more correct than - // guessing - heightTotal = GetRowsHeight(0, m_rowsMax); - } - else // too many lines to calculate exactly +void wxVarHVScrollHelper::RefreshRowColumn(size_t row, size_t column) +{ + // is this unit visible? + if ( !IsRowVisible(row) || !IsColumnVisible(column) ) { - // look at some lines in the beginning/middle/end - heightTotal = - GetRowsHeight(0, NUM_LINES_TO_SAMPLE) + - GetRowsHeight(m_rowsMax - NUM_LINES_TO_SAMPLE, - m_rowsMax) + - GetRowsHeight(m_rowsMax/2 - NUM_LINES_TO_SAMPLE/2, - m_rowsMax/2 + NUM_LINES_TO_SAMPLE/2); - - // use the height of the lines we looked as the average - heightTotal = (wxCoord) - (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_rowsMax); + // no, it is useless to do anything + return; } - return heightTotal; -} + // calculate the rect occupied by this cell on screen + wxRect v_rect, h_rect; + v_rect.height = OnGetRowHeight(row); + h_rect.width = OnGetColumnWidth(column); -wxCoord wxHVScrolledWindow::EstimateTotalWidth() const -{ - // estimate the total width: it is impossible to call - // OnGetLineWidth() for every line because there may be too many of - // them, so we just make a guess using some lines in the beginning, - // some in the end and some in the middle - static const size_t NUM_LINES_TO_SAMPLE = 10; + size_t n; - wxCoord widthTotal; - if ( m_columnsMax < 3*NUM_LINES_TO_SAMPLE ) + for ( n = GetVisibleRowsBegin(); n < row; n++ ) { - // in this case calculating exactly is faster and more correct than - // guessing - widthTotal = GetColumnsWidth(0, m_columnsMax); + v_rect.y += OnGetRowHeight(n); } - else // too many lines to calculate exactly + + for ( n = GetVisibleColumnsBegin(); n < column; n++ ) { - // look at some lines in the beginning/middle/end - widthTotal = - GetColumnsWidth(0, NUM_LINES_TO_SAMPLE) + - GetColumnsWidth(m_columnsMax - NUM_LINES_TO_SAMPLE, - m_columnsMax) + - GetColumnsWidth(m_columnsMax/2 - NUM_LINES_TO_SAMPLE/2, - m_columnsMax/2 + NUM_LINES_TO_SAMPLE/2); - - // use the width of the lines we looked as the average - widthTotal = (wxCoord) - (((float)widthTotal / (3*NUM_LINES_TO_SAMPLE)) * m_columnsMax); + h_rect.x += OnGetColumnWidth(n); } - return widthTotal; -} - -wxCoord wxHVScrolledWindow::GetRowsHeight(size_t rowMin, size_t rowMax) const -{ - if ( rowMin == rowMax ) - return 0; - else if ( rowMin > rowMax ) - return -GetRowsHeight(rowMax, rowMin); - //else: lineMin < lineMax - - // let the user code know that we're going to need all these lines - OnGetRowsHeightHint(rowMin, rowMax); - - // do sum up their heights - wxCoord height = 0; - for ( size_t row = rowMin; row < rowMax; row++ ) + // refresh but specialize the behaviour if we have a single target window + if ( wxVarVScrollHelper::GetTargetWindow() == wxVarHScrollHelper::GetTargetWindow() ) { - height += OnGetRowHeight(row); + v_rect.x = h_rect.x; + v_rect.width = h_rect.width; + wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect); } + else + { + v_rect.x = 0; + v_rect.width = wxVarVScrollHelper::GetNonOrientationTargetSize(); + h_rect.y = 0; + h_rect.width = wxVarHScrollHelper::GetNonOrientationTargetSize(); - return height; + wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect); + wxVarHScrollHelper::GetTargetWindow()->RefreshRect(h_rect); + } } -wxCoord wxHVScrolledWindow::GetColumnsWidth(size_t columnMin, size_t columnMax) const -{ - if ( columnMin == columnMax ) - return 0; - else if ( columnMin > columnMax ) - return -GetColumnsWidth(columnMax, columnMin); - //else: lineMin < lineMax - - // let the user code know that we're going to need all these lines - OnGetColumnsWidthHint(columnMin, columnMax); - - // do sum up their widths - wxCoord width = 0; - for ( size_t column = columnMin; column < columnMax; column++ ) - { - width += OnGetColumnWidth(column); - } - - return width; -} - -size_t wxHVScrolledWindow::FindFirstFromBottom(size_t rowLast, bool full) -{ - const wxCoord hWindow = GetClientSize().y; - - // go upwards until we arrive at a line such that lineLast is not visible - // any more when it is shown - size_t lineFirst = rowLast; - wxCoord h = 0; - for ( ;; ) - { - h += OnGetRowHeight(lineFirst); - - if ( h > hWindow ) - { - // for this line to be fully visible we need to go one line - // down, but if it is enough for it to be only partly visible then - // this line will do as well - if ( full ) - { - lineFirst++; - } - - break; - } - - if ( !lineFirst ) - break; - - lineFirst--; - } - - return lineFirst; -} - -size_t wxHVScrolledWindow::FindFirstFromRight(size_t columnLast, bool full) -{ - const wxCoord wWindow = GetClientSize().x; - - // go upwards until we arrive at a line such that lineLast is not visible - // any more when it is shown - size_t lineFirst = columnLast; - wxCoord w = 0; - for ( ;; ) - { - w += OnGetColumnWidth(lineFirst); - - if ( w > wWindow ) - { - // for this line to be fully visible we need to go one line - // down, but if it is enough for it to be only partly visible then - // this line will do as well - if ( full ) - { - lineFirst++; - } - - break; - } - - if ( !lineFirst ) - break; - - lineFirst--; - } - - return lineFirst; -} - -void wxHVScrolledWindow::UpdateScrollbars() -{ - // see how many lines can we fit on screen (on both axes) - const wxCoord wWindow = GetClientSize().x; - const wxCoord hWindow = GetClientSize().y; - - // first do the horizontal calculations - wxCoord w = 0; - size_t column; - for ( column = m_columnsFirst; column < m_columnsMax; column++ ) - { - if ( w > wWindow ) - break; - - w += OnGetColumnWidth(column); - } - - m_nColumnsVisible = column - m_columnsFirst; - - int columnsPageSize = m_nColumnsVisible; - if ( w > wWindow ) - { - // last line is only partially visible, we still need the scrollbar and - // so we have to "fix" pageSize because if it is equal to - // m_horizLineMax the scrollbar is not shown at all under MSW - columnsPageSize--; - } - - // set the scrollbar parameters to reflect this - SetScrollbar(wxHORIZONTAL, m_columnsFirst, columnsPageSize, m_columnsMax); - - - // now do the vertical calculations - wxCoord h = 0; - size_t row; - for ( row = m_rowsFirst; row < m_rowsMax; row++ ) - { - if ( h > hWindow ) - break; - - h += OnGetRowHeight(row); - } - - m_nRowsVisible = row - m_rowsFirst; - - int rowsPageSize = m_nRowsVisible; - if ( h > hWindow ) - { - // last line is only partially visible, we still need the scrollbar and - // so we have to "fix" pageSize because if it is equal to m_vertLineMax - // the scrollbar is not shown at all under MSW - rowsPageSize--; - } - - // set the scrollbar parameters to reflect this - SetScrollbar(wxVERTICAL, m_rowsFirst, rowsPageSize, m_rowsMax); -} - -void wxHVScrolledWindow::PrepareDC(wxDC& dc) -{ - if(m_physicalScrolling) - { - dc.SetDeviceOrigin(-GetColumnsWidth(0, GetVisibleColumnsBegin()), - -GetRowsHeight(0, GetVisibleRowsBegin())); - } -} - -// ---------------------------------------------------------------------------- -// operations -// ---------------------------------------------------------------------------- - -void wxHVScrolledWindow::SetRowColumnCounts(size_t rowCount, size_t columnCount) -{ - // save the number of lines - m_rowsMax = rowCount; - m_columnsMax = columnCount; - - // and our estimate for their total height and width - m_heightTotal = EstimateTotalHeight(); - m_widthTotal = EstimateTotalWidth(); - - // recalculate the scrollbars parameters - if(m_rowsFirst >= rowCount) - m_rowsFirst = (rowCount > 0) ? rowCount - 1 : 0; - - if(m_columnsFirst >= columnCount) - m_columnsFirst = (columnCount > 0) ? columnCount - 1 : 0; - -#if 0 - // checks disabled due to size_t type of members - // but leave them here if anyone would want to do some debugging - if(m_rowsFirst < 0) - m_rowsFirst = 0; - - if(m_columnsFirst < 0) - m_columnsFirst = 0; -#endif - - ScrollToRowColumn(m_rowsFirst, m_columnsFirst); -} - -void wxHVScrolledWindow::RefreshColumn(size_t column) -{ - // is this line visible? - if ( !IsColumnVisible(column) ) - { - // no, it is useless to do anything - return; - } - - // calculate the rect occupied by this line on screen - wxRect rect; - rect.width = OnGetColumnWidth(column); - rect.height = GetClientSize().y; - for ( size_t n = GetVisibleColumnsBegin(); n < column; n++ ) - { - rect.y += OnGetColumnWidth(n); - } - - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshRow(size_t row) -{ - // is this line visible? - if ( !IsRowVisible(row) ) - { - // no, it is useless to do anything - return; - } - - // calculate the rect occupied by this line on screen - wxRect rect; - rect.width = GetClientSize().x; - rect.height = OnGetRowHeight(row); - for ( size_t n = GetVisibleRowsBegin(); n < row; n++ ) - { - rect.y += OnGetRowHeight(n); - } - - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshRowColumn(size_t row, size_t column) -{ - // is this line visible? - if ( !IsRowVisible(row) || !IsColumnVisible(column) ) - { - // no, it is useless to do anything - return; - } - - // calculate the rect occupied by this cell on screen - wxRect rect; - rect.height = OnGetRowHeight(row); - rect.width = OnGetColumnWidth(column); - - size_t n; - - for ( n = GetVisibleRowsBegin(); n < row; n++ ) - { - rect.y += OnGetRowHeight(n); - } - - for ( n = GetVisibleColumnsBegin(); n < column; n++ ) - { - rect.x += OnGetColumnWidth(n); - } - - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshRows(size_t from, size_t to) -{ - wxASSERT_MSG( from <= to, _T("RefreshRows(): empty range") ); - - // clump the range to just the visible lines -- it is useless to refresh - // the other ones - if ( from < GetVisibleRowsBegin() ) - from = GetVisibleRowsBegin(); - - if ( to > GetVisibleRowsEnd() ) - to = GetVisibleRowsEnd(); - - // calculate the rect occupied by these lines on screen - wxRect rect; - rect.width = GetClientSize().x; - for ( size_t nBefore = GetVisibleRowsBegin(); - nBefore < from; - nBefore++ ) - { - rect.y += OnGetRowHeight(nBefore); - } - - for ( size_t nBetween = from; nBetween <= to; nBetween++ ) - { - rect.height += OnGetRowHeight(nBetween); - } - - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshColumns(size_t from, size_t to) -{ - wxASSERT_MSG( from <= to, _T("RefreshColumns(): empty range") ); - - // clump the range to just the visible lines -- it is useless to refresh - // the other ones - if ( from < GetVisibleColumnsBegin() ) - from = GetVisibleColumnsBegin(); - - if ( to > GetVisibleColumnsEnd() ) - to = GetVisibleColumnsEnd(); - - // calculate the rect occupied by these lines on screen - wxRect rect; - rect.height = GetClientSize().y; - for ( size_t nBefore = GetVisibleColumnsBegin(); - nBefore < from; - nBefore++ ) - { - rect.x += OnGetColumnWidth(nBefore); - } - - for ( size_t nBetween = from; nBetween <= to; nBetween++ ) - { - rect.width += OnGetColumnWidth(nBetween); - } - - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshRowsColumns(size_t fromRow, size_t toRow, - size_t fromColumn, size_t toColumn) +void wxVarHVScrollHelper::RefreshRowsColumns(size_t fromRow, size_t toRow, + size_t fromColumn, size_t toColumn) { wxASSERT_MSG( fromRow <= toRow || fromColumn <= toColumn, - _T("RefreshRowsColumns(): empty range") ); + wxT("RefreshRowsColumns(): empty range") ); - // clump the range to just the visible lines -- it is useless to refresh + // clump the range to just the visible units -- it is useless to refresh // the other ones if ( fromRow < GetVisibleRowsBegin() ) fromRow = GetVisibleRowsBegin(); @@ -946,452 +861,156 @@ void wxHVScrolledWindow::RefreshRowsColumns(size_t fromRow, size_t toRow, if ( toColumn > GetVisibleColumnsEnd() ) toColumn = GetVisibleColumnsEnd(); - // calculate the rect occupied by these lines on screen - wxRect rect; + // calculate the rect occupied by these units on screen + wxRect v_rect, h_rect; size_t nBefore, nBetween; for ( nBefore = GetVisibleRowsBegin(); nBefore < fromRow; nBefore++ ) { - rect.y += OnGetRowHeight(nBefore); + v_rect.y += OnGetRowHeight(nBefore); } for ( nBetween = fromRow; nBetween <= toRow; nBetween++ ) { - rect.height += OnGetRowHeight(nBetween); + v_rect.height += OnGetRowHeight(nBetween); } for ( nBefore = GetVisibleColumnsBegin(); nBefore < fromColumn; nBefore++ ) { - rect.x += OnGetColumnWidth(nBefore); + h_rect.x += OnGetColumnWidth(nBefore); } for ( nBetween = fromColumn; nBetween <= toColumn; nBetween++ ) { - rect.width += OnGetColumnWidth(nBetween); + h_rect.width += OnGetColumnWidth(nBetween); } - // do refresh it - RefreshRect(rect); -} - -void wxHVScrolledWindow::RefreshAll() -{ - UpdateScrollbars(); - - Refresh(); -} - -bool wxHVScrolledWindow::Layout() -{ - if(GetSizer() && m_physicalScrolling) + // refresh but specialize the behaviour if we have a single target window + if ( wxVarVScrollHelper::GetTargetWindow() == wxVarHScrollHelper::GetTargetWindow() ) { - // adjust the sizer dimensions/position taking into account the - // virtual size and scrolled position of the window. - - int x, y, w, h; - - y = -GetRowsHeight(0, GetVisibleRowsBegin()); - x = -GetColumnsWidth(0, GetVisibleColumnsBegin()); - GetVirtualSize(&w, &h); - GetSizer()->SetDimension(0, y, w, h); - return true; + v_rect.x = h_rect.x; + v_rect.width = h_rect.width; + wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect); } - - // fall back to default for LayoutConstraints - return wxPanel::Layout(); -} - -wxPoint wxHVScrolledWindow::HitTest(wxCoord x, wxCoord y) const -{ - const size_t rowMax = GetVisibleRowsEnd(); - const size_t columnMax = GetVisibleColumnsEnd(); - - wxPoint hit(wxNOT_FOUND, wxNOT_FOUND); - for ( size_t row = GetVisibleRowsBegin(); - row <= rowMax; - row++ ) + else { - y -= OnGetRowHeight(row); - if ( y < 0 ) - hit.y = row; - } + v_rect.x = 0; + v_rect.width = wxVarVScrollHelper::GetNonOrientationTargetSize(); + h_rect.y = 0; + h_rect.width = wxVarHScrollHelper::GetNonOrientationTargetSize(); - for ( size_t column = GetVisibleColumnsBegin(); - column <= columnMax; - column++ ) - { - x -= OnGetColumnWidth(column); - if ( x < 0 ) - hit.x = column; + wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect); + wxVarHScrollHelper::GetTargetWindow()->RefreshRect(h_rect); } - - return hit; } -// ---------------------------------------------------------------------------- -// scrolling -// ---------------------------------------------------------------------------- - -bool wxHVScrolledWindow::ScrollToRowColumn(size_t row, size_t column) +wxPosition wxVarHVScrollHelper::VirtualHitTest(wxCoord x, wxCoord y) const { - if ( !m_rowsMax && !m_columnsMax ) - { - // we're empty, code below doesn't make sense in this case - return false; - } - - bool scrolled = false; - scrolled |= ScrollToRow(row); - scrolled |= ScrollToColumn(column); - - return scrolled; + return wxPosition(wxVarVScrollHelper::VirtualHitTest(y), + wxVarHScrollHelper::VirtualHitTest(x)); } -bool wxHVScrolledWindow::ScrollToRow(size_t row) +void wxVarHVScrollHelper::DoPrepareDC(wxDC& dc) { - if ( !m_rowsMax ) - { - // we're empty, code below doesn't make sense in this case - return false; - } - - // determine the real first line to scroll to: we shouldn't scroll beyond - // the end - size_t lineFirstLast = FindFirstFromBottom(m_rowsMax - 1, true); - if ( row > lineFirstLast ) - row = lineFirstLast; - - // anything to do? - if ( row == m_rowsFirst ) - { - // no - return false; - } - - - // remember the currently shown lines for the refresh code below - size_t lineFirstOld = GetVisibleRowsBegin(); - - m_rowsFirst = row; - - - // the size of scrollbar thumb could have changed - UpdateScrollbars(); - - - // finally, scroll the actual window contents vertically - if(m_physicalScrolling) - ScrollWindow(0, GetRowsHeight(GetVisibleRowsBegin(), lineFirstOld)); - - return true; + wxVarVScrollHelper::DoPrepareDC(dc); + wxVarHScrollHelper::DoPrepareDC(dc); } -bool wxHVScrolledWindow::ScrollToColumn(size_t column) +bool wxVarHVScrollHelper::ScrollLayout() { - if ( !m_columnsMax ) - { - // we're empty, code below doesn't make sense in this case - return false; - } - - // determine the real first line to scroll to: we shouldn't scroll beyond - // the end - size_t lineFirstLast = FindFirstFromRight(m_columnsMax - 1, true); - if ( column > lineFirstLast ) - column = lineFirstLast; - - // anything to do? - if ( column == m_columnsFirst ) - { - // no - return false; - } - - - // remember the currently shown lines for the refresh code below - size_t lineFirstOld = GetVisibleColumnsBegin(); - - m_columnsFirst = column; - - - // the size of scrollbar thumb could have changed - UpdateScrollbars(); - - // finally, scroll the actual window contents horizontally - if(m_physicalScrolling) - ScrollWindow(GetColumnsWidth(GetVisibleColumnsBegin(), lineFirstOld), 0); - - return true; + bool layout_result = false; + layout_result |= wxVarVScrollHelper::ScrollLayout(); + layout_result |= wxVarHScrollHelper::ScrollLayout(); + return layout_result; } -bool wxHVScrolledWindow::ScrollRows(int rows) +wxSize wxVarHVScrollHelper::GetRowColumnCount() const { - rows += m_rowsFirst; - if ( rows < 0 ) - rows = 0; - - return ScrollToRow(rows); + return wxSize(GetColumnCount(), GetRowCount()); } -bool wxHVScrolledWindow::ScrollColumns(int columns) +wxPosition wxVarHVScrollHelper::GetVisibleBegin() const { - columns += m_columnsFirst; - if ( columns < 0 ) - columns = 0; - - return ScrollToColumn(columns); + return wxPosition(GetVisibleRowsBegin(), GetVisibleColumnsBegin()); } -bool wxHVScrolledWindow::ScrollRowsColumns(int rows, int columns) +wxPosition wxVarHVScrollHelper::GetVisibleEnd() const { - rows += m_rowsFirst; - if ( rows < 0 ) - rows = 0; - - columns += m_columnsFirst; - if ( columns < 0 ) - columns = 0; - - return ScrollToRowColumn(rows, columns); + return wxPosition(GetVisibleRowsEnd(), GetVisibleColumnsEnd()); } -bool wxHVScrolledWindow::ScrollRowPages(int pages) +bool wxVarHVScrollHelper::IsVisible(size_t row, size_t column) const { - bool didSomething = false; + return IsRowVisible(row) && IsColumnVisible(column); +} - while ( pages ) - { - int line; - if ( pages > 0 ) - { - line = GetVisibleRowsEnd(); - if ( line ) - line--; - pages--; - } - else // pages < 0 - { - line = FindFirstFromBottom(GetVisibleRowsEnd()); - pages++; - } - didSomething = ScrollToRow(line); - } +// ============================================================================ +// wx[V/H/HV]ScrolledWindow implementations +// ============================================================================ - return didSomething; -} +IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel) +IMPLEMENT_ABSTRACT_CLASS(wxHScrolledWindow, wxPanel) +IMPLEMENT_ABSTRACT_CLASS(wxHVScrolledWindow, wxPanel) -bool wxHVScrolledWindow::ScrollColumnPages(int pages) -{ - bool didSomething = false; - while ( pages ) - { - int line; - if ( pages > 0 ) - { - line = GetVisibleColumnsEnd(); - if ( line ) - line--; - pages--; - } - else // pages < 0 - { - line = FindFirstFromRight(GetVisibleColumnsEnd()); - pages++; - } +#if WXWIN_COMPATIBILITY_2_8 - didSomething = ScrollToColumn(line); - } +// =========================================================================== +// wxVarVScrollLegacyAdaptor +// =========================================================================== - return didSomething; -} +size_t wxVarVScrollLegacyAdaptor::GetFirstVisibleLine() const +{ return GetVisibleRowsBegin(); } -bool wxHVScrolledWindow::ScrollPages(int rowPages, int columnPages) -{ - bool didSomething = false; +size_t wxVarVScrollLegacyAdaptor::GetLastVisibleLine() const +{ return GetVisibleRowsEnd() - 1; } - while ( rowPages ) - { - int line; - if ( rowPages > 0 ) - { - line = GetVisibleRowsEnd(); - if ( line ) - line--; - rowPages--; - } - else // rowPages < 0 - { - line = FindFirstFromBottom(GetVisibleRowsBegin()); - rowPages++; - } +size_t wxVarVScrollLegacyAdaptor::GetLineCount() const +{ return GetRowCount(); } - didSomething = ScrollToRow(line); - } +void wxVarVScrollLegacyAdaptor::SetLineCount(size_t count) +{ SetRowCount(count); } - while ( columnPages ) - { - int line; - if ( columnPages > 0 ) - { - line = GetVisibleColumnsEnd(); - if ( line ) - line--; - columnPages--; - } - else // columnPages < 0 - { - line = FindFirstFromRight(GetVisibleColumnsBegin()); - columnPages++; - } +void wxVarVScrollLegacyAdaptor::RefreshLine(size_t line) +{ RefreshRow(line); } - didSomething |= ScrollToColumn(line); - } +void wxVarVScrollLegacyAdaptor::RefreshLines(size_t from, size_t to) +{ RefreshRows(from, to); } - return didSomething; -} +bool wxVarVScrollLegacyAdaptor::ScrollToLine(size_t line) +{ return ScrollToRow(line); } -// ---------------------------------------------------------------------------- -// event handling -// ---------------------------------------------------------------------------- +bool wxVarVScrollLegacyAdaptor::ScrollLines(int lines) +{ return ScrollRows(lines); } -void wxHVScrolledWindow::OnSize(wxSizeEvent& event) -{ - UpdateScrollbars(); - Layout(); +bool wxVarVScrollLegacyAdaptor::ScrollPages(int pages) +{ return ScrollRowPages(pages); } - event.Skip(); +wxCoord wxVarVScrollLegacyAdaptor::OnGetLineHeight(size_t WXUNUSED(n)) const +{ + wxFAIL_MSG( wxT("OnGetLineHeight() must be overridden if OnGetRowHeight() isn't!") ); + return -1; } -void wxHVScrolledWindow::OnScroll(wxScrollWinEvent& event) +void wxVarVScrollLegacyAdaptor::OnGetLinesHint(size_t WXUNUSED(lineMin), + size_t WXUNUSED(lineMax)) const { - if(event.GetOrientation() == wxHORIZONTAL) - { - size_t columnsFirstNew; - const wxEventType evtType = event.GetEventType(); - - if ( evtType == wxEVT_SCROLLWIN_TOP ) - { - columnsFirstNew = 0; - } - else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) - { - columnsFirstNew = m_columnsMax; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) - { - columnsFirstNew = m_columnsFirst ? m_columnsFirst - 1 : 0; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) - { - columnsFirstNew = m_columnsFirst + 1; - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) - { - columnsFirstNew = FindFirstFromRight(m_columnsFirst); - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) - { - columnsFirstNew = GetVisibleColumnsEnd(); - if ( columnsFirstNew ) - columnsFirstNew--; - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) - { - columnsFirstNew = event.GetPosition(); - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) - { - columnsFirstNew = event.GetPosition(); - } - - else // unknown scroll event? - { - wxFAIL_MSG( _T("unknown scroll event type?") ); - return; - } - - ScrollToColumn(columnsFirstNew); - } - else if(event.GetOrientation() == wxVERTICAL) - { - size_t rowsFirstNew; - const wxEventType evtType = event.GetEventType(); - - if ( evtType == wxEVT_SCROLLWIN_TOP ) - { - rowsFirstNew = 0; - } - else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) - { - rowsFirstNew = m_rowsMax; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) - { - rowsFirstNew = m_rowsFirst ? m_rowsFirst - 1 : 0; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) - { - rowsFirstNew = m_rowsFirst + 1; - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) - { - rowsFirstNew = FindFirstFromBottom(m_rowsFirst); - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) - { - rowsFirstNew = GetVisibleRowsEnd(); - if ( rowsFirstNew ) - rowsFirstNew--; - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) - { - rowsFirstNew = event.GetPosition(); - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) - { - rowsFirstNew = event.GetPosition(); - } - - else // unknown scroll event? - { - wxFAIL_MSG( _T("unknown scroll event type?") ); - return; - } - - ScrollToRow(rowsFirstNew); - } - - -#ifdef __WXMAC__ - Update(); -#endif // __WXMAC__ } -#if wxUSE_MOUSEWHEEL - -void wxHVScrolledWindow::OnMouseWheel(wxMouseEvent& event) +wxCoord wxVarVScrollLegacyAdaptor::OnGetRowHeight(size_t n) const { - m_sumWheelRotation += event.GetWheelRotation(); - int delta = event.GetWheelDelta(); - - // how much to scroll this time - int units_to_scroll = -(m_sumWheelRotation/delta); - if ( !units_to_scroll ) - return; - - m_sumWheelRotation += units_to_scroll*delta; + return OnGetLineHeight(n); +} - if ( !event.IsPageScroll() ) - ScrollRows( units_to_scroll*event.GetLinesPerAction() ); - else - // scroll pages instead of lines - ScrollRowPages( units_to_scroll ); +void wxVarVScrollLegacyAdaptor::OnGetRowsHeightHint(size_t rowMin, + size_t rowMax) const +{ + OnGetLinesHint(rowMin, rowMax); } -#endif +#endif // WXWIN_COMPATIBILITY_2_8