]> git.saurik.com Git - wxWidgets.git/blame - src/generic/vscroll.cpp
Added headers that didn't get installed.
[wxWidgets.git] / src / generic / vscroll.cpp
CommitLineData
cf7d6329
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/vscroll.cpp
3// Purpose: wxVScrolledWindow implementation
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 30.05.03
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
36758fc6 20#if defined(__GNUG__) && !defined(__APPLE__)
687dcff3
VS
21#pragma implementation "vscroll.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
cf7d6329
VZ
31#include "wx/vscroll.h"
32
33// ----------------------------------------------------------------------------
34// event tables
35// ----------------------------------------------------------------------------
36
37BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel)
38 EVT_SIZE(wxVScrolledWindow::OnSize)
39 EVT_SCROLLWIN(wxVScrolledWindow::OnScroll)
40END_EVENT_TABLE()
41
42
43// ============================================================================
44// implementation
45// ============================================================================
46
47// ----------------------------------------------------------------------------
48// initialization
49// ----------------------------------------------------------------------------
50
51void wxVScrolledWindow::Init()
52{
53 // we're initially empty
54 m_lineMax =
55 m_lineFirst = 0;
56
57 // this one should always be strictly positive
58 m_nVisible = 1;
59
60 m_heightTotal = 0;
61}
62
63// ----------------------------------------------------------------------------
64// various helpers
65// ----------------------------------------------------------------------------
66
1e0af0bc
VZ
67wxCoord wxVScrolledWindow::EstimateTotalHeight() const
68{
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;
74
75 wxCoord heightTotal;
76 if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE )
77 {
78 // in this case calculating exactly is faster and more correct than
79 // guessing
80 heightTotal = GetLinesHeight(0, m_lineMax);
81 }
82 else // too many lines to calculate exactly
83 {
84 // look at some lines in the beginning/middle/end
85 heightTotal =
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);
90
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);
94 }
95
96 return heightTotal;
97}
98
cf7d6329
VZ
99wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const
100{
101 if ( lineMin == lineMax )
102 return 0;
103 else if ( lineMin > lineMax )
104 return -GetLinesHeight(lineMax, lineMin);
105 //else: lineMin < lineMax
106
107 // let the user code know that we're going to need all these lines
108 OnGetLinesHint(lineMin, lineMax);
109
110 // do sum up their heights
111 wxCoord height = 0;
112 for ( size_t line = lineMin; line < lineMax; line++ )
113 {
114 height += OnGetLineHeight(line);
115 }
116
117 return height;
118}
119
0b49ccf8 120size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full)
cf7d6329
VZ
121{
122 const wxCoord hWindow = GetClientSize().y;
123
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;
127 wxCoord h = 0;
128 for ( ;; )
129 {
130 h += OnGetLineHeight(lineFirst);
131
132 if ( h > hWindow )
133 {
0b49ccf8
VZ
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
137 if ( full )
138 {
139 lineFirst++;
140 }
cf7d6329
VZ
141
142 break;
143 }
144
145 if ( !lineFirst )
146 break;
147
148 lineFirst--;
149 }
150
151 return lineFirst;
152}
153
154void wxVScrolledWindow::UpdateScrollbar()
155{
156 // see how many lines can we fit on screen
157 const wxCoord hWindow = GetClientSize().y;
158
159 wxCoord h = 0;
160 size_t line;
161 for ( line = m_lineFirst; line < m_lineMax; line++ )
162 {
163 if ( h > hWindow )
164 break;
165
166 h += OnGetLineHeight(line);
167 }
168
169 m_nVisible = line - m_lineFirst;
170
171 int pageSize = m_nVisible;
172 if ( h > hWindow )
173 {
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
177 pageSize--;
178 }
179
180 // set the scrollbar parameters to reflect this
181 SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax);
182}
183
184// ----------------------------------------------------------------------------
185// operations
186// ----------------------------------------------------------------------------
187
188void wxVScrolledWindow::SetLineCount(size_t count)
189{
190 // save the number of lines
191 m_lineMax = count;
192
1e0af0bc
VZ
193 // and our estimate for their total height
194 m_heightTotal = EstimateTotalHeight();
cf7d6329
VZ
195
196 // recalculate the scrollbars parameters
e0c6027b 197 m_lineFirst = 1; // make sure it is != 0
cf7d6329
VZ
198 ScrollToLine(0);
199}
200
e0c6027b
VZ
201void wxVScrolledWindow::RefreshLine(size_t line)
202{
203 // is this line visible?
204 if ( !IsVisible(line) )
205 {
206 // no, it is useless to do anything
207 return;
208 }
209
210 // calculate the rect occupied by this line on screen
211 wxRect rect;
212 rect.width = GetClientSize().x;
213 rect.height = OnGetLineHeight(line);
214 for ( size_t n = GetFirstVisibleLine(); n < line; n++ )
215 {
216 rect.y += OnGetLineHeight(n);
217 }
ae0f0223
VZ
218
219 // do refresh it
220 RefreshRect(rect);
221}
222
223void wxVScrolledWindow::RefreshLines(size_t from, size_t to)
224{
225 wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") );
226
227 // clump the range to just the visible lines -- it is useless to refresh
228 // the other ones
229 if ( from < GetFirstVisibleLine() )
230 from = GetFirstVisibleLine();
231
232 if ( to > GetLastVisibleLine() )
233 to = GetLastVisibleLine();
234
235 // calculate the rect occupied by these lines on screen
236 wxRect rect;
237 rect.width = GetClientSize().x;
238 for ( size_t nBefore = GetFirstVisibleLine(); nBefore < from; nBefore++ )
239 {
240 rect.y += OnGetLineHeight(nBefore);
241 }
242
33a03749 243 for ( size_t nBetween = from; nBetween <= to; nBetween++ )
ae0f0223
VZ
244 {
245 rect.height += OnGetLineHeight(nBetween);
246 }
e0c6027b
VZ
247
248 // do refresh it
249 RefreshRect(rect);
250}
251
8b053348
VZ
252void wxVScrolledWindow::RefreshAll()
253{
254 UpdateScrollbar();
255
256 Refresh();
257}
258
e0c6027b
VZ
259int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const
260{
261 const size_t lineMax = GetLastVisibleLine();
262 for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ )
263 {
264 y -= OnGetLineHeight(line);
265 if ( y < 0 )
266 return line;
267 }
268
269 return wxNOT_FOUND;
270}
271
cf7d6329
VZ
272// ----------------------------------------------------------------------------
273// scrolling
274// ----------------------------------------------------------------------------
275
276bool wxVScrolledWindow::ScrollToLine(size_t line)
277{
278 if ( !m_lineMax )
279 {
280 // we're empty, code below doesn't make sense in this case
281 return false;
282 }
283
284 // determine the real first line to scroll to: we shouldn't scroll beyond
285 // the end
0b49ccf8 286 size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true);
cf7d6329
VZ
287 if ( line > lineFirstLast )
288 line = lineFirstLast;
289
290 // anything to do?
291 if ( line == m_lineFirst )
292 {
293 // no
294 return false;
295 }
296
297
298 // remember the currently shown lines for the refresh code below
299 size_t lineFirstOld = GetFirstVisibleLine(),
300 lineLastOld = GetLastVisibleLine();
301
302 m_lineFirst = line;
303
304
305 // the size of scrollbar thumb could have changed
306 UpdateScrollbar();
307
308
309 // finally refresh the display -- but only redraw as few lines as possible
310 // to avoid flicker
311 if ( GetFirstVisibleLine() > lineLastOld ||
312 GetLastVisibleLine() < lineFirstOld )
313 {
314 // the simplest case: we don't have any old lines left, just redraw
315 // everything
316 Refresh();
317 }
318 else // overlap between the lines we showed before and should show now
319 {
320 ScrollWindow(0, GetLinesHeight(GetFirstVisibleLine(), lineFirstOld));
321 }
322
323 return true;
324}
325
326bool wxVScrolledWindow::ScrollLines(int lines)
327{
328 lines += m_lineFirst;
329 if ( lines < 0 )
330 lines = 0;
331
332 return ScrollToLine(lines);
333}
334
335bool wxVScrolledWindow::ScrollPages(int pages)
336{
337 bool didSomething = false;
338
339 while ( pages )
340 {
341 int line;
342 if ( pages > 0 )
343 {
344 line = GetLastVisibleLine();
345 pages--;
346 }
347 else // pages < 0
348 {
349 line = FindFirstFromBottom(GetFirstVisibleLine());
350 pages++;
351 }
352
353 didSomething = ScrollToLine(line);
354 }
355
356 return didSomething;
357}
358
359// ----------------------------------------------------------------------------
360// event handling
361// ----------------------------------------------------------------------------
362
363void wxVScrolledWindow::OnSize(wxSizeEvent& event)
364{
365 UpdateScrollbar();
366
367 event.Skip();
368}
369
370void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event)
371{
372 size_t lineFirstNew;
373
374 const wxEventType evtType = event.GetEventType();
375 if ( evtType == wxEVT_SCROLLWIN_TOP )
376 {
377 lineFirstNew = 0;
378 }
379 else if ( evtType == wxEVT_SCROLLWIN_BOTTOM )
380 {
381 lineFirstNew = m_lineMax;
382 }
383 else if ( evtType == wxEVT_SCROLLWIN_LINEUP )
384 {
385 lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0;
386 }
387 else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN )
388 {
389 lineFirstNew = m_lineFirst + 1;
390 }
391 else if ( evtType == wxEVT_SCROLLWIN_PAGEUP )
392 {
393 lineFirstNew = FindFirstFromBottom(m_lineFirst);
394 }
395 else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
396 {
397 lineFirstNew = GetLastVisibleLine();
398 }
399 else // unknown scroll event?
400 {
401 if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
402 {
403 lineFirstNew = event.GetPosition();
404 }
405 else
406 {
407 wxASSERT_MSG( evtType == wxEVT_SCROLLWIN_THUMBTRACK,
408 _T("unknown scroll event type?") );
409
410 // don't do anything, otherwise dragging the thumb around would
411 // be too slow
412 return;
413 }
414 }
415
416 ScrollToLine(lineFirstNew);
b544a278
VZ
417
418#ifdef __WXMAC__
419 Update();
420#endif // __WXMAC__
cf7d6329
VZ
421}
422