X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8b053348a5c2371c1347a935dfea7b3d314fab46..fac6eaec24736932770d26367b93c376a3f6d050:/src/generic/vscroll.cpp diff --git a/src/generic/vscroll.cpp b/src/generic/vscroll.cpp index 5d2ccf0cb6..cee98cef45 100644 --- a/src/generic/vscroll.cpp +++ b/src/generic/vscroll.cpp @@ -2,7 +2,7 @@ // Name: src/generic/vscroll.cpp // Purpose: wxVScrolledWindow implementation // Author: Vadim Zeitlin -// Modified by: +// Modified by: Brad Anderson // Created: 30.05.03 // RCS-ID: $Id$ // Copyright: (c) 2003 Vadim Zeitlin @@ -17,7 +17,16 @@ // 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 @@ -26,6 +35,9 @@ BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel) EVT_SIZE(wxVScrolledWindow::OnSize) EVT_SCROLLWIN(wxVScrolledWindow::OnScroll) +#if wxUSE_MOUSEWHEEL + EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel) +#endif END_EVENT_TABLE() @@ -33,6 +45,8 @@ END_EVENT_TABLE() // implementation // ============================================================================ +IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel) + // ---------------------------------------------------------------------------- // initialization // ---------------------------------------------------------------------------- @@ -47,12 +61,48 @@ void wxVScrolledWindow::Init() 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 ) @@ -74,7 +124,7 @@ wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const return height; } -size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast) +size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full) { const wxCoord hWindow = GetClientSize().y; @@ -88,7 +138,13 @@ size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast) if ( h > hWindow ) { - lineFirst++; + // 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; } @@ -141,33 +197,8 @@ void wxVScrolledWindow::SetLineCount(size_t count) // 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 @@ -187,7 +218,7 @@ void wxVScrolledWindow::RefreshLine(size_t line) 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); } @@ -196,6 +227,37 @@ void wxVScrolledWindow::RefreshLine(size_t line) RefreshRect(rect); } +void wxVScrolledWindow::RefreshLines(size_t from, size_t to) +{ + wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") ); + + // clump the range to just the visible lines -- it is useless to refresh + // the other ones + if ( from < GetVisibleBegin() ) + from = GetVisibleBegin(); + + 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++ ) + { + rect.y += OnGetLineHeight(nBefore); + } + + for ( size_t nBetween = from; nBetween < to; nBetween++ ) + { + rect.height += OnGetLineHeight(nBetween); + } + + // do refresh it + RefreshRect(rect); +} + void wxVScrolledWindow::RefreshAll() { UpdateScrollbar(); @@ -203,10 +265,29 @@ void wxVScrolledWindow::RefreshAll() 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 ) @@ -230,7 +311,7 @@ bool wxVScrolledWindow::ScrollToLine(size_t line) // determine the real first line to scroll to: we shouldn't scroll beyond // the end - size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1); + size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true); if ( line > lineFirstLast ) line = lineFirstLast; @@ -243,8 +324,7 @@ bool wxVScrolledWindow::ScrollToLine(size_t line) // remember the currently shown lines for the refresh code below - size_t lineFirstOld = GetFirstVisibleLine(), - lineLastOld = GetLastVisibleLine(); + size_t lineFirstOld = GetVisibleBegin(); m_lineFirst = line; @@ -252,20 +332,8 @@ bool wxVScrolledWindow::ScrollToLine(size_t 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; } @@ -288,12 +356,14 @@ bool wxVScrolledWindow::ScrollPages(int pages) int line; if ( pages > 0 ) { - line = GetLastVisibleLine(); + line = GetVisibleEnd(); + if ( line ) + line--; pages--; } else // pages < 0 { - line = FindFirstFromBottom(GetFirstVisibleLine()); + line = FindFirstFromBottom(GetVisibleBegin()); pages++; } @@ -319,6 +389,7 @@ void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) size_t lineFirstNew; const wxEventType evtType = event.GetEventType(); + if ( evtType == wxEVT_SCROLLWIN_TOP ) { lineFirstNew = 0; @@ -341,29 +412,986 @@ void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) } 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