// Name: src/generic/vscroll.cpp
// Purpose: wxVScrolledWindow implementation
// Author: Vadim Zeitlin
-// Modified by:
+// Modified by: Brad Anderson
// Created: 30.05.03
// RCS-ID: $Id$
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
// headers
// ----------------------------------------------------------------------------
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
#include "wx/vscroll.h"
+#include "wx/sizer.h"
+#include "wx/dc.h"
// ----------------------------------------------------------------------------
// event tables
BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel)
EVT_SIZE(wxVScrolledWindow::OnSize)
EVT_SCROLLWIN(wxVScrolledWindow::OnScroll)
+#if wxUSE_MOUSEWHEEL
+ EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel)
+#endif
END_EVENT_TABLE()
// implementation
// ============================================================================
+IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel)
+
// ----------------------------------------------------------------------------
// initialization
// ----------------------------------------------------------------------------
m_nVisible = 1;
m_heightTotal = 0;
+
+#if wxUSE_MOUSEWHEEL
+ m_sumWheelRotation = 0;
+#endif
}
// ----------------------------------------------------------------------------
// various helpers
// ----------------------------------------------------------------------------
+wxCoord wxVScrolledWindow::EstimateTotalHeight() 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,
+ // some in the end and some in the middle
+ static const size_t NUM_LINES_TO_SAMPLE = 10;
+
+ wxCoord heightTotal;
+ if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE )
+ {
+ // in this case calculating exactly is faster and more correct than
+ // guessing
+ heightTotal = GetLinesHeight(0, m_lineMax);
+ }
+ else // too many lines 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);
+ }
+
+ return heightTotal;
+}
+
wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const
{
if ( lineMin == lineMax )
// save the number of lines
m_lineMax = count;
-
- // 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;
-
- if ( count < 3*NUM_LINES_TO_SAMPLE )
- {
- // in this case calculating exactly is faster and more correct than
- // guessing
- m_heightTotal = GetLinesHeight(0, m_lineMax);
- }
- else // too many lines to calculate exactly
- {
- // look at some lines in the beginning/middle/end
- m_heightTotal =
- GetLinesHeight(0, NUM_LINES_TO_SAMPLE) +
- GetLinesHeight(count - NUM_LINES_TO_SAMPLE, count) +
- GetLinesHeight(count/2 - NUM_LINES_TO_SAMPLE/2,
- count/2 + NUM_LINES_TO_SAMPLE/2);
-
- // use the height of the lines we looked as the average
- m_heightTotal = (wxCoord)
- (((float)m_heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_lineMax);
- }
-
+ // and our estimate for their total height
+ m_heightTotal = EstimateTotalHeight();
// recalculate the scrollbars parameters
m_lineFirst = 1; // make sure it is != 0
wxRect rect;
rect.width = GetClientSize().x;
rect.height = OnGetLineHeight(line);
- for ( size_t n = GetFirstVisibleLine(); n < line; n++ )
+ for ( size_t n = GetVisibleBegin(); n < line; n++ )
{
rect.y += OnGetLineHeight(n);
}
// clump the range to just the visible lines -- it is useless to refresh
// the other ones
- if ( from < GetFirstVisibleLine() )
- from = GetFirstVisibleLine();
+ if ( from < GetVisibleBegin() )
+ from = GetVisibleBegin();
- if ( to > GetLastVisibleLine() )
- to = GetLastVisibleLine();
+ 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 = GetFirstVisibleLine(); nBefore < from; nBefore++ )
+ for ( size_t nBefore = GetVisibleBegin(); nBefore < from; nBefore++ )
{
rect.y += OnGetLineHeight(nBefore);
}
Refresh();
}
+bool wxVScrolledWindow::Layout()
+{
+ if(GetSizer())
+ {
+ // 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
+
+ y = -GetLinesHeight(0, GetFirstVisibleLine());
+ GetVirtualSize(&w, &h);
+ GetSizer()->SetDimension(0, y, w, h);
+ return true;
+ }
+
+ // fall back to default for LayoutConstraints
+ return wxPanel::Layout();
+}
+
int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const
{
- const size_t lineMax = GetLastVisibleLine();
- for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ )
+ const size_t lineMax = GetVisibleEnd();
+ for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
{
y -= OnGetLineHeight(line);
if ( y < 0 )
// remember the currently shown lines for the refresh code below
- size_t lineFirstOld = GetFirstVisibleLine(),
- lineLastOld = GetLastVisibleLine();
+ size_t lineFirstOld = GetVisibleBegin();
m_lineFirst = line;
// the size of scrollbar thumb could have changed
UpdateScrollbar();
-
- // finally refresh the display -- but only redraw as few lines as possible
- // to avoid flicker
- if ( GetFirstVisibleLine() > lineLastOld ||
- GetLastVisibleLine() < lineFirstOld )
- {
- // the simplest case: we don't have any old lines left, just redraw
- // everything
- Refresh();
- }
- else // overlap between the lines we showed before and should show now
- {
- ScrollWindow(0, GetLinesHeight(GetFirstVisibleLine(), lineFirstOld));
- }
+ // finally, scroll the actual window
+ ScrollWindow(0, GetLinesHeight(GetVisibleBegin(), lineFirstOld));
return true;
}
int line;
if ( pages > 0 )
{
- line = GetLastVisibleLine();
+ line = GetVisibleEnd();
+ if ( line )
+ line--;
pages--;
}
else // pages < 0
{
- line = FindFirstFromBottom(GetFirstVisibleLine());
+ line = FindFirstFromBottom(GetVisibleBegin());
pages++;
}
size_t lineFirstNew;
const wxEventType evtType = event.GetEventType();
+
if ( evtType == wxEVT_SCROLLWIN_TOP )
{
lineFirstNew = 0;
}
else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
{
- lineFirstNew = GetLastVisibleLine();
+ 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 ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
+ wxFAIL_MSG( _T("unknown scroll event type?") );
+ return;
+ }
+
+ ScrollToLine(lineFirstNew);
+
+#ifdef __WXMAC__
+ Update();
+#endif // __WXMAC__
+}
+
+#if wxUSE_MOUSEWHEEL
+
+void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event)
+{
+ 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;
+
+ if ( !event.IsPageScroll() )
+ ScrollLines( units_to_scroll*event.GetLinesPerAction() );
+ else
+ // scroll pages instead of lines
+ ScrollPages( 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()
+
+
+// ============================================================================
+// wxVarScrolled implementation
+// ============================================================================
+
+IMPLEMENT_ABSTRACT_CLASS(wxHVScrolledWindow, wxPanel)
+
+// ----------------------------------------------------------------------------
+// initialization
+// ----------------------------------------------------------------------------
+
+void wxHVScrolledWindow::Init()
+{
+ // 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
+}
+
+// ----------------------------------------------------------------------------
+// various helpers
+// ----------------------------------------------------------------------------
+
+wxCoord wxHVScrolledWindow::EstimateTotalHeight() 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,
+ // some in the end and some in the middle
+ static const size_t NUM_LINES_TO_SAMPLE = 10;
+
+ 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
+ {
+ // 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);
+ }
+
+ return heightTotal;
+}
+
+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;
+
+ wxCoord widthTotal;
+ if ( m_columnsMax < 3*NUM_LINES_TO_SAMPLE )
+ {
+ // in this case calculating exactly is faster and more correct than
+ // guessing
+ widthTotal = GetColumnsWidth(0, m_columnsMax);
+ }
+ else // too many lines to calculate exactly
+ {
+ // 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);
+ }
+
+ 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++ )
+ {
+ 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 )
{
- lineFirstNew = event.GetPosition();
+ // 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;
}
- else
+
+ 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 )
{
- wxASSERT_MSG( evtType == wxEVT_SCROLLWIN_THUMBTRACK,
- _T("unknown scroll event type?") );
+ // 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++;
+ }
- // don't do anything, otherwise dragging the thumb around would
- // be too slow
- return;
+ break;
}
+
+ if ( !lineFirst )
+ break;
+
+ lineFirst--;
}
- ScrollToLine(lineFirstNew);
+ return lineFirst;
+}
-#ifdef __WXMAC__
- Update();
-#endif // __WXMAC__
+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
+ // the other ones
+ if ( fromRow < GetVisibleRowsBegin() )
+ fromRow = GetVisibleRowsBegin();
+
+ if ( toRow > GetVisibleRowsEnd() )
+ toRow = GetVisibleRowsEnd();
+
+ if ( fromColumn < GetVisibleColumnsBegin() )
+ fromColumn = GetVisibleColumnsBegin();
+
+ if ( toColumn > GetVisibleColumnsEnd() )
+ toColumn = GetVisibleColumnsEnd();
+
+ // calculate the rect occupied by these lines on screen
+ wxRect rect;
+ size_t nBefore, nBetween;
+
+ for ( nBefore = GetVisibleRowsBegin();
+ nBefore < fromRow;
+ nBefore++ )
+ {
+ rect.y += OnGetRowHeight(nBefore);
+ }
+
+ for ( nBetween = fromRow; nBetween <= toRow; nBetween++ )
+ {
+ rect.height += OnGetRowHeight(nBetween);
+ }
+
+ for ( nBefore = GetVisibleColumnsBegin();
+ nBefore < fromColumn;
+ nBefore++ )
+ {
+ rect.x += OnGetColumnWidth(nBefore);
+ }
+
+ for ( nBetween = fromColumn; nBetween <= toColumn; nBetween++ )
+ {
+ rect.width += OnGetColumnWidth(nBetween);
+ }
+
+ // do refresh it
+ RefreshRect(rect);
+}
+
+void wxHVScrolledWindow::RefreshAll()
+{
+ UpdateScrollbars();
+
+ Refresh();
+}
+
+bool wxHVScrolledWindow::Layout()
+{
+ if(GetSizer() && m_physicalScrolling)
+ {
+ // 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;
+ }
+
+ // 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++ )
+ {
+ y -= OnGetRowHeight(row);
+ if ( y < 0 )
+ hit.y = row;
+ }
+
+ for ( size_t column = GetVisibleColumnsBegin();
+ column <= columnMax;
+ column++ )
+ {
+ x -= OnGetColumnWidth(column);
+ if ( x < 0 )
+ hit.x = column;
+ }
+
+ return hit;
+}
+
+// ----------------------------------------------------------------------------
+// scrolling
+// ----------------------------------------------------------------------------
+
+bool wxHVScrolledWindow::ScrollToRowColumn(size_t row, size_t column)
+{
+ 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;
+}
+
+bool wxHVScrolledWindow::ScrollToRow(size_t row)
+{
+ 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;
+}
+
+bool wxHVScrolledWindow::ScrollToColumn(size_t column)
+{
+ 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 wxHVScrolledWindow::ScrollRows(int rows)
+{
+ rows += m_rowsFirst;
+ if ( rows < 0 )
+ rows = 0;
+
+ return ScrollToRow(rows);
+}
+
+bool wxHVScrolledWindow::ScrollColumns(int columns)
+{
+ columns += m_columnsFirst;
+ if ( columns < 0 )
+ columns = 0;
+
+ return ScrollToColumn(columns);
+}
+
+bool wxHVScrolledWindow::ScrollRowsColumns(int rows, int columns)
+{
+ rows += m_rowsFirst;
+ if ( rows < 0 )
+ rows = 0;
+
+ columns += m_columnsFirst;
+ if ( columns < 0 )
+ columns = 0;
+
+ return ScrollToRowColumn(rows, columns);
+}
+
+bool wxHVScrolledWindow::ScrollRowPages(int pages)
+{
+ bool didSomething = false;
+
+ while ( pages )
+ {
+ int line;
+ if ( pages > 0 )
+ {
+ line = GetVisibleRowsEnd();
+ if ( line )
+ line--;
+ pages--;
+ }
+ else // pages < 0
+ {
+ line = FindFirstFromBottom(GetVisibleRowsEnd());
+ pages++;
+ }
+
+ didSomething = ScrollToRow(line);
+ }
+
+ return didSomething;
+}
+
+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++;
+ }
+
+ didSomething = ScrollToColumn(line);
+ }
+
+ return didSomething;
+}
+
+bool wxHVScrolledWindow::ScrollPages(int rowPages, int columnPages)
+{
+ bool didSomething = false;
+
+ while ( rowPages )
+ {
+ int line;
+ if ( rowPages > 0 )
+ {
+ line = GetVisibleRowsEnd();
+ if ( line )
+ line--;
+ rowPages--;
+ }
+ else // rowPages < 0
+ {
+ line = FindFirstFromBottom(GetVisibleRowsBegin());
+ rowPages++;
+ }
+
+ didSomething = ScrollToRow(line);
+ }
+
+ while ( columnPages )
+ {
+ int line;
+ if ( columnPages > 0 )
+ {
+ line = GetVisibleColumnsEnd();
+ if ( line )
+ line--;
+ columnPages--;
+ }
+ else // columnPages < 0
+ {
+ line = FindFirstFromRight(GetVisibleColumnsBegin());
+ columnPages++;
+ }
+
+ didSomething |= ScrollToColumn(line);
+ }
+
+ return didSomething;
+}
+
+// ----------------------------------------------------------------------------
+// event handling
+// ----------------------------------------------------------------------------
+
+void wxHVScrolledWindow::OnSize(wxSizeEvent& event)
+{
+ UpdateScrollbars();
+ Layout();
+
+ event.Skip();
+}
+
+void wxHVScrolledWindow::OnScroll(wxScrollWinEvent& event)
+{
+ 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)
+{
+ 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;
+
+ if ( !event.IsPageScroll() )
+ ScrollRows( units_to_scroll*event.GetLinesPerAction() );
+ else
+ // scroll pages instead of lines
+ ScrollRowPages( units_to_scroll );
}
+#endif