1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/vscroll.cpp
3 // Purpose: wxVScrolledWindow implementation
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(__APPLE__)
21 #pragma implementation "vscroll.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
31 #include "wx/vscroll.h"
33 // ----------------------------------------------------------------------------
35 // ----------------------------------------------------------------------------
37 BEGIN_EVENT_TABLE(wxVScrolledWindow
, wxPanel
)
38 EVT_SIZE(wxVScrolledWindow::OnSize
)
39 EVT_SCROLLWIN(wxVScrolledWindow::OnScroll
)
43 // ============================================================================
45 // ============================================================================
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 void wxVScrolledWindow::Init()
53 // we're initially empty
57 // this one should always be strictly positive
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 wxCoord
wxVScrolledWindow::EstimateTotalHeight() const
69 // estimate the total height: it is impossible to call
70 // OnGetLineHeight() for every line because there may be too many of
71 // them, so we just make a guess using some lines in the beginning,
72 // some in the end and some in the middle
73 static const size_t NUM_LINES_TO_SAMPLE
= 10;
76 if ( m_lineMax
< 3*NUM_LINES_TO_SAMPLE
)
78 // in this case calculating exactly is faster and more correct than
80 heightTotal
= GetLinesHeight(0, m_lineMax
);
82 else // too many lines to calculate exactly
84 // look at some lines in the beginning/middle/end
86 GetLinesHeight(0, NUM_LINES_TO_SAMPLE
) +
87 GetLinesHeight(m_lineMax
- NUM_LINES_TO_SAMPLE
, m_lineMax
) +
88 GetLinesHeight(m_lineMax
/2 - NUM_LINES_TO_SAMPLE
/2,
89 m_lineMax
/2 + NUM_LINES_TO_SAMPLE
/2);
91 // use the height of the lines we looked as the average
92 heightTotal
= (wxCoord
)
93 (((float)m_heightTotal
/ (3*NUM_LINES_TO_SAMPLE
)) * m_lineMax
);
99 wxCoord
wxVScrolledWindow::GetLinesHeight(size_t lineMin
, size_t lineMax
) const
101 if ( lineMin
== lineMax
)
103 else if ( lineMin
> lineMax
)
104 return -GetLinesHeight(lineMax
, lineMin
);
105 //else: lineMin < lineMax
107 // let the user code know that we're going to need all these lines
108 OnGetLinesHint(lineMin
, lineMax
);
110 // do sum up their heights
112 for ( size_t line
= lineMin
; line
< lineMax
; line
++ )
114 height
+= OnGetLineHeight(line
);
120 size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast
, bool full
)
122 const wxCoord hWindow
= GetClientSize().y
;
124 // go upwards until we arrive at a line such that lineLast is not visible
125 // any more when it is shown
126 size_t lineFirst
= lineLast
;
130 h
+= OnGetLineHeight(lineFirst
);
134 // for this line to be fully visible we need to go one line
135 // down, but if it is enough for it to be only partly visible then
136 // this line will do as well
154 void wxVScrolledWindow::UpdateScrollbar()
156 // see how many lines can we fit on screen
157 const wxCoord hWindow
= GetClientSize().y
;
161 for ( line
= m_lineFirst
; line
< m_lineMax
; line
++ )
166 h
+= OnGetLineHeight(line
);
169 m_nVisible
= line
- m_lineFirst
;
171 int pageSize
= m_nVisible
;
174 // last line is only partially visible, we still need the scrollbar and
175 // so we have to "fix" pageSize because if it is equal to m_lineMax the
176 // scrollbar is not shown at all under MSW
180 // set the scrollbar parameters to reflect this
181 SetScrollbar(wxVERTICAL
, m_lineFirst
, pageSize
, m_lineMax
);
184 // ----------------------------------------------------------------------------
186 // ----------------------------------------------------------------------------
188 void wxVScrolledWindow::SetLineCount(size_t count
)
190 // save the number of lines
193 // and our estimate for their total height
194 m_heightTotal
= EstimateTotalHeight();
196 // recalculate the scrollbars parameters
197 m_lineFirst
= 1; // make sure it is != 0
201 void wxVScrolledWindow::RefreshLine(size_t line
)
203 // is this line visible?
204 if ( !IsVisible(line
) )
206 // no, it is useless to do anything
210 // calculate the rect occupied by this line on screen
212 rect
.width
= GetClientSize().x
;
213 rect
.height
= OnGetLineHeight(line
);
214 for ( size_t n
= GetFirstVisibleLine(); n
< line
; n
++ )
216 rect
.y
+= OnGetLineHeight(n
);
223 void wxVScrolledWindow::RefreshLines(size_t from
, size_t to
)
225 wxASSERT_MSG( from
<= to
, _T("RefreshLines(): empty range") );
227 // clump the range to just the visible lines -- it is useless to refresh
229 if ( from
< GetFirstVisibleLine() )
230 from
= GetFirstVisibleLine();
232 if ( to
> GetLastVisibleLine() )
233 to
= GetLastVisibleLine();
235 // calculate the rect occupied by these lines on screen
237 rect
.width
= GetClientSize().x
;
238 for ( size_t nBefore
= GetFirstVisibleLine(); nBefore
< from
; nBefore
++ )
240 rect
.y
+= OnGetLineHeight(nBefore
);
243 for ( size_t nBetween
= from
; nBetween
<= to
; nBetween
++ )
245 rect
.height
+= OnGetLineHeight(nBetween
);
252 void wxVScrolledWindow::RefreshAll()
259 int wxVScrolledWindow::HitTest(wxCoord
WXUNUSED(x
), wxCoord y
) const
261 const size_t lineMax
= GetLastVisibleLine();
262 for ( size_t line
= GetFirstVisibleLine(); line
<= lineMax
; line
++ )
264 y
-= OnGetLineHeight(line
);
272 // ----------------------------------------------------------------------------
274 // ----------------------------------------------------------------------------
276 bool wxVScrolledWindow::ScrollToLine(size_t line
)
280 // we're empty, code below doesn't make sense in this case
284 // determine the real first line to scroll to: we shouldn't scroll beyond
286 size_t lineFirstLast
= FindFirstFromBottom(m_lineMax
- 1, true);
287 if ( line
> lineFirstLast
)
288 line
= lineFirstLast
;
291 if ( line
== m_lineFirst
)
298 // remember the currently shown lines for the refresh code below
299 size_t lineFirstOld
= GetFirstVisibleLine(),
300 lineLastOld
= GetLastVisibleLine();
305 // the size of scrollbar thumb could have changed
309 // finally refresh the display -- but only redraw as few lines as possible
311 if ( GetFirstVisibleLine() > lineLastOld
||
312 GetLastVisibleLine() < lineFirstOld
)
314 // the simplest case: we don't have any old lines left, just redraw
318 else // overlap between the lines we showed before and should show now
320 ScrollWindow(0, GetLinesHeight(GetFirstVisibleLine(), lineFirstOld
));
326 bool wxVScrolledWindow::ScrollLines(int lines
)
328 lines
+= m_lineFirst
;
332 return ScrollToLine(lines
);
335 bool wxVScrolledWindow::ScrollPages(int pages
)
337 bool didSomething
= false;
344 line
= GetLastVisibleLine();
349 line
= FindFirstFromBottom(GetFirstVisibleLine());
353 didSomething
= ScrollToLine(line
);
359 // ----------------------------------------------------------------------------
361 // ----------------------------------------------------------------------------
363 void wxVScrolledWindow::OnSize(wxSizeEvent
& event
)
370 void wxVScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
374 const wxEventType evtType
= event
.GetEventType();
375 if ( evtType
== wxEVT_SCROLLWIN_TOP
)
379 else if ( evtType
== wxEVT_SCROLLWIN_BOTTOM
)
381 lineFirstNew
= m_lineMax
;
383 else if ( evtType
== wxEVT_SCROLLWIN_LINEUP
)
385 lineFirstNew
= m_lineFirst
? m_lineFirst
- 1 : 0;
387 else if ( evtType
== wxEVT_SCROLLWIN_LINEDOWN
)
389 lineFirstNew
= m_lineFirst
+ 1;
391 else if ( evtType
== wxEVT_SCROLLWIN_PAGEUP
)
393 lineFirstNew
= FindFirstFromBottom(m_lineFirst
);
395 else if ( evtType
== wxEVT_SCROLLWIN_PAGEDOWN
)
397 lineFirstNew
= GetLastVisibleLine();
399 else // unknown scroll event?
401 if ( evtType
== wxEVT_SCROLLWIN_THUMBRELEASE
)
403 lineFirstNew
= event
.GetPosition();
407 wxASSERT_MSG( evtType
== wxEVT_SCROLLWIN_THUMBTRACK
,
408 _T("unknown scroll event type?") );
410 // don't do anything, otherwise dragging the thumb around would
416 ScrollToLine(lineFirstNew
);