// 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 <vadim@wxwindows.org>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#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"
+
+#include "wx/utils.h" // For wxMin/wxMax().
+
+// ============================================================================
+// 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 unitFirst;
+}
+
+size_t wxVarScrollHelperBase::GetNewScrollPosition(wxScrollWinEvent& event) const
+{
+ wxEventType evtType = event.GetEventType();
+
+ 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 )
+ {
+ // Page up should do at least as much as line up.
+ return wxMin(FindFirstVisibleFromLast(m_unitFirst),
+ m_unitFirst ? m_unitFirst - 1 : 0);
+ }
+ else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
+ {
+ // And page down should do at least as much as line down.
+ if ( GetVisibleEnd() )
+ return wxMax(GetVisibleEnd() - 1, m_unitFirst + 1);
+ else
+ return wxMax(GetVisibleEnd(), m_unitFirst + 1);
+ }
+ else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
+ {
+ return event.GetPosition();
+ }
+ else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
+ {
+ return event.GetPosition();
}
- return lineFirst;
+ // unknown scroll event?
+ wxFAIL_MSG( wxT("unknown scroll event type?") );
+ return 0;
}
-void wxVScrolledWindow::UpdateScrollbar()
+void wxVarScrollHelperBase::UpdateScrollbar()
{
- // see how many lines can we fit on screen
- const wxCoord hWindow = GetClientSize().y;
+ // if there is nothing to scroll, remove the scrollbar
+ if ( !m_unitMax )
+ {
+ RemoveScrollbar();
+ return;
+ }
- wxCoord h = 0;
- size_t line;
- for ( line = m_lineFirst; line < m_lineMax; line++ )
+ // 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)
{
- // save the number of lines
- m_lineMax = count;
+ 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 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 = 0,
+ orient_pos = 0;
+
+ int 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());
- y = -GetLinesHeight(0, GetFirstVisibleLine());
- GetVirtualSize(&w, &h);
- GetSizer()->SetDimension(0, y, w, h);
+ int w, h;
+ m_targetWindow->GetVirtualSize(&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;
// 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 )
+ if (GetOrientation() != event.GetOrientation())
{
- lineFirstNew = event.GetPosition();
- }
- else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
- {
- lineFirstNew = event.GetPosition();
- }
-
- else // unknown scroll event?
- {
- 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();
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);
+ }
+
+ for ( n = GetVisibleColumnsBegin(); n < column; n++ )
+ {
+ h_rect.x += OnGetColumnWidth(n);
}
- else // too many lines to calculate exactly
+
+ // refresh but specialize the behaviour if we have a single target window
+ if ( wxVarVScrollHelper::GetTargetWindow() == wxVarHScrollHelper::GetTargetWindow() )
{
- // 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);
+ 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 widthTotal;
+ wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect);
+ wxVarHScrollHelper::GetTargetWindow()->RefreshRect(h_rect);
+ }
}
-wxCoord wxHVScrolledWindow::GetRowsHeight(size_t rowMin, size_t rowMax) const
+void wxVarHVScrollHelper::RefreshRowsColumns(size_t fromRow, size_t toRow,
+ size_t fromColumn, size_t toColumn)
{
- if ( rowMin == rowMax )
- return 0;
- else if ( rowMin > rowMax )
- return -GetRowsHeight(rowMax, rowMin);
- //else: lineMin < lineMax
+ wxASSERT_MSG( fromRow <= toRow || fromColumn <= toColumn,
+ wxT("RefreshRowsColumns(): empty range") );
- // 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++ )
- {
- height += OnGetRowHeight(row);
- }
-
- return height;
-}
-
-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)
-{
- wxASSERT_MSG( fromRow <= toRow || fromColumn <= toColumn,
- _T("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();
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(x, 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