The great wxVScrolledWindow refactoring: allow using it both horizontal and
[wxWidgets.git] / src / generic / vscroll.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/vscroll.cpp
3 // Purpose: wxVScrolledWindow implementation
4 // Author: Vadim Zeitlin
5 // Modified by: Brad Anderson
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
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/sizer.h"
29 #endif
30
31 #include "wx/vscroll.h"
32
33 // ============================================================================
34 // wxVarScrollHelperEvtHandler declaration
35 // ============================================================================
36
37 // ----------------------------------------------------------------------------
38 // wxScrollHelperEvtHandler: intercept the events from the window and forward
39 // them to wxVarScrollHelperBase
40 // ----------------------------------------------------------------------------
41
42 class WXDLLEXPORT wxVarScrollHelperEvtHandler : public wxEvtHandler
43 {
44 public:
45 wxVarScrollHelperEvtHandler(wxVarScrollHelperBase *scrollHelper)
46 {
47 m_scrollHelper = scrollHelper;
48 }
49
50 virtual bool ProcessEvent(wxEvent& event);
51
52 private:
53 wxVarScrollHelperBase *m_scrollHelper;
54
55 DECLARE_NO_COPY_CLASS(wxVarScrollHelperEvtHandler)
56 };
57
58 // ============================================================================
59 // wxVarScrollHelperEvtHandler implementation
60 // ============================================================================
61
62 bool wxVarScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
63 {
64 wxEventType evType = event.GetEventType();
65
66 // pass it on to the real handler
67 bool processed = wxEvtHandler::ProcessEvent(event);
68
69 // always process the size events ourselves, even if the user code handles
70 // them as well, as we need to AdjustScrollbars()
71 //
72 // NB: it is important to do it after processing the event in the normal
73 // way as HandleOnSize() may generate a wxEVT_SIZE itself if the
74 // scrollbar[s] (dis)appear and it should be seen by the user code
75 // after this one
76 if ( evType == wxEVT_SIZE )
77 {
78 m_scrollHelper->HandleOnSize((wxSizeEvent &)event);
79
80 return !event.GetSkipped();
81 }
82
83 if ( processed )
84 {
85 // normally, nothing more to do here - except if we have a command
86 // event
87 if ( event.IsCommandEvent() )
88 {
89 return true;
90 }
91 }
92
93 // reset the skipped flag (which might have been set to true in
94 // ProcessEvent() above) to be able to test it below
95 bool wasSkipped = event.GetSkipped();
96 if ( wasSkipped )
97 event.Skip(false);
98
99 // reset the skipped flag to false as it might have been set to true in
100 // ProcessEvent() above
101 event.Skip(false);
102
103 if ( evType == wxEVT_SCROLLWIN_TOP ||
104 evType == wxEVT_SCROLLWIN_BOTTOM ||
105 evType == wxEVT_SCROLLWIN_LINEUP ||
106 evType == wxEVT_SCROLLWIN_LINEDOWN ||
107 evType == wxEVT_SCROLLWIN_PAGEUP ||
108 evType == wxEVT_SCROLLWIN_PAGEDOWN ||
109 evType == wxEVT_SCROLLWIN_THUMBTRACK ||
110 evType == wxEVT_SCROLLWIN_THUMBRELEASE )
111 {
112 m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event);
113 if ( !event.GetSkipped() )
114 {
115 // it makes sense to indicate that we processed the message as we
116 // did scroll the window (and also notice that wxAutoScrollTimer
117 // relies on our return value for continuous scrolling)
118 processed = true;
119 wasSkipped = false;
120 }
121 }
122 #if wxUSE_MOUSEWHEEL
123 else if ( evType == wxEVT_MOUSEWHEEL )
124 {
125 m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event);
126 }
127 #endif // wxUSE_MOUSEWHEEL
128
129 if ( processed )
130 event.Skip(wasSkipped);
131
132 return processed;
133 }
134
135
136 // ============================================================================
137 // wxVarScrollHelperBase implementation
138 // ============================================================================
139
140 // ----------------------------------------------------------------------------
141 // wxVarScrollHelperBase initialization
142 // ----------------------------------------------------------------------------
143
144 wxVarScrollHelperBase::wxVarScrollHelperBase(wxWindow *win)
145 {
146 wxASSERT_MSG( win, _T("associated window can't be NULL in wxVarScrollHelperBase") );
147
148 #if wxUSE_MOUSEWHEEL
149 m_sumWheelRotation = 0;
150 #endif
151
152 m_unitMax = 0;
153 m_sizeTotal = 0;
154 m_unitFirst = 0;
155
156 m_win =
157 m_targetWindow = (wxWindow *)NULL;
158
159 m_handler = NULL;
160
161 m_win = win;
162
163 // by default, the associated window is also the target window
164 DoSetTargetWindow(win);
165
166 }
167
168 wxVarScrollHelperBase::~wxVarScrollHelperBase()
169 {
170 DeleteEvtHandler();
171 }
172
173 // ----------------------------------------------------------------------------
174 // wxVarScrollHelperBase various helpers
175 // ----------------------------------------------------------------------------
176
177 void
178 wxVarScrollHelperBase::AssignOrient(wxCoord& x,
179 wxCoord& y,
180 wxCoord first,
181 wxCoord second)
182 {
183 if ( GetOrientation() == wxVERTICAL )
184 {
185 x = first;
186 y = second;
187 }
188 else // horizontal
189 {
190 x = second;
191 y = first;
192 }
193 }
194
195 void
196 wxVarScrollHelperBase::IncOrient(wxCoord& x, wxCoord& y, wxCoord inc)
197 {
198 if ( GetOrientation() == wxVERTICAL )
199 y += inc;
200 else
201 x += inc;
202 }
203
204 wxCoord wxVarScrollHelperBase::DoEstimateTotalSize() const
205 {
206 // estimate the total height: it is impossible to call
207 // OnGetUnitSize() for every unit because there may be too many of
208 // them, so we just make a guess using some units in the beginning,
209 // some in the end and some in the middle
210 static const size_t NUM_UNITS_TO_SAMPLE = 10;
211
212 wxCoord sizeTotal;
213 if ( m_unitMax < 3*NUM_UNITS_TO_SAMPLE )
214 {
215 // in this case, full calculations are faster and more correct than
216 // guessing
217 sizeTotal = GetUnitsSize(0, m_unitMax);
218 }
219 else // too many units to calculate exactly
220 {
221 // look at some units in the beginning/middle/end
222 sizeTotal =
223 GetUnitsSize(0, NUM_UNITS_TO_SAMPLE) +
224 GetUnitsSize(m_unitMax - NUM_UNITS_TO_SAMPLE,
225 m_unitMax) +
226 GetUnitsSize(m_unitMax/2 - NUM_UNITS_TO_SAMPLE/2,
227 m_unitMax/2 + NUM_UNITS_TO_SAMPLE/2);
228
229 // use the height of the units we looked as the average
230 sizeTotal = (wxCoord)
231 (((float)sizeTotal / (3*NUM_UNITS_TO_SAMPLE)) * m_unitMax);
232 }
233
234 return sizeTotal;
235 }
236
237 wxCoord wxVarScrollHelperBase::GetUnitsSize(size_t unitMin, size_t unitMax) const
238 {
239 if ( unitMin == unitMax )
240 return 0;
241 else if ( unitMin > unitMax )
242 return -GetUnitsSize(unitMax, unitMin);
243 //else: unitMin < unitMax
244
245 // let the user code know that we're going to need all these units
246 OnGetUnitsSizeHint(unitMin, unitMax);
247
248 // sum up their sizes
249 wxCoord size = 0;
250 for ( size_t unit = unitMin; unit < unitMax; ++unit )
251 {
252 size += OnGetUnitSize(unit);
253 }
254
255 return size;
256 }
257
258 size_t wxVarScrollHelperBase::FindFirstVisibleFromLast(size_t unitLast, bool full) const
259 {
260 const wxCoord sWindow = GetOrientationTargetSize();
261
262 // go upwards until we arrive at a unit such that unitLast is not visible
263 // any more when it is shown
264 size_t unitFirst = unitLast;
265 wxCoord s = 0;
266 for ( ;; )
267 {
268 s += OnGetUnitSize(unitFirst);
269
270 if ( s > sWindow )
271 {
272 // for this unit to be fully visible we need to go one unit
273 // down, but if it is enough for it to be only partly visible then
274 // this unit will do as well
275 if ( full )
276 {
277 ++unitFirst;
278 }
279
280 break;
281 }
282
283 if ( !unitFirst )
284 break;
285
286 --unitFirst;
287 }
288
289 return unitFirst;
290 }
291
292 size_t wxVarScrollHelperBase::GetNewScrollPosition(wxScrollWinEvent& event) const
293 {
294 wxEventType evtType = event.GetEventType();
295
296 if ( evtType == wxEVT_SCROLLWIN_TOP )
297 {
298 return 0;
299 }
300 else if ( evtType == wxEVT_SCROLLWIN_BOTTOM )
301 {
302 return m_unitMax;
303 }
304 else if ( evtType == wxEVT_SCROLLWIN_LINEUP )
305 {
306 return m_unitFirst ? m_unitFirst - 1 : 0;
307 }
308 else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN )
309 {
310 return m_unitFirst + 1;
311 }
312 else if ( evtType == wxEVT_SCROLLWIN_PAGEUP )
313 {
314 return FindFirstVisibleFromLast(m_unitFirst);
315 }
316 else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN )
317 {
318 if ( GetVisibleEnd() )
319 return GetVisibleEnd() - 1;
320 else
321 return GetVisibleEnd();
322 }
323 else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE )
324 {
325 return event.GetPosition();
326 }
327 else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK )
328 {
329 return event.GetPosition();
330 }
331
332 // unknown scroll event?
333 wxFAIL_MSG( _T("unknown scroll event type?") );
334 return 0;
335 }
336
337 void wxVarScrollHelperBase::UpdateScrollbar()
338 {
339 // if there is nothing to scroll, remove the scrollbar
340 if ( !m_unitMax )
341 {
342 RemoveScrollbar();
343 return;
344 }
345
346 // see how many units can we fit on screen
347 const wxCoord sWindow = GetOrientationTargetSize();
348
349 // do vertical calculations
350 wxCoord s = 0;
351 size_t unit;
352 for ( unit = m_unitFirst; unit < m_unitMax; ++unit )
353 {
354 if ( s > sWindow )
355 break;
356
357 s += OnGetUnitSize(unit);
358 }
359
360 m_nUnitsVisible = unit - m_unitFirst;
361
362 int unitsPageSize = m_nUnitsVisible;
363 if ( s > sWindow )
364 {
365 // last unit is only partially visible, we still need the scrollbar and
366 // so we have to "fix" pageSize because if it is equal to m_unitMax
367 // the scrollbar is not shown at all under MSW
368 --unitsPageSize;
369 }
370
371 // set the scrollbar parameters to reflect this
372 m_win->SetScrollbar(GetOrientation(), m_unitFirst, unitsPageSize, m_unitMax);
373 }
374
375 void wxVarScrollHelperBase::RemoveScrollbar()
376 {
377 m_unitFirst = 0;
378 m_nUnitsVisible = m_unitMax;
379 m_win->SetScrollbar(GetOrientation(), 0, 0, 0);
380 }
381
382 void wxVarScrollHelperBase::DeleteEvtHandler()
383 {
384 // search for m_handler in the handler list
385 if ( m_win && m_handler )
386 {
387 if ( m_win->RemoveEventHandler(m_handler) )
388 {
389 delete m_handler;
390 }
391 //else: something is very wrong, so better [maybe] leak memory than
392 // risk a crash because of double deletion
393
394 m_handler = NULL;
395 }
396 }
397
398 void wxVarScrollHelperBase::DoSetTargetWindow(wxWindow *target)
399 {
400 m_targetWindow = target;
401 #ifdef __WXMAC__
402 target->MacSetClipChildren( true ) ;
403 #endif
404
405 // install the event handler which will intercept the events we're
406 // interested in (but only do it for our real window, not the target window
407 // which we scroll - we don't need to hijack its events)
408 if ( m_targetWindow == m_win )
409 {
410 // if we already have a handler, delete it first
411 DeleteEvtHandler();
412
413 m_handler = new wxVarScrollHelperEvtHandler(this);
414 m_targetWindow->PushEventHandler(m_handler);
415 }
416 }
417
418 // ----------------------------------------------------------------------------
419 // wxVarScrollHelperBase operations
420 // ----------------------------------------------------------------------------
421
422 void wxVarScrollHelperBase::SetTargetWindow(wxWindow *target)
423 {
424 wxCHECK_RET( target, wxT("target window must not be NULL") );
425
426 if ( target == m_targetWindow )
427 return;
428
429 DoSetTargetWindow(target);
430 }
431
432 void wxVarScrollHelperBase::SetUnitCount(size_t count)
433 {
434 // save the number of units
435 m_unitMax = count;
436
437 // and our estimate for their total height
438 m_sizeTotal = EstimateTotalSize();
439
440 // ScrollToUnit() will update the scrollbar itself if it changes the unit
441 // we pass to it because it's out of [new] range
442 size_t oldScrollPos = m_unitFirst;
443 DoScrollToUnit(m_unitFirst);
444 if ( oldScrollPos == m_unitFirst )
445 {
446 // but if it didn't do it, we still need to update the scrollbar to
447 // reflect the changed number of units ourselves
448 UpdateScrollbar();
449 }
450 }
451
452 void wxVarScrollHelperBase::RefreshUnit(size_t unit)
453 {
454 // is this unit visible?
455 if ( !IsVisible(unit) )
456 {
457 // no, it is useless to do anything
458 return;
459 }
460
461 // calculate the rect occupied by this unit on screen
462 wxRect rect;
463 AssignOrient(rect.width, rect.height,
464 GetNonOrientationTargetSize(), OnGetUnitSize(unit));
465
466 for ( size_t n = GetVisibleBegin(); n < unit; ++n )
467 {
468 IncOrient(rect.x, rect.y, OnGetUnitSize(n));
469 }
470
471 // do refresh it
472 m_targetWindow->RefreshRect(rect);
473 }
474
475 void wxVarScrollHelperBase::RefreshUnits(size_t from, size_t to)
476 {
477 wxASSERT_MSG( from <= to, _T("RefreshUnits(): empty range") );
478
479 // clump the range to just the visible units -- it is useless to refresh
480 // the other ones
481 if ( from < GetVisibleBegin() )
482 from = GetVisibleBegin();
483
484 if ( to > GetVisibleEnd() )
485 to = GetVisibleEnd();
486
487 // calculate the rect occupied by these units on screen
488 int orient_size, nonorient_size, orient_pos;
489 orient_size = nonorient_size = orient_pos = 0;
490
491 nonorient_size = GetNonOrientationTargetSize();
492
493 for ( size_t nBefore = GetVisibleBegin();
494 nBefore < from;
495 nBefore++ )
496 {
497 orient_pos += OnGetUnitSize(nBefore);
498 }
499
500 for ( size_t nBetween = from; nBetween <= to; nBetween++ )
501 {
502 orient_size += OnGetUnitSize(nBetween);
503 }
504
505 wxRect rect;
506 AssignOrient(rect.x, rect.y, 0, orient_pos);
507 AssignOrient(rect.width, rect.height, nonorient_size, orient_size);
508
509 // do refresh it
510 m_targetWindow->RefreshRect(rect);
511 }
512
513 void wxVarScrollHelperBase::RefreshAll()
514 {
515 UpdateScrollbar();
516
517 m_targetWindow->Refresh();
518 }
519
520 bool wxVarScrollHelperBase::ScrollLayout()
521 {
522 if ( m_targetWindow->GetSizer() && m_physicalScrolling )
523 {
524 // adjust the sizer dimensions/position taking into account the
525 // virtual size and scrolled position of the window.
526
527 int x, y;
528 AssignOrient(x, y, 0, -GetScrollOffset());
529
530 int w, h;
531 m_targetWindow->GetVirtualSize(&w, &h);
532
533 m_targetWindow->GetSizer()->SetDimension(x, y, w, h);
534 return true;
535 }
536
537 // fall back to default for LayoutConstraints
538 return m_targetWindow->wxWindow::Layout();
539 }
540
541 int wxVarScrollHelperBase::HitTest(wxCoord coord) const
542 {
543 const size_t unitMax = GetVisibleEnd();
544 for ( size_t unit = GetVisibleBegin(); unit < unitMax; ++unit )
545 {
546 coord -= OnGetUnitSize(unit);
547 if ( coord < 0 )
548 return unit;
549 }
550
551 return wxNOT_FOUND;
552 }
553
554 // ----------------------------------------------------------------------------
555 // wxVarScrollHelperBase scrolling
556 // ----------------------------------------------------------------------------
557
558 bool wxVarScrollHelperBase::DoScrollToUnit(size_t unit)
559 {
560 if ( !m_unitMax )
561 {
562 // we're empty, code below doesn't make sense in this case
563 return false;
564 }
565
566 // determine the real first unit to scroll to: we shouldn't scroll beyond
567 // the end
568 size_t unitFirstLast = FindFirstVisibleFromLast(m_unitMax - 1, true);
569 if ( unit > unitFirstLast )
570 unit = unitFirstLast;
571
572 // anything to do?
573 if ( unit == m_unitFirst )
574 {
575 // no
576 return false;
577 }
578
579
580 // remember the currently shown units for the refresh code below
581 size_t unitFirstOld = GetVisibleBegin(),
582 unitLastOld = GetVisibleEnd();
583
584 m_unitFirst = unit;
585
586
587 // the size of scrollbar thumb could have changed
588 UpdateScrollbar();
589
590 // finally refresh the display -- but only redraw as few units as possible
591 // to avoid flicker. We can't do this if we have children because they
592 // won't be scrolled
593 if ( m_targetWindow->GetChildren().empty() &&
594 GetVisibleBegin() >= unitLastOld || GetVisibleEnd() <= unitFirstOld )
595 {
596 // the simplest case: we don't have any old units left, just redraw
597 // everything
598 m_targetWindow->Refresh();
599 }
600 else // scroll the window
601 {
602 if ( m_physicalScrolling )
603 {
604 wxCoord dx = 0,
605 dy = GetUnitsSize(GetVisibleBegin(), unitFirstOld);
606
607 if ( GetOrientation() == wxHORIZONTAL )
608 {
609 wxCoord tmp = dx;
610 dx = dy;
611 dy = tmp;
612 }
613
614 m_targetWindow->ScrollWindow(dx, dy);
615 }
616 else // !m_physicalScrolling
617 {
618 // we still need to invalidate but we can't use ScrollWindow
619 // because physical scrolling is disabled (the user either didn't
620 // want children scrolled and/or doesn't want pixels to be
621 // physically scrolled).
622 m_targetWindow->Refresh();
623 }
624 }
625
626 return true;
627 }
628
629 bool wxVarScrollHelperBase::DoScrollUnits(int units)
630 {
631 units += m_unitFirst;
632 if ( units < 0 )
633 units = 0;
634
635 return DoScrollToUnit(units);
636 }
637
638 bool wxVarScrollHelperBase::DoScrollPages(int pages)
639 {
640 bool didSomething = false;
641
642 while ( pages )
643 {
644 int unit;
645 if ( pages > 0 )
646 {
647 unit = GetVisibleEnd();
648 if ( unit )
649 --unit;
650 --pages;
651 }
652 else // pages < 0
653 {
654 unit = FindFirstVisibleFromLast(GetVisibleEnd());
655 ++pages;
656 }
657
658 didSomething = DoScrollToUnit(unit);
659 }
660
661 return didSomething;
662 }
663
664 // ----------------------------------------------------------------------------
665 // event handling
666 // ----------------------------------------------------------------------------
667
668 void wxVarScrollHelperBase::HandleOnSize(wxSizeEvent& event)
669 {
670 UpdateScrollbar();
671
672 event.Skip();
673 }
674
675 void wxVarScrollHelperBase::HandleOnScroll(wxScrollWinEvent& event)
676 {
677 if (GetOrientation() != event.GetOrientation())
678 {
679 event.Skip();
680 return;
681 }
682
683 DoScrollToUnit(GetNewScrollPosition(event));
684
685 #ifdef __WXMAC__
686 UpdateMacScrollWindow();
687 #endif // __WXMAC__
688 }
689
690 void wxVarScrollHelperBase::DoPrepareDC(wxDC& dc)
691 {
692 if ( m_physicalScrolling )
693 {
694 wxPoint pt = dc.GetDeviceOrigin();
695
696 IncOrient(pt.x, pt.y, -GetScrollOffset());
697
698 dc.SetDeviceOrigin(pt.x, pt.y);
699 }
700 }
701
702 int wxVarScrollHelperBase::DoCalcScrolledPosition(int coord) const
703 {
704 return coord - GetScrollOffset();
705 }
706
707 int wxVarScrollHelperBase::DoCalcUnscrolledPosition(int coord) const
708 {
709 return coord + GetScrollOffset();
710 }
711
712 #if wxUSE_MOUSEWHEEL
713
714 void wxVarScrollHelperBase::HandleOnMouseWheel(wxMouseEvent& event)
715 {
716 // we only want to process wheel events for vertical implementations.
717 // There is no way to determine wheel orientation (and on MSW horizontal
718 // wheel rotation just fakes scroll events, rather than sending a MOUSEWHEEL
719 // event).
720 if ( GetOrientation() != wxVERTICAL )
721 return;
722
723 m_sumWheelRotation += event.GetWheelRotation();
724 int delta = event.GetWheelDelta();
725
726 // how much to scroll this time
727 int units_to_scroll = -(m_sumWheelRotation/delta);
728 if ( !units_to_scroll )
729 return;
730
731 m_sumWheelRotation += units_to_scroll*delta;
732
733 if ( !event.IsPageScroll() )
734 DoScrollUnits( units_to_scroll*event.GetLinesPerAction() );
735 else // scroll pages instead of units
736 DoScrollPages( units_to_scroll );
737 }
738
739 #endif // wxUSE_MOUSEWHEEL
740
741
742 // ============================================================================
743 // wxVarHVScrollHelper implementation
744 // ============================================================================
745
746 // ----------------------------------------------------------------------------
747 // wxVarHVScrollHelper operations
748 // ----------------------------------------------------------------------------
749
750 void wxVarHVScrollHelper::SetRowColumnCount(size_t rowCount, size_t columnCount)
751 {
752 SetRowCount(rowCount);
753 SetColumnCount(columnCount);
754 }
755
756 bool wxVarHVScrollHelper::ScrollToRowColumn(size_t row, size_t column)
757 {
758 bool result = false;
759 result |= ScrollToRow(row);
760 result |= ScrollToColumn(column);
761 return result;
762 }
763
764 void wxVarHVScrollHelper::RefreshRowColumn(size_t row, size_t column)
765 {
766 // is this unit visible?
767 if ( !IsRowVisible(row) || !IsColumnVisible(column) )
768 {
769 // no, it is useless to do anything
770 return;
771 }
772
773 // calculate the rect occupied by this cell on screen
774 wxRect v_rect, h_rect;
775 v_rect.height = OnGetRowHeight(row);
776 h_rect.width = OnGetColumnWidth(column);
777
778 size_t n;
779
780 for ( n = GetVisibleRowsBegin(); n < row; n++ )
781 {
782 v_rect.y += OnGetRowHeight(n);
783 }
784
785 for ( n = GetVisibleColumnsBegin(); n < column; n++ )
786 {
787 h_rect.x += OnGetColumnWidth(n);
788 }
789
790 // refresh but specialize the behavior if we have a single target window
791 if ( wxVarVScrollHelper::GetTargetWindow() == wxVarHScrollHelper::GetTargetWindow() )
792 {
793 v_rect.x = h_rect.x;
794 v_rect.width = h_rect.width;
795 wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect);
796 }
797 else
798 {
799 v_rect.x = 0;
800 v_rect.width = wxVarVScrollHelper::GetNonOrientationTargetSize();
801 h_rect.y = 0;
802 h_rect.width = wxVarHScrollHelper::GetNonOrientationTargetSize();
803
804 wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect);
805 wxVarHScrollHelper::GetTargetWindow()->RefreshRect(h_rect);
806 }
807 }
808
809 void wxVarHVScrollHelper::RefreshRowsColumns(size_t fromRow, size_t toRow,
810 size_t fromColumn, size_t toColumn)
811 {
812 wxASSERT_MSG( fromRow <= toRow || fromColumn <= toColumn,
813 _T("RefreshRowsColumns(): empty range") );
814
815 // clump the range to just the visible units -- it is useless to refresh
816 // the other ones
817 if ( fromRow < GetVisibleRowsBegin() )
818 fromRow = GetVisibleRowsBegin();
819
820 if ( toRow > GetVisibleRowsEnd() )
821 toRow = GetVisibleRowsEnd();
822
823 if ( fromColumn < GetVisibleColumnsBegin() )
824 fromColumn = GetVisibleColumnsBegin();
825
826 if ( toColumn > GetVisibleColumnsEnd() )
827 toColumn = GetVisibleColumnsEnd();
828
829 // calculate the rect occupied by these units on screen
830 wxRect v_rect, h_rect;
831 size_t nBefore, nBetween;
832
833 for ( nBefore = GetVisibleRowsBegin();
834 nBefore < fromRow;
835 nBefore++ )
836 {
837 v_rect.y += OnGetRowHeight(nBefore);
838 }
839
840 for ( nBetween = fromRow; nBetween <= toRow; nBetween++ )
841 {
842 v_rect.height += OnGetRowHeight(nBetween);
843 }
844
845 for ( nBefore = GetVisibleColumnsBegin();
846 nBefore < fromColumn;
847 nBefore++ )
848 {
849 h_rect.x += OnGetColumnWidth(nBefore);
850 }
851
852 for ( nBetween = fromColumn; nBetween <= toColumn; nBetween++ )
853 {
854 h_rect.width += OnGetColumnWidth(nBetween);
855 }
856
857 // refresh but specialize the behavior if we have a single target window
858 if ( wxVarVScrollHelper::GetTargetWindow() == wxVarHScrollHelper::GetTargetWindow() )
859 {
860 v_rect.x = h_rect.x;
861 v_rect.width = h_rect.width;
862 wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect);
863 }
864 else
865 {
866 v_rect.x = 0;
867 v_rect.width = wxVarVScrollHelper::GetNonOrientationTargetSize();
868 h_rect.y = 0;
869 h_rect.width = wxVarHScrollHelper::GetNonOrientationTargetSize();
870
871 wxVarVScrollHelper::GetTargetWindow()->RefreshRect(v_rect);
872 wxVarHScrollHelper::GetTargetWindow()->RefreshRect(h_rect);
873 }
874 }
875
876 wxPosition wxVarHVScrollHelper::HitTest(wxCoord x, wxCoord y) const
877 {
878 return wxPosition(wxVarVScrollHelper::HitTest(y),
879 wxVarHScrollHelper::HitTest(x));
880 }
881
882 void wxVarHVScrollHelper::DoPrepareDC(wxDC& dc)
883 {
884 wxVarVScrollHelper::DoPrepareDC(dc);
885 wxVarHScrollHelper::DoPrepareDC(dc);
886 }
887
888 bool wxVarHVScrollHelper::ScrollLayout()
889 {
890 bool layout_result = false;
891 layout_result |= wxVarVScrollHelper::ScrollLayout();
892 layout_result |= wxVarHScrollHelper::ScrollLayout();
893 return layout_result;
894 }
895
896 wxSize wxVarHVScrollHelper::GetRowColumnCount() const
897 {
898 return wxSize(GetColumnCount(), GetRowCount());
899 }
900
901 wxPosition wxVarHVScrollHelper::GetVisibleBegin() const
902 {
903 return wxPosition(GetVisibleRowsBegin(), GetVisibleColumnsBegin());
904 }
905
906 wxPosition wxVarHVScrollHelper::GetVisibleEnd() const
907 {
908 return wxPosition(GetVisibleRowsEnd(), GetVisibleColumnsEnd());
909 }
910
911 bool wxVarHVScrollHelper::IsVisible(size_t row, size_t column) const
912 {
913 return IsRowVisible(row) && IsColumnVisible(column);
914 }
915
916
917 // ============================================================================
918 // wx[V/H/HV]ScrolledWindow implementations
919 // ============================================================================
920
921 IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel)
922 IMPLEMENT_ABSTRACT_CLASS(wxHScrolledWindow, wxPanel)
923 IMPLEMENT_ABSTRACT_CLASS(wxHVScrolledWindow, wxPanel)
924