+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-1;
+
+ if(m_columnsFirst >= columnCount)
+ m_columnsFirst = columnCount-1;
+
+ if(m_rowsFirst < 0)
+ m_rowsFirst = 0;
+
+ if(m_columnsFirst < 0)
+ m_columnsFirst = 0;
+
+ 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(0, 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 );