// headers
// ----------------------------------------------------------------------------
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "vscroll.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
#include "wx/vscroll.h"
// ----------------------------------------------------------------------------
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 )
return height;
}
-size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast)
+size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full)
{
const wxCoord hWindow = GetClientSize().y;
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;
}
// save the number of lines
m_lineMax = count;
+ // and our estimate for their total height
+ m_heightTotal = EstimateTotalHeight();
- // 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;
+ // recalculate the scrollbars parameters
+ m_lineFirst = 1; // make sure it is != 0
+ ScrollToLine(0);
+}
- if ( count < 3*NUM_LINES_TO_SAMPLE )
+void wxVScrolledWindow::RefreshLine(size_t line)
+{
+ // is this line visible?
+ if ( !IsVisible(line) )
{
- // in this case calculating exactly is faster and more correct than
- // guessing
- m_heightTotal = GetLinesHeight(0, m_lineMax);
+ // no, it is useless to do anything
+ return;
}
- else // too many lines to calculate exactly
+
+ // calculate the rect occupied by this line on screen
+ wxRect rect;
+ rect.width = GetClientSize().x;
+ rect.height = OnGetLineHeight(line);
+ for ( size_t n = GetFirstVisibleLine(); n < line; n++ )
{
- // 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);
+ rect.y += OnGetLineHeight(n);
+ }
- // use the height of the lines we looked as the average
- m_heightTotal = ((float)m_heightTotal / (3*NUM_LINES_TO_SAMPLE)) *
- m_lineMax;
+ // do refresh it
+ 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 < GetFirstVisibleLine() )
+ from = GetFirstVisibleLine();
+
+ if ( to > GetLastVisibleLine() )
+ to = GetLastVisibleLine();
+
+ // calculate the rect occupied by these lines on screen
+ wxRect rect;
+ rect.width = GetClientSize().x;
+ for ( size_t nBefore = GetFirstVisibleLine(); nBefore < from; nBefore++ )
+ {
+ rect.y += OnGetLineHeight(nBefore);
}
+ for ( size_t nBetween = from; nBetween <= to; nBetween++ )
+ {
+ rect.height += OnGetLineHeight(nBetween);
+ }
- // recalculate the scrollbars parameters
- ScrollToLine(0);
+ // do refresh it
+ RefreshRect(rect);
+}
+
+void wxVScrolledWindow::RefreshAll()
+{
+ UpdateScrollbar();
+
+ Refresh();
+}
+
+int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const
+{
+ const size_t lineMax = GetLastVisibleLine();
+ for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ )
+ {
+ y -= OnGetLineHeight(line);
+ if ( y < 0 )
+ return line;
+ }
+
+ return wxNOT_FOUND;
}
// ----------------------------------------------------------------------------
// 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;
size_t lineFirstNew;
const wxEventType evtType = event.GetEventType();
+
if ( evtType == wxEVT_SCROLLWIN_TOP )
{
lineFirstNew = 0;
{
lineFirstNew = GetLastVisibleLine();
}
- else // unknown scroll event?
+ else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
{
- if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
- {
- lineFirstNew = event.GetPosition();
- }
- else
- {
- wxASSERT_MSG( evtType == wxEVT_SCROLLWIN_THUMBTRACK,
- _T("unknown scroll event type?") );
+ lineFirstNew = event.GetPosition();
+ }
+ else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
+ {
+ lineFirstNew = event.GetPosition();
+ }
- // don't do anything, otherwise dragging the thumb around would
- // be too slow
- return;
- }
+ else // unknown scroll event?
+ {
+ 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