]> git.saurik.com Git - wxWidgets.git/blame - src/generic/vscroll.cpp
make the string properly 0 terminated and allow for one char more on the output buffer
[wxWidgets.git] / src / generic / vscroll.cpp
CommitLineData
cf7d6329
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/vscroll.cpp
3// Purpose: wxVScrolledWindow implementation
4// Author: Vadim Zeitlin
d77836e4 5// Modified by: Brad Anderson
cf7d6329
VZ
6// Created: 30.05.03
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
65571936 9// Licence: wxWindows licence
cf7d6329
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
687dcff3
VS
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24#pragma hdrstop
25#endif
26
cf7d6329 27#include "wx/vscroll.h"
d77836e4
RR
28#include "wx/sizer.h"
29#include "wx/dc.h"
cf7d6329
VZ
30
31// ----------------------------------------------------------------------------
32// event tables
33// ----------------------------------------------------------------------------
34
35BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel)
36 EVT_SIZE(wxVScrolledWindow::OnSize)
37 EVT_SCROLLWIN(wxVScrolledWindow::OnScroll)
4719e58d
RD
38#if wxUSE_MOUSEWHEEL
39 EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel)
40#endif
cf7d6329
VZ
41END_EVENT_TABLE()
42
43
44// ============================================================================
45// implementation
46// ============================================================================
47
0c8392ca
RD
48IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel)
49
cf7d6329
VZ
50// ----------------------------------------------------------------------------
51// initialization
52// ----------------------------------------------------------------------------
53
54void wxVScrolledWindow::Init()
55{
56 // we're initially empty
57 m_lineMax =
58 m_lineFirst = 0;
59
60 // this one should always be strictly positive
61 m_nVisible = 1;
62
63 m_heightTotal = 0;
4719e58d
RD
64
65#if wxUSE_MOUSEWHEEL
66 m_sumWheelRotation = 0;
67#endif
cf7d6329
VZ
68}
69
70// ----------------------------------------------------------------------------
71// various helpers
72// ----------------------------------------------------------------------------
73
1e0af0bc
VZ
74wxCoord wxVScrolledWindow::EstimateTotalHeight() const
75{
76 // estimate the total height: it is impossible to call
77 // OnGetLineHeight() for every line because there may be too many of
78 // them, so we just make a guess using some lines in the beginning,
79 // some in the end and some in the middle
80 static const size_t NUM_LINES_TO_SAMPLE = 10;
81
82 wxCoord heightTotal;
83 if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE )
84 {
85 // in this case calculating exactly is faster and more correct than
86 // guessing
87 heightTotal = GetLinesHeight(0, m_lineMax);
88 }
89 else // too many lines to calculate exactly
90 {
91 // look at some lines in the beginning/middle/end
92 heightTotal =
93 GetLinesHeight(0, NUM_LINES_TO_SAMPLE) +
94 GetLinesHeight(m_lineMax - NUM_LINES_TO_SAMPLE, m_lineMax) +
95 GetLinesHeight(m_lineMax/2 - NUM_LINES_TO_SAMPLE/2,
96 m_lineMax/2 + NUM_LINES_TO_SAMPLE/2);
97
98 // use the height of the lines we looked as the average
99 heightTotal = (wxCoord)
999836aa 100 (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_lineMax);
1e0af0bc
VZ
101 }
102
103 return heightTotal;
104}
105
cf7d6329
VZ
106wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const
107{
108 if ( lineMin == lineMax )
109 return 0;
110 else if ( lineMin > lineMax )
111 return -GetLinesHeight(lineMax, lineMin);
112 //else: lineMin < lineMax
113
114 // let the user code know that we're going to need all these lines
115 OnGetLinesHint(lineMin, lineMax);
116
117 // do sum up their heights
118 wxCoord height = 0;
119 for ( size_t line = lineMin; line < lineMax; line++ )
120 {
121 height += OnGetLineHeight(line);
122 }
123
124 return height;
125}
126
0b49ccf8 127size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full)
cf7d6329
VZ
128{
129 const wxCoord hWindow = GetClientSize().y;
130
131 // go upwards until we arrive at a line such that lineLast is not visible
132 // any more when it is shown
133 size_t lineFirst = lineLast;
134 wxCoord h = 0;
135 for ( ;; )
136 {
137 h += OnGetLineHeight(lineFirst);
138
139 if ( h > hWindow )
140 {
0b49ccf8
VZ
141 // for this line to be fully visible we need to go one line
142 // down, but if it is enough for it to be only partly visible then
143 // this line will do as well
144 if ( full )
145 {
146 lineFirst++;
147 }
cf7d6329
VZ
148
149 break;
150 }
151
152 if ( !lineFirst )
153 break;
154
155 lineFirst--;
156 }
157
158 return lineFirst;
159}
160
161void wxVScrolledWindow::UpdateScrollbar()
162{
163 // see how many lines can we fit on screen
164 const wxCoord hWindow = GetClientSize().y;
165
166 wxCoord h = 0;
167 size_t line;
168 for ( line = m_lineFirst; line < m_lineMax; line++ )
169 {
170 if ( h > hWindow )
171 break;
172
173 h += OnGetLineHeight(line);
174 }
175
176 m_nVisible = line - m_lineFirst;
177
178 int pageSize = m_nVisible;
179 if ( h > hWindow )
180 {
181 // last line is only partially visible, we still need the scrollbar and
182 // so we have to "fix" pageSize because if it is equal to m_lineMax the
183 // scrollbar is not shown at all under MSW
184 pageSize--;
185 }
186
187 // set the scrollbar parameters to reflect this
188 SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax);
189}
190
191// ----------------------------------------------------------------------------
192// operations
193// ----------------------------------------------------------------------------
194
195void wxVScrolledWindow::SetLineCount(size_t count)
196{
197 // save the number of lines
198 m_lineMax = count;
199
1e0af0bc
VZ
200 // and our estimate for their total height
201 m_heightTotal = EstimateTotalHeight();
cf7d6329
VZ
202
203 // recalculate the scrollbars parameters
e0c6027b 204 m_lineFirst = 1; // make sure it is != 0
cf7d6329
VZ
205 ScrollToLine(0);
206}
207
e0c6027b
VZ
208void wxVScrolledWindow::RefreshLine(size_t line)
209{
210 // is this line visible?
211 if ( !IsVisible(line) )
212 {
213 // no, it is useless to do anything
214 return;
215 }
216
217 // calculate the rect occupied by this line on screen
218 wxRect rect;
219 rect.width = GetClientSize().x;
220 rect.height = OnGetLineHeight(line);
dd932cbe 221 for ( size_t n = GetVisibleBegin(); n < line; n++ )
e0c6027b
VZ
222 {
223 rect.y += OnGetLineHeight(n);
224 }
ae0f0223
VZ
225
226 // do refresh it
227 RefreshRect(rect);
228}
229
230void wxVScrolledWindow::RefreshLines(size_t from, size_t to)
231{
232 wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") );
233
234 // clump the range to just the visible lines -- it is useless to refresh
235 // the other ones
dd932cbe
VZ
236 if ( from < GetVisibleBegin() )
237 from = GetVisibleBegin();
ae0f0223 238
dd932cbe
VZ
239 if ( to >= GetVisibleEnd() )
240 to = GetVisibleEnd();
241 else
242 to++;
ae0f0223
VZ
243
244 // calculate the rect occupied by these lines on screen
245 wxRect rect;
246 rect.width = GetClientSize().x;
dd932cbe 247 for ( size_t nBefore = GetVisibleBegin(); nBefore < from; nBefore++ )
ae0f0223
VZ
248 {
249 rect.y += OnGetLineHeight(nBefore);
250 }
251
dd932cbe 252 for ( size_t nBetween = from; nBetween < to; nBetween++ )
ae0f0223
VZ
253 {
254 rect.height += OnGetLineHeight(nBetween);
255 }
e0c6027b
VZ
256
257 // do refresh it
258 RefreshRect(rect);
259}
260
8b053348
VZ
261void wxVScrolledWindow::RefreshAll()
262{
263 UpdateScrollbar();
264
265 Refresh();
266}
267
d77836e4
RR
268bool wxVScrolledWindow::Layout()
269{
270 if(GetSizer())
271 {
272 // adjust the sizer dimensions/position taking into account the
273 // virtual size and scrolled position of the window.
274
275 int y, w, h; // x is always 0 so no variable needed
276
277 y = -GetLinesHeight(0, GetFirstVisibleLine());
278 GetVirtualSize(&w, &h);
279 GetSizer()->SetDimension(0, y, w, h);
280 return true;
281 }
282
283 // fall back to default for LayoutConstraints
284 return wxPanel::Layout();
285}
286
e0c6027b
VZ
287int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const
288{
dd932cbe
VZ
289 const size_t lineMax = GetVisibleEnd();
290 for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
e0c6027b
VZ
291 {
292 y -= OnGetLineHeight(line);
293 if ( y < 0 )
294 return line;
295 }
296
297 return wxNOT_FOUND;
298}
299
cf7d6329
VZ
300// ----------------------------------------------------------------------------
301// scrolling
302// ----------------------------------------------------------------------------
303
304bool wxVScrolledWindow::ScrollToLine(size_t line)
305{
306 if ( !m_lineMax )
307 {
308 // we're empty, code below doesn't make sense in this case
309 return false;
310 }
311
312 // determine the real first line to scroll to: we shouldn't scroll beyond
313 // the end
0b49ccf8 314 size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true);
cf7d6329
VZ
315 if ( line > lineFirstLast )
316 line = lineFirstLast;
317
318 // anything to do?
319 if ( line == m_lineFirst )
320 {
321 // no
322 return false;
323 }
324
325
326 // remember the currently shown lines for the refresh code below
d77836e4 327 size_t lineFirstOld = GetVisibleBegin();
cf7d6329
VZ
328
329 m_lineFirst = line;
330
331
332 // the size of scrollbar thumb could have changed
333 UpdateScrollbar();
334
d77836e4
RR
335 // finally, scroll the actual window
336 ScrollWindow(0, GetLinesHeight(GetVisibleBegin(), lineFirstOld));
cf7d6329
VZ
337
338 return true;
339}
340
341bool wxVScrolledWindow::ScrollLines(int lines)
342{
343 lines += m_lineFirst;
344 if ( lines < 0 )
345 lines = 0;
346
347 return ScrollToLine(lines);
348}
349
350bool wxVScrolledWindow::ScrollPages(int pages)
351{
352 bool didSomething = false;
353
354 while ( pages )
355 {
356 int line;
357 if ( pages > 0 )
358 {
dd932cbe
VZ
359 line = GetVisibleEnd();
360 if ( line )
361 line--;
cf7d6329
VZ
362 pages--;
363 }
364 else // pages < 0
365 {
dd932cbe 366 line = FindFirstFromBottom(GetVisibleBegin());
cf7d6329
VZ
367 pages++;
368 }
369
370 didSomething = ScrollToLine(line);
371 }
372
373 return didSomething;
374}
375
376// ----------------------------------------------------------------------------
377// event handling
378// ----------------------------------------------------------------------------
379
380void wxVScrolledWindow::OnSize(wxSizeEvent& event)
381{
382 UpdateScrollbar();
383
384 event.Skip();
385}
386
387void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event)
388{
389 size_t lineFirstNew;
390
391 const wxEventType evtType = event.GetEventType();
5d2ad055 392
cf7d6329
VZ
393 if ( evtType == wxEVT_SCROLLWIN_TOP )
394 {
395 lineFirstNew = 0;
396 }
397 else if ( evtType == wxEVT_SCROLLWIN_BOTTOM )
398 {
399 lineFirstNew = m_lineMax;
400 }
401 else if ( evtType == wxEVT_SCROLLWIN_LINEUP )
402 {
403 lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0;
404 }
405 else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN )
406 {
407 lineFirstNew = m_lineFirst + 1;
408 }
409 else if ( evtType == wxEVT_SCROLLWIN_PAGEUP )
410 {
411 lineFirstNew = FindFirstFromBottom(m_lineFirst);
412 }
413 else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
414 {
dd932cbe
VZ
415 lineFirstNew = GetVisibleEnd();
416 if ( lineFirstNew )
417 lineFirstNew--;
cf7d6329 418 }
5d2ad055
RD
419 else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
420 {
421 lineFirstNew = event.GetPosition();
422 }
423 else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
424 {
425 lineFirstNew = event.GetPosition();
426 }
ca65c044 427
cf7d6329
VZ
428 else // unknown scroll event?
429 {
5d2ad055
RD
430 wxFAIL_MSG( _T("unknown scroll event type?") );
431 return;
cf7d6329
VZ
432 }
433
434 ScrollToLine(lineFirstNew);
b544a278
VZ
435
436#ifdef __WXMAC__
437 Update();
438#endif // __WXMAC__
cf7d6329
VZ
439}
440
4719e58d
RD
441#if wxUSE_MOUSEWHEEL
442
443void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event)
444{
445 m_sumWheelRotation += event.GetWheelRotation();
446 int delta = event.GetWheelDelta();
447
448 // how much to scroll this time
449 int units_to_scroll = -(m_sumWheelRotation/delta);
450 if ( !units_to_scroll )
451 return;
452
453 m_sumWheelRotation += units_to_scroll*delta;
454
455 if ( !event.IsPageScroll() )
456 ScrollLines( units_to_scroll*event.GetLinesPerAction() );
457 else
458 // scroll pages instead of lines
459 ScrollPages( units_to_scroll );
460}
461
462#endif
d77836e4
RR
463
464
465
466
467// ----------------------------------------------------------------------------
468// wxVarScrolled Window event tables
469// ----------------------------------------------------------------------------
470
471BEGIN_EVENT_TABLE(wxHVScrolledWindow, wxPanel)
472 EVT_SIZE(wxHVScrolledWindow::OnSize)
473 EVT_SCROLLWIN(wxHVScrolledWindow::OnScroll)
474#if wxUSE_MOUSEWHEEL
475 EVT_MOUSEWHEEL(wxHVScrolledWindow::OnMouseWheel)
476#endif
477END_EVENT_TABLE()
478
479
480// ============================================================================
481// wxVarScrolled implementation
482// ============================================================================
483
484IMPLEMENT_ABSTRACT_CLASS(wxHVScrolledWindow, wxPanel)
485
486// ----------------------------------------------------------------------------
487// initialization
488// ----------------------------------------------------------------------------
489
490void wxHVScrolledWindow::Init()
491{
492 // we're initially empty
493 m_rowsMax =
494 m_columnsMax =
555b2ce9 495 m_rowsFirst =
d77836e4
RR
496 m_columnsFirst = 0;
497
498 // these should always be strictly positive
499 m_nRowsVisible =
500 m_nColumnsVisible = 1;
501
502 m_widthTotal =
503 m_heightTotal = 0;
504
505 m_physicalScrolling = true;
506
507#if wxUSE_MOUSEWHEEL
508 m_sumWheelRotation = 0;
509#endif
510}
511
512// ----------------------------------------------------------------------------
513// various helpers
514// ----------------------------------------------------------------------------
515
516wxCoord wxHVScrolledWindow::EstimateTotalHeight() const
517{
518 // estimate the total height: it is impossible to call
519 // OnGetLineHeight() for every line because there may be too many of
520 // them, so we just make a guess using some lines in the beginning,
521 // some in the end and some in the middle
522 static const size_t NUM_LINES_TO_SAMPLE = 10;
523
524 wxCoord heightTotal;
525 if ( m_rowsMax < 3*NUM_LINES_TO_SAMPLE )
526 {
527 // in this case calculating exactly is faster and more correct than
528 // guessing
529 heightTotal = GetRowsHeight(0, m_rowsMax);
530 }
531 else // too many lines to calculate exactly
532 {
533 // look at some lines in the beginning/middle/end
534 heightTotal =
535 GetRowsHeight(0, NUM_LINES_TO_SAMPLE) +
536 GetRowsHeight(m_rowsMax - NUM_LINES_TO_SAMPLE,
537 m_rowsMax) +
538 GetRowsHeight(m_rowsMax/2 - NUM_LINES_TO_SAMPLE/2,
539 m_rowsMax/2 + NUM_LINES_TO_SAMPLE/2);
540
541 // use the height of the lines we looked as the average
542 heightTotal = (wxCoord)
543 (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_rowsMax);
544 }
545
546 return heightTotal;
547}
548
549wxCoord wxHVScrolledWindow::EstimateTotalWidth() const
550{
551 // estimate the total width: it is impossible to call
552 // OnGetLineWidth() for every line because there may be too many of
553 // them, so we just make a guess using some lines in the beginning,
554 // some in the end and some in the middle
555 static const size_t NUM_LINES_TO_SAMPLE = 10;
556
557 wxCoord widthTotal;
558 if ( m_columnsMax < 3*NUM_LINES_TO_SAMPLE )
559 {
560 // in this case calculating exactly is faster and more correct than
561 // guessing
562 widthTotal = GetColumnsWidth(0, m_columnsMax);
563 }
564 else // too many lines to calculate exactly
565 {
566 // look at some lines in the beginning/middle/end
567 widthTotal =
568 GetColumnsWidth(0, NUM_LINES_TO_SAMPLE) +
569 GetColumnsWidth(m_columnsMax - NUM_LINES_TO_SAMPLE,
570 m_columnsMax) +
571 GetColumnsWidth(m_columnsMax/2 - NUM_LINES_TO_SAMPLE/2,
572 m_columnsMax/2 + NUM_LINES_TO_SAMPLE/2);
573
574 // use the width of the lines we looked as the average
575 widthTotal = (wxCoord)
576 (((float)widthTotal / (3*NUM_LINES_TO_SAMPLE)) * m_columnsMax);
577 }
578
579 return widthTotal;
580}
581
582wxCoord wxHVScrolledWindow::GetRowsHeight(size_t rowMin, size_t rowMax) const
583{
584 if ( rowMin == rowMax )
585 return 0;
586 else if ( rowMin > rowMax )
587 return -GetRowsHeight(rowMax, rowMin);
588 //else: lineMin < lineMax
589
590 // let the user code know that we're going to need all these lines
591 OnGetRowsHeightHint(rowMin, rowMax);
592
593 // do sum up their heights
594 wxCoord height = 0;
595 for ( size_t row = rowMin; row < rowMax; row++ )
596 {
597 height += OnGetRowHeight(row);
598 }
599
600 return height;
601}
602
603wxCoord wxHVScrolledWindow::GetColumnsWidth(size_t columnMin, size_t columnMax) const
604{
605 if ( columnMin == columnMax )
606 return 0;
607 else if ( columnMin > columnMax )
608 return -GetColumnsWidth(columnMax, columnMin);
609 //else: lineMin < lineMax
610
611 // let the user code know that we're going to need all these lines
612 OnGetColumnsWidthHint(columnMin, columnMax);
613
614 // do sum up their widths
615 wxCoord width = 0;
616 for ( size_t column = columnMin; column < columnMax; column++ )
617 {
618 width += OnGetColumnWidth(column);
619 }
620
621 return width;
622}
623
624size_t wxHVScrolledWindow::FindFirstFromBottom(size_t rowLast, bool full)
625{
626 const wxCoord hWindow = GetClientSize().y;
627
628 // go upwards until we arrive at a line such that lineLast is not visible
629 // any more when it is shown
630 size_t lineFirst = rowLast;
631 wxCoord h = 0;
632 for ( ;; )
633 {
634 h += OnGetRowHeight(lineFirst);
635
636 if ( h > hWindow )
637 {
638 // for this line to be fully visible we need to go one line
639 // down, but if it is enough for it to be only partly visible then
640 // this line will do as well
641 if ( full )
642 {
643 lineFirst++;
644 }
645
646 break;
647 }
648
649 if ( !lineFirst )
650 break;
651
652 lineFirst--;
653 }
654
655 return lineFirst;
656}
657
658size_t wxHVScrolledWindow::FindFirstFromRight(size_t columnLast, bool full)
659{
660 const wxCoord wWindow = GetClientSize().x;
661
662 // go upwards until we arrive at a line such that lineLast is not visible
663 // any more when it is shown
664 size_t lineFirst = columnLast;
665 wxCoord w = 0;
666 for ( ;; )
667 {
668 w += OnGetColumnWidth(lineFirst);
669
670 if ( w > wWindow )
671 {
672 // for this line to be fully visible we need to go one line
673 // down, but if it is enough for it to be only partly visible then
674 // this line will do as well
675 if ( full )
676 {
677 lineFirst++;
678 }
679
680 break;
681 }
682
683 if ( !lineFirst )
684 break;
685
686 lineFirst--;
687 }
688
689 return lineFirst;
690}
691
692void wxHVScrolledWindow::UpdateScrollbars()
693{
694 // see how many lines can we fit on screen (on both axes)
695 const wxCoord wWindow = GetClientSize().x;
696 const wxCoord hWindow = GetClientSize().y;
697
698 // first do the horizontal calculations
699 wxCoord w = 0;
700 size_t column;
701 for ( column = m_columnsFirst; column < m_columnsMax; column++ )
702 {
703 if ( w > wWindow )
704 break;
705
706 w += OnGetColumnWidth(column);
707 }
708
709 m_nColumnsVisible = column - m_columnsFirst;
710
711 int columnsPageSize = m_nColumnsVisible;
712 if ( w > wWindow )
713 {
714 // last line is only partially visible, we still need the scrollbar and
715 // so we have to "fix" pageSize because if it is equal to
716 // m_horizLineMax the scrollbar is not shown at all under MSW
717 columnsPageSize--;
718 }
719
720 // set the scrollbar parameters to reflect this
721 SetScrollbar(wxHORIZONTAL, m_columnsFirst, columnsPageSize, m_columnsMax);
722
723
724 // now do the vertical calculations
725 wxCoord h = 0;
726 size_t row;
727 for ( row = m_rowsFirst; row < m_rowsMax; row++ )
728 {
729 if ( h > hWindow )
730 break;
731
732 h += OnGetRowHeight(row);
733 }
734
735 m_nRowsVisible = row - m_rowsFirst;
736
737 int rowsPageSize = m_nRowsVisible;
738 if ( h > hWindow )
739 {
740 // last line is only partially visible, we still need the scrollbar and
741 // so we have to "fix" pageSize because if it is equal to m_vertLineMax
742 // the scrollbar is not shown at all under MSW
743 rowsPageSize--;
744 }
745
746 // set the scrollbar parameters to reflect this
747 SetScrollbar(wxVERTICAL, m_rowsFirst, rowsPageSize, m_rowsMax);
748}
749
750void wxHVScrolledWindow::PrepareDC(wxDC& dc)
751{
752 if(m_physicalScrolling)
753 {
754 dc.SetDeviceOrigin(-GetColumnsWidth(0, GetVisibleColumnsBegin()),
755 -GetRowsHeight(0, GetVisibleRowsBegin()));
756 }
757}
758
759// ----------------------------------------------------------------------------
760// operations
761// ----------------------------------------------------------------------------
762
763void wxHVScrolledWindow::SetRowColumnCounts(size_t rowCount, size_t columnCount)
764{
765 // save the number of lines
766 m_rowsMax = rowCount;
767 m_columnsMax = columnCount;
768
769 // and our estimate for their total height and width
770 m_heightTotal = EstimateTotalHeight();
771 m_widthTotal = EstimateTotalWidth();
555b2ce9 772
d77836e4
RR
773 // recalculate the scrollbars parameters
774 if(m_rowsFirst >= rowCount)
4bc6f7a0 775 m_rowsFirst = (rowCount > 0) ? rowCount - 1 : 0;
d77836e4
RR
776
777 if(m_columnsFirst >= columnCount)
4bc6f7a0 778 m_columnsFirst = (columnCount > 0) ? columnCount - 1 : 0;
555b2ce9 779
4bc6f7a0
WS
780#if 0
781 // checks disabled due to size_t type of members
782 // but leave them here if anyone would want to do some debugging
d77836e4
RR
783 if(m_rowsFirst < 0)
784 m_rowsFirst = 0;
555b2ce9 785
d77836e4
RR
786 if(m_columnsFirst < 0)
787 m_columnsFirst = 0;
4bc6f7a0 788#endif
d77836e4
RR
789
790 ScrollToRowColumn(m_rowsFirst, m_columnsFirst);
791}
792
793void wxHVScrolledWindow::RefreshColumn(size_t column)
794{
795 // is this line visible?
796 if ( !IsColumnVisible(column) )
797 {
798 // no, it is useless to do anything
799 return;
800 }
801
802 // calculate the rect occupied by this line on screen
803 wxRect rect;
804 rect.width = OnGetColumnWidth(column);
805 rect.height = GetClientSize().y;
806 for ( size_t n = GetVisibleColumnsBegin(); n < column; n++ )
807 {
808 rect.y += OnGetColumnWidth(n);
809 }
810
811 // do refresh it
812 RefreshRect(rect);
813}
814
815void wxHVScrolledWindow::RefreshRow(size_t row)
816{
817 // is this line visible?
818 if ( !IsRowVisible(row) )
819 {
820 // no, it is useless to do anything
821 return;
822 }
823
824 // calculate the rect occupied by this line on screen
825 wxRect rect;
826 rect.width = GetClientSize().x;
827 rect.height = OnGetRowHeight(row);
828 for ( size_t n = GetVisibleRowsBegin(); n < row; n++ )
829 {
830 rect.y += OnGetRowHeight(n);
831 }
832
833 // do refresh it
834 RefreshRect(rect);
835}
836
837void wxHVScrolledWindow::RefreshRowColumn(size_t row, size_t column)
838{
839 // is this line visible?
840 if ( !IsRowVisible(row) || !IsColumnVisible(column) )
841 {
842 // no, it is useless to do anything
843 return;
844 }
845
846 // calculate the rect occupied by this cell on screen
847 wxRect rect;
848 rect.height = OnGetRowHeight(row);
849 rect.width = OnGetColumnWidth(column);
850
555b2ce9
WS
851 size_t n;
852
853 for ( n = GetVisibleRowsBegin(); n < row; n++ )
d77836e4
RR
854 {
855 rect.y += OnGetRowHeight(n);
856 }
857
555b2ce9 858 for ( n = GetVisibleColumnsBegin(); n < column; n++ )
d77836e4
RR
859 {
860 rect.x += OnGetColumnWidth(n);
861 }
862
863 // do refresh it
864 RefreshRect(rect);
865}
866
867void wxHVScrolledWindow::RefreshRows(size_t from, size_t to)
868{
869 wxASSERT_MSG( from <= to, _T("RefreshRows(): empty range") );
870
871 // clump the range to just the visible lines -- it is useless to refresh
872 // the other ones
873 if ( from < GetVisibleRowsBegin() )
874 from = GetVisibleRowsBegin();
875
876 if ( to > GetVisibleRowsEnd() )
877 to = GetVisibleRowsEnd();
878
879 // calculate the rect occupied by these lines on screen
880 wxRect rect;
881 rect.width = GetClientSize().x;
882 for ( size_t nBefore = GetVisibleRowsBegin();
883 nBefore < from;
884 nBefore++ )
885 {
886 rect.y += OnGetRowHeight(nBefore);
887 }
888
889 for ( size_t nBetween = from; nBetween <= to; nBetween++ )
890 {
891 rect.height += OnGetRowHeight(nBetween);
892 }
893
894 // do refresh it
895 RefreshRect(rect);
896}
897
898void wxHVScrolledWindow::RefreshColumns(size_t from, size_t to)
899{
900 wxASSERT_MSG( from <= to, _T("RefreshColumns(): empty range") );
901
902 // clump the range to just the visible lines -- it is useless to refresh
903 // the other ones
904 if ( from < GetVisibleColumnsBegin() )
905 from = GetVisibleColumnsBegin();
906
907 if ( to > GetVisibleColumnsEnd() )
908 to = GetVisibleColumnsEnd();
909
910 // calculate the rect occupied by these lines on screen
911 wxRect rect;
912 rect.height = GetClientSize().y;
913 for ( size_t nBefore = GetVisibleColumnsBegin();
914 nBefore < from;
915 nBefore++ )
916 {
917 rect.x += OnGetColumnWidth(nBefore);
918 }
919
920 for ( size_t nBetween = from; nBetween <= to; nBetween++ )
921 {
922 rect.width += OnGetColumnWidth(nBetween);
923 }
924
925 // do refresh it
926 RefreshRect(rect);
927}
928
929void wxHVScrolledWindow::RefreshRowsColumns(size_t fromRow, size_t toRow,
930 size_t fromColumn, size_t toColumn)
931{
932 wxASSERT_MSG( fromRow <= toRow || fromColumn <= toColumn,
933 _T("RefreshRowsColumns(): empty range") );
934
935 // clump the range to just the visible lines -- it is useless to refresh
936 // the other ones
937 if ( fromRow < GetVisibleRowsBegin() )
938 fromRow = GetVisibleRowsBegin();
939
940 if ( toRow > GetVisibleRowsEnd() )
941 toRow = GetVisibleRowsEnd();
942
943 if ( fromColumn < GetVisibleColumnsBegin() )
944 fromColumn = GetVisibleColumnsBegin();
945
946 if ( toColumn > GetVisibleColumnsEnd() )
947 toColumn = GetVisibleColumnsEnd();
948
949 // calculate the rect occupied by these lines on screen
950 wxRect rect;
555b2ce9
WS
951 size_t nBefore, nBetween;
952
953 for ( nBefore = GetVisibleRowsBegin();
d77836e4
RR
954 nBefore < fromRow;
955 nBefore++ )
956 {
957 rect.y += OnGetRowHeight(nBefore);
958 }
959
555b2ce9 960 for ( nBetween = fromRow; nBetween <= toRow; nBetween++ )
d77836e4
RR
961 {
962 rect.height += OnGetRowHeight(nBetween);
963 }
964
555b2ce9 965 for ( nBefore = GetVisibleColumnsBegin();
d77836e4
RR
966 nBefore < fromColumn;
967 nBefore++ )
968 {
969 rect.x += OnGetColumnWidth(nBefore);
970 }
971
555b2ce9 972 for ( nBetween = fromColumn; nBetween <= toColumn; nBetween++ )
d77836e4
RR
973 {
974 rect.width += OnGetColumnWidth(nBetween);
975 }
976
977 // do refresh it
978 RefreshRect(rect);
979}
980
981void wxHVScrolledWindow::RefreshAll()
982{
983 UpdateScrollbars();
984
985 Refresh();
986}
987
988bool wxHVScrolledWindow::Layout()
989{
990 if(GetSizer() && m_physicalScrolling)
991 {
992 // adjust the sizer dimensions/position taking into account the
993 // virtual size and scrolled position of the window.
994
995 int x, y, w, h;
555b2ce9 996
d77836e4
RR
997 y = -GetRowsHeight(0, GetVisibleRowsBegin());
998 x = -GetColumnsWidth(0, GetVisibleColumnsBegin());
999 GetVirtualSize(&w, &h);
550eb91a 1000 GetSizer()->SetDimension(x, y, w, h);
d77836e4
RR
1001 return true;
1002 }
1003
1004 // fall back to default for LayoutConstraints
1005 return wxPanel::Layout();
1006}
1007
1008wxPoint wxHVScrolledWindow::HitTest(wxCoord x, wxCoord y) const
1009{
1010 const size_t rowMax = GetVisibleRowsEnd();
1011 const size_t columnMax = GetVisibleColumnsEnd();
1012
1013 wxPoint hit(wxNOT_FOUND, wxNOT_FOUND);
1014 for ( size_t row = GetVisibleRowsBegin();
1015 row <= rowMax;
1016 row++ )
1017 {
1018 y -= OnGetRowHeight(row);
1019 if ( y < 0 )
1020 hit.y = row;
1021 }
555b2ce9 1022
d77836e4
RR
1023 for ( size_t column = GetVisibleColumnsBegin();
1024 column <= columnMax;
1025 column++ )
1026 {
1027 x -= OnGetColumnWidth(column);
1028 if ( x < 0 )
1029 hit.x = column;
1030 }
1031
1032 return hit;
1033}
1034
1035// ----------------------------------------------------------------------------
1036// scrolling
1037// ----------------------------------------------------------------------------
1038
1039bool wxHVScrolledWindow::ScrollToRowColumn(size_t row, size_t column)
1040{
1041 if ( !m_rowsMax && !m_columnsMax )
1042 {
1043 // we're empty, code below doesn't make sense in this case
1044 return false;
1045 }
1046
1047 bool scrolled = false;
1048 scrolled |= ScrollToRow(row);
1049 scrolled |= ScrollToColumn(column);
1050
1051 return scrolled;
1052}
1053
1054bool wxHVScrolledWindow::ScrollToRow(size_t row)
1055{
1056 if ( !m_rowsMax )
1057 {
1058 // we're empty, code below doesn't make sense in this case
1059 return false;
1060 }
1061
1062 // determine the real first line to scroll to: we shouldn't scroll beyond
1063 // the end
1064 size_t lineFirstLast = FindFirstFromBottom(m_rowsMax - 1, true);
1065 if ( row > lineFirstLast )
1066 row = lineFirstLast;
555b2ce9 1067
d77836e4
RR
1068 // anything to do?
1069 if ( row == m_rowsFirst )
1070 {
1071 // no
1072 return false;
1073 }
1074
1075
1076 // remember the currently shown lines for the refresh code below
1077 size_t lineFirstOld = GetVisibleRowsBegin();
1078
1079 m_rowsFirst = row;
1080
1081
1082 // the size of scrollbar thumb could have changed
1083 UpdateScrollbars();
1084
1085
1086 // finally, scroll the actual window contents vertically
1087 if(m_physicalScrolling)
1088 ScrollWindow(0, GetRowsHeight(GetVisibleRowsBegin(), lineFirstOld));
555b2ce9 1089
d77836e4
RR
1090 return true;
1091}
1092
1093bool wxHVScrolledWindow::ScrollToColumn(size_t column)
1094{
1095 if ( !m_columnsMax )
1096 {
1097 // we're empty, code below doesn't make sense in this case
1098 return false;
1099 }
1100
1101 // determine the real first line to scroll to: we shouldn't scroll beyond
1102 // the end
1103 size_t lineFirstLast = FindFirstFromRight(m_columnsMax - 1, true);
1104 if ( column > lineFirstLast )
1105 column = lineFirstLast;
1106
1107 // anything to do?
1108 if ( column == m_columnsFirst )
1109 {
1110 // no
1111 return false;
1112 }
1113
1114
1115 // remember the currently shown lines for the refresh code below
1116 size_t lineFirstOld = GetVisibleColumnsBegin();
1117
1118 m_columnsFirst = column;
1119
1120
1121 // the size of scrollbar thumb could have changed
1122 UpdateScrollbars();
1123
1124 // finally, scroll the actual window contents horizontally
1125 if(m_physicalScrolling)
1126 ScrollWindow(GetColumnsWidth(GetVisibleColumnsBegin(), lineFirstOld), 0);
1127
1128 return true;
1129}
1130
1131bool wxHVScrolledWindow::ScrollRows(int rows)
1132{
1133 rows += m_rowsFirst;
1134 if ( rows < 0 )
1135 rows = 0;
1136
1137 return ScrollToRow(rows);
1138}
1139
1140bool wxHVScrolledWindow::ScrollColumns(int columns)
1141{
1142 columns += m_columnsFirst;
1143 if ( columns < 0 )
1144 columns = 0;
1145
1146 return ScrollToColumn(columns);
1147}
1148
1149bool wxHVScrolledWindow::ScrollRowsColumns(int rows, int columns)
1150{
1151 rows += m_rowsFirst;
1152 if ( rows < 0 )
1153 rows = 0;
1154
1155 columns += m_columnsFirst;
1156 if ( columns < 0 )
1157 columns = 0;
1158
1159 return ScrollToRowColumn(rows, columns);
1160}
1161
1162bool wxHVScrolledWindow::ScrollRowPages(int pages)
1163{
1164 bool didSomething = false;
1165
1166 while ( pages )
1167 {
1168 int line;
1169 if ( pages > 0 )
1170 {
1171 line = GetVisibleRowsEnd();
1172 if ( line )
1173 line--;
1174 pages--;
1175 }
1176 else // pages < 0
1177 {
1178 line = FindFirstFromBottom(GetVisibleRowsEnd());
1179 pages++;
1180 }
1181
1182 didSomething = ScrollToRow(line);
1183 }
1184
1185 return didSomething;
1186}
1187
1188bool wxHVScrolledWindow::ScrollColumnPages(int pages)
1189{
1190 bool didSomething = false;
1191
1192 while ( pages )
1193 {
1194 int line;
1195 if ( pages > 0 )
1196 {
1197 line = GetVisibleColumnsEnd();
1198 if ( line )
1199 line--;
1200 pages--;
1201 }
1202 else // pages < 0
1203 {
1204 line = FindFirstFromRight(GetVisibleColumnsEnd());
1205 pages++;
1206 }
1207
1208 didSomething = ScrollToColumn(line);
1209 }
1210
1211 return didSomething;
1212}
1213
1214bool wxHVScrolledWindow::ScrollPages(int rowPages, int columnPages)
1215{
1216 bool didSomething = false;
1217
1218 while ( rowPages )
1219 {
1220 int line;
1221 if ( rowPages > 0 )
1222 {
1223 line = GetVisibleRowsEnd();
1224 if ( line )
1225 line--;
1226 rowPages--;
1227 }
1228 else // rowPages < 0
1229 {
1230 line = FindFirstFromBottom(GetVisibleRowsBegin());
1231 rowPages++;
1232 }
1233
1234 didSomething = ScrollToRow(line);
1235 }
1236
1237 while ( columnPages )
1238 {
1239 int line;
1240 if ( columnPages > 0 )
1241 {
1242 line = GetVisibleColumnsEnd();
1243 if ( line )
1244 line--;
1245 columnPages--;
1246 }
1247 else // columnPages < 0
1248 {
1249 line = FindFirstFromRight(GetVisibleColumnsBegin());
1250 columnPages++;
1251 }
1252
1253 didSomething |= ScrollToColumn(line);
1254 }
1255
1256 return didSomething;
1257}
1258
1259// ----------------------------------------------------------------------------
1260// event handling
1261// ----------------------------------------------------------------------------
1262
1263void wxHVScrolledWindow::OnSize(wxSizeEvent& event)
1264{
1265 UpdateScrollbars();
1266 Layout();
1267
1268 event.Skip();
1269}
1270
1271void wxHVScrolledWindow::OnScroll(wxScrollWinEvent& event)
1272{
1273 if(event.GetOrientation() == wxHORIZONTAL)
1274 {
1275 size_t columnsFirstNew;
1276 const wxEventType evtType = event.GetEventType();
1277
1278 if ( evtType == wxEVT_SCROLLWIN_TOP )
1279 {
1280 columnsFirstNew = 0;
1281 }
1282 else if ( evtType == wxEVT_SCROLLWIN_BOTTOM )
1283 {
1284 columnsFirstNew = m_columnsMax;
1285 }
1286 else if ( evtType == wxEVT_SCROLLWIN_LINEUP )
1287 {
1288 columnsFirstNew = m_columnsFirst ? m_columnsFirst - 1 : 0;
1289 }
1290 else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN )
1291 {
1292 columnsFirstNew = m_columnsFirst + 1;
1293 }
1294 else if ( evtType == wxEVT_SCROLLWIN_PAGEUP )
1295 {
1296 columnsFirstNew = FindFirstFromRight(m_columnsFirst);
1297 }
1298 else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
1299 {
1300 columnsFirstNew = GetVisibleColumnsEnd();
1301 if ( columnsFirstNew )
1302 columnsFirstNew--;
1303 }
1304 else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
1305 {
1306 columnsFirstNew = event.GetPosition();
1307 }
1308 else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
1309 {
1310 columnsFirstNew = event.GetPosition();
1311 }
1312
1313 else // unknown scroll event?
1314 {
1315 wxFAIL_MSG( _T("unknown scroll event type?") );
1316 return;
1317 }
1318
1319 ScrollToColumn(columnsFirstNew);
1320 }
1321 else if(event.GetOrientation() == wxVERTICAL)
1322 {
1323 size_t rowsFirstNew;
1324 const wxEventType evtType = event.GetEventType();
1325
1326 if ( evtType == wxEVT_SCROLLWIN_TOP )
1327 {
1328 rowsFirstNew = 0;
1329 }
1330 else if ( evtType == wxEVT_SCROLLWIN_BOTTOM )
1331 {
1332 rowsFirstNew = m_rowsMax;
1333 }
1334 else if ( evtType == wxEVT_SCROLLWIN_LINEUP )
1335 {
1336 rowsFirstNew = m_rowsFirst ? m_rowsFirst - 1 : 0;
1337 }
1338 else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN )
1339 {
1340 rowsFirstNew = m_rowsFirst + 1;
1341 }
1342 else if ( evtType == wxEVT_SCROLLWIN_PAGEUP )
1343 {
1344 rowsFirstNew = FindFirstFromBottom(m_rowsFirst);
1345 }
1346 else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
1347 {
1348 rowsFirstNew = GetVisibleRowsEnd();
1349 if ( rowsFirstNew )
1350 rowsFirstNew--;
1351 }
1352 else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
1353 {
1354 rowsFirstNew = event.GetPosition();
1355 }
1356 else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
1357 {
1358 rowsFirstNew = event.GetPosition();
1359 }
1360
1361 else // unknown scroll event?
1362 {
1363 wxFAIL_MSG( _T("unknown scroll event type?") );
1364 return;
1365 }
1366
1367 ScrollToRow(rowsFirstNew);
1368 }
555b2ce9 1369
d77836e4
RR
1370
1371#ifdef __WXMAC__
1372 Update();
1373#endif // __WXMAC__
1374}
1375
1376#if wxUSE_MOUSEWHEEL
1377
1378void wxHVScrolledWindow::OnMouseWheel(wxMouseEvent& event)
1379{
1380 m_sumWheelRotation += event.GetWheelRotation();
1381 int delta = event.GetWheelDelta();
1382
1383 // how much to scroll this time
1384 int units_to_scroll = -(m_sumWheelRotation/delta);
1385 if ( !units_to_scroll )
1386 return;
1387
1388 m_sumWheelRotation += units_to_scroll*delta;
1389
1390 if ( !event.IsPageScroll() )
1391 ScrollRows( units_to_scroll*event.GetLinesPerAction() );
1392 else
1393 // scroll pages instead of lines
1394 ScrollRowPages( units_to_scroll );
1395}
1396
1397#endif