]> git.saurik.com Git - wxWidgets.git/blob - src/univ/scrolbar.cpp
Fix MinGW compilation.
[wxWidgets.git] / src / univ / scrolbar.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/scrolbar.cpp
3 // Purpose: wxScrollBar implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "univscrolbar.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #if wxUSE_SCROLLBAR
31
32 #ifndef WX_PRECOMP
33 #include "wx/timer.h"
34
35 #include "wx/dcclient.h"
36 #include "wx/scrolbar.h"
37 #include "wx/validate.h"
38 #endif
39
40 #include "wx/univ/scrtimer.h"
41
42 #include "wx/univ/renderer.h"
43 #include "wx/univ/inphand.h"
44 #include "wx/univ/theme.h"
45
46 #define WXDEBUG_SCROLLBAR
47
48 #ifndef __WXDEBUG__
49 #undef WXDEBUG_SCROLLBAR
50 #endif // !__WXDEBUG__
51
52 #if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
53 #include "wx/msw/private.h"
54 #endif
55
56 // ----------------------------------------------------------------------------
57 // wxScrollBarTimer: this class is used to repeatedly scroll the scrollbar
58 // when the mouse is help pressed on the arrow or on the bar. It generates the
59 // given scroll action command periodically.
60 // ----------------------------------------------------------------------------
61
62 class wxScrollBarTimer : public wxScrollTimer
63 {
64 public:
65 wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
66 const wxControlAction& action,
67 wxScrollBar *control);
68
69 protected:
70 virtual bool DoNotify();
71
72 private:
73 wxStdScrollBarInputHandler *m_handler;
74 wxControlAction m_action;
75 wxScrollBar *m_control;
76 };
77
78 // ============================================================================
79 // implementation
80 // ============================================================================
81
82 IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
83
84 BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
85 EVT_IDLE(wxScrollBar::OnIdle)
86 END_EVENT_TABLE()
87
88 // ----------------------------------------------------------------------------
89 // creation
90 // ----------------------------------------------------------------------------
91
92 #ifdef __VISUALC__
93 // warning C4355: 'this' : used in base member initializer list
94 #pragma warning(disable:4355) // so what? disable it...
95 #endif
96
97 wxScrollBar::wxScrollBar()
98 : m_arrows(this)
99 {
100 Init();
101 }
102
103 wxScrollBar::wxScrollBar(wxWindow *parent,
104 wxWindowID id,
105 const wxPoint& pos,
106 const wxSize& size,
107 long style,
108 const wxValidator& validator,
109 const wxString& name)
110 : m_arrows(this)
111 {
112 Init();
113
114 (void)Create(parent, id, pos, size, style, validator, name);
115 }
116
117 #ifdef __VISUALC__
118 // warning C4355: 'this' : used in base member initializer list
119 #pragma warning(default:4355)
120 #endif
121
122 void wxScrollBar::Init()
123 {
124 m_range =
125 m_thumbSize =
126 m_thumbPos =
127 m_pageSize = 0;
128
129 m_thumbPosOld = -1;
130
131 for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
132 {
133 m_elementsState[n] = 0;
134 }
135
136 m_dirty = FALSE;
137 }
138
139 bool wxScrollBar::Create(wxWindow *parent,
140 wxWindowID id,
141 const wxPoint &pos,
142 const wxSize &size,
143 long style,
144 const wxValidator& validator,
145 const wxString &name)
146 {
147 // the scrollbars never have the border
148 style &= ~wxBORDER_MASK;
149
150 if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) )
151 return FALSE;
152
153 SetBestSize(size);
154
155 // override the cursor of the target window (if any)
156 SetCursor(wxCURSOR_ARROW);
157
158 CreateInputHandler(wxINP_HANDLER_SCROLLBAR);
159
160 return TRUE;
161 }
162
163 wxScrollBar::~wxScrollBar()
164 {
165 }
166
167 // ----------------------------------------------------------------------------
168 // scrollbar API
169 // ----------------------------------------------------------------------------
170
171 void wxScrollBar::DoSetThumb(int pos)
172 {
173 // don't assert hecks here, we're a private function which is meant to be
174 // called with any args at all
175 if ( pos < 0 )
176 {
177 pos = 0;
178 }
179 else if ( pos > m_range - m_thumbSize )
180 {
181 pos = m_range - m_thumbSize;
182 }
183
184 if ( m_thumbPos == pos )
185 {
186 // nothing changed, avoid refreshes which would provoke flicker
187 return;
188 }
189
190 if ( m_thumbPosOld == -1 )
191 {
192 // remember the old thumb position
193 m_thumbPosOld = m_thumbPos;
194 }
195
196 m_thumbPos = pos;
197
198 // we have to refresh the part of the bar which was under the thumb and the
199 // thumb itself
200 m_elementsState[Element_Thumb] |= wxCONTROL_DIRTY;
201 m_elementsState[m_thumbPos > m_thumbPosOld
202 ? Element_Bar_1 : Element_Bar_2] |= wxCONTROL_DIRTY;
203 m_dirty = TRUE;
204 }
205
206 int wxScrollBar::GetThumbPosition() const
207 {
208 return m_thumbPos;
209 }
210
211 int wxScrollBar::GetThumbSize() const
212 {
213 return m_thumbSize;
214 }
215
216 int wxScrollBar::GetPageSize() const
217 {
218 return m_pageSize;
219 }
220
221 int wxScrollBar::GetRange() const
222 {
223 return m_range;
224 }
225
226 void wxScrollBar::SetThumbPosition(int pos)
227 {
228 wxCHECK_RET( pos >= 0 && pos <= m_range, _T("thumb position out of range") );
229
230 DoSetThumb(pos);
231 }
232
233 void wxScrollBar::SetScrollbar(int position, int thumbSize,
234 int range, int pageSize,
235 bool refresh)
236 {
237 // we only refresh everythign when the range changes, thumb position
238 // changes are handled in OnIdle
239 bool needsRefresh = (range != m_range) ||
240 (thumbSize != m_thumbSize) ||
241 (pageSize != m_pageSize);
242
243 // set all parameters
244 m_range = range;
245 m_thumbSize = thumbSize;
246 SetThumbPosition(position);
247 m_pageSize = pageSize;
248
249 // ignore refresh parameter unless we really need to refresh everything -
250 // there ir a lot of existing code which just calls SetScrollbar() without
251 // specifying the last parameter even though it doesn't need at all to
252 // refresh the window immediately
253 if ( refresh && needsRefresh )
254 {
255 // and update the window
256 Refresh();
257 Update();
258 }
259 }
260
261 // ----------------------------------------------------------------------------
262 // geometry
263 // ----------------------------------------------------------------------------
264
265 wxSize wxScrollBar::DoGetBestClientSize() const
266 {
267 // this dimension is completely arbitrary
268 static const wxCoord SIZE = 140;
269
270 wxSize size = m_renderer->GetScrollbarArrowSize();
271 if ( IsVertical() )
272 {
273 size.y = SIZE;
274 }
275 else // horizontal
276 {
277 size.x = SIZE;
278 }
279
280 return size;
281 }
282
283 wxScrollArrows::Arrow wxScrollBar::HitTest(const wxPoint& pt) const
284 {
285 switch ( m_renderer->HitTestScrollbar(this, pt) )
286 {
287 case wxHT_SCROLLBAR_ARROW_LINE_1:
288 return wxScrollArrows::Arrow_First;
289
290 case wxHT_SCROLLBAR_ARROW_LINE_2:
291 return wxScrollArrows::Arrow_Second;
292
293 default:
294 return wxScrollArrows::Arrow_None;
295 }
296 }
297
298 // ----------------------------------------------------------------------------
299 // drawing
300 // ----------------------------------------------------------------------------
301
302 void wxScrollBar::OnIdle(wxIdleEvent& event)
303 {
304 if ( m_dirty )
305 {
306 for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
307 {
308 if ( m_elementsState[n] & wxCONTROL_DIRTY )
309 {
310 wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
311
312 if ( rect.width && rect.height )
313 {
314 // we try to avoid redrawing the entire shaft (which might
315 // be quite long) if possible by only redrawing the area
316 // wich really changed
317 if ( (n == Element_Bar_1 || n == Element_Bar_2) &&
318 (m_thumbPosOld != -1) )
319 {
320 // the less efficient but more reliable (i.e. this will
321 // probably work everywhere) version: refresh the
322 // distance covered by thumb since the last update
323 #if 0
324 wxRect rectOld =
325 GetRenderer()->GetScrollbarRect(this,
326 (Element)n,
327 m_thumbPosOld);
328 if ( IsVertical() )
329 {
330 if ( n == Element_Bar_1 )
331 rect.SetTop(rectOld.GetBottom());
332 else
333 rect.SetBottom(rectOld.GetBottom());
334 }
335 else // horizontal
336 {
337 if ( n == Element_Bar_1 )
338 rect.SetLeft(rectOld.GetRight());
339 else
340 rect.SetRight(rectOld.GetRight());
341 }
342 #else // efficient version: only repaint the area occupied by
343 // the thumb previously - we can't do better than this
344 rect = GetRenderer()->GetScrollbarRect(this,
345 Element_Thumb,
346 m_thumbPosOld);
347 #endif // 0/1
348 }
349
350 #ifdef WXDEBUG_SCROLLBAR
351 static bool s_refreshDebug = FALSE;
352 if ( s_refreshDebug )
353 {
354 wxClientDC dc(this);
355 dc.SetBrush(*wxCYAN_BRUSH);
356 dc.SetPen(*wxTRANSPARENT_PEN);
357 dc.DrawRectangle(rect);
358
359 // under Unix we use "--sync" X option for this
360 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
361 ::GdiFlush();
362 ::Sleep(200);
363 #endif // __WXMSW__
364 }
365 #endif // WXDEBUG_SCROLLBAR
366
367 Refresh(TRUE, &rect);
368 }
369
370 m_elementsState[n] &= ~wxCONTROL_DIRTY;
371 }
372 }
373
374 m_dirty = FALSE;
375 }
376
377 event.Skip();
378 }
379
380 void wxScrollBar::DoDraw(wxControlRenderer *renderer)
381 {
382 renderer->DrawScrollbar(this, m_thumbPosOld);
383
384 // clear all dirty flags
385 m_dirty = FALSE;
386 m_thumbPosOld = -1;
387 }
388
389 // ----------------------------------------------------------------------------
390 // state flags
391 // ----------------------------------------------------------------------------
392
393 static inline wxScrollBar::Element ElementForArrow(wxScrollArrows::Arrow arrow)
394 {
395 return arrow == wxScrollArrows::Arrow_First
396 ? wxScrollBar::Element_Arrow_Line_1
397 : wxScrollBar::Element_Arrow_Line_2;
398 }
399
400 int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow) const
401 {
402 return GetState(ElementForArrow(arrow));
403 }
404
405 void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
406 {
407 Element which = ElementForArrow(arrow);
408 int state = GetState(which);
409 if ( set )
410 state |= flag;
411 else
412 state &= ~flag;
413
414 SetState(which, state);
415 }
416
417 int wxScrollBar::GetState(Element which) const
418 {
419 // if the entire scrollbar is disabled, all of its elements are too
420 int flags = m_elementsState[which];
421 if ( !IsEnabled() )
422 flags |= wxCONTROL_DISABLED;
423
424 return flags;
425 }
426
427 void wxScrollBar::SetState(Element which, int flags)
428 {
429 if ( (int)(m_elementsState[which] & ~wxCONTROL_DIRTY) != flags )
430 {
431 m_elementsState[which] = flags | wxCONTROL_DIRTY;
432
433 m_dirty = TRUE;
434 }
435 }
436
437 // ----------------------------------------------------------------------------
438 // input processing
439 // ----------------------------------------------------------------------------
440
441 bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow)
442 {
443 int oldThumbPos = GetThumbPosition();
444 PerformAction(arrow == wxScrollArrows::Arrow_First
445 ? wxACTION_SCROLL_LINE_UP
446 : wxACTION_SCROLL_LINE_DOWN);
447
448 // did we scroll till the end?
449 return GetThumbPosition() != oldThumbPos;
450 }
451
452 bool wxScrollBar::PerformAction(const wxControlAction& action,
453 long numArg,
454 const wxString& strArg)
455 {
456 int thumbOld = m_thumbPos;
457
458 bool notify = FALSE; // send an event about the change?
459
460 wxEventType scrollType;
461
462 // test for thumb move first as these events happen in quick succession
463 if ( action == wxACTION_SCROLL_THUMB_MOVE )
464 {
465 DoSetThumb(numArg);
466
467 scrollType = wxEVT_SCROLLWIN_THUMBTRACK;
468 }
469 else if ( action == wxACTION_SCROLL_LINE_UP )
470 {
471 scrollType = wxEVT_SCROLLWIN_LINEUP;
472 ScrollLines(-1);
473 }
474 else if ( action == wxACTION_SCROLL_LINE_DOWN )
475 {
476 scrollType = wxEVT_SCROLLWIN_LINEDOWN;
477 ScrollLines(1);
478 }
479 else if ( action == wxACTION_SCROLL_PAGE_UP )
480 {
481 scrollType = wxEVT_SCROLLWIN_PAGEUP;
482 ScrollPages(-1);
483 }
484 else if ( action == wxACTION_SCROLL_PAGE_DOWN )
485 {
486 scrollType = wxEVT_SCROLLWIN_PAGEDOWN;
487 ScrollPages(1);
488 }
489 else if ( action == wxACTION_SCROLL_START )
490 {
491 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
492 ScrollToStart();
493 }
494 else if ( action == wxACTION_SCROLL_END )
495 {
496 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
497 ScrollToEnd();
498 }
499 else if ( action == wxACTION_SCROLL_THUMB_DRAG )
500 {
501 // we won't use it but this line suppresses the compiler
502 // warning about "variable may be used without having been
503 // initialized"
504 scrollType = wxEVT_NULL;
505 }
506 else if ( action == wxACTION_SCROLL_THUMB_RELEASE )
507 {
508 // always notify about this
509 notify = TRUE;
510 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE;
511 }
512 else
513 return wxControl::PerformAction(action, numArg, strArg);
514
515 // has scrollbar position changed?
516 bool changed = m_thumbPos != thumbOld;
517 if ( notify || changed )
518 {
519 wxScrollWinEvent event(scrollType, m_thumbPos,
520 IsVertical() ? wxVERTICAL : wxHORIZONTAL);
521 event.SetEventObject(this);
522 GetParent()->GetEventHandler()->ProcessEvent(event);
523 }
524
525 return TRUE;
526 }
527
528 void wxScrollBar::ScrollToStart()
529 {
530 DoSetThumb(0);
531 }
532
533 void wxScrollBar::ScrollToEnd()
534 {
535 DoSetThumb(m_range - m_thumbSize);
536 }
537
538 bool wxScrollBar::ScrollLines(int nLines)
539 {
540 DoSetThumb(m_thumbPos + nLines);
541 return TRUE;
542 }
543
544 bool wxScrollBar::ScrollPages(int nPages)
545 {
546 DoSetThumb(m_thumbPos + nPages*m_pageSize);
547 return TRUE;
548 }
549
550 // ============================================================================
551 // scroll bar input handler
552 // ============================================================================
553
554 // ----------------------------------------------------------------------------
555 // wxScrollBarTimer
556 // ----------------------------------------------------------------------------
557
558 wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
559 const wxControlAction& action,
560 wxScrollBar *control)
561 {
562 m_handler = handler;
563 m_action = action;
564 m_control = control;
565 }
566
567 bool wxScrollBarTimer::DoNotify()
568 {
569 return m_handler->OnScrollTimer(m_control, m_action);
570 }
571
572 // ----------------------------------------------------------------------------
573 // wxStdScrollBarInputHandler
574 // ----------------------------------------------------------------------------
575
576 wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
577 wxInputHandler *handler)
578 : wxStdInputHandler(handler)
579 {
580 m_renderer = renderer;
581 m_winCapture = NULL;
582 m_htLast = wxHT_NOWHERE;
583 m_timerScroll = NULL;
584 }
585
586 wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler()
587 {
588 // normally, it's NULL by now but just in case the user somehow managed to
589 // keep the mouse captured until now...
590 delete m_timerScroll;
591 }
592
593 void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
594 int flag,
595 bool doIt)
596 {
597 if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
598 {
599 wxScrollBar::Element
600 elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
601
602 int flags = control->GetState(elem);
603 if ( doIt )
604 flags |= flag;
605 else
606 flags &= ~flag;
607 control->SetState(elem, flags);
608 }
609 }
610
611 bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
612 const wxControlAction& action)
613 {
614 int oldThumbPos = scrollbar->GetThumbPosition();
615 scrollbar->PerformAction(action);
616 if ( scrollbar->GetThumbPosition() != oldThumbPos )
617 return TRUE;
618
619 // we scrolled till the end
620 m_timerScroll->Stop();
621
622 return FALSE;
623 }
624
625 void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar *control)
626 {
627 // return everything to the normal state
628 if ( m_winCapture )
629 {
630 m_winCapture->ReleaseMouse();
631 m_winCapture = NULL;
632 }
633
634 m_btnCapture = -1;
635
636 if ( m_timerScroll )
637 {
638 delete m_timerScroll;
639 m_timerScroll = NULL;
640 }
641
642 // unpress the arrow and highlight the current element
643 Press(control, FALSE);
644 }
645
646 wxCoord
647 wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar *scrollbar,
648 const wxMouseEvent& event) const
649 {
650 wxPoint pt = event.GetPosition();
651 return scrollbar->GetWindowStyle() & wxVERTICAL ? pt.y : pt.x;
652 }
653
654 void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar *scrollbar,
655 const wxMouseEvent& event)
656 {
657 int thumbPos = GetMouseCoord(scrollbar, event) - m_ofsMouse;
658 thumbPos = m_renderer->PixelToScrollbar(scrollbar, thumbPos);
659 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, thumbPos);
660 }
661
662 bool wxStdScrollBarInputHandler::HandleKey(wxInputConsumer *consumer,
663 const wxKeyEvent& event,
664 bool pressed)
665 {
666 // we only react to the key presses here
667 if ( pressed )
668 {
669 wxControlAction action;
670 switch ( event.GetKeyCode() )
671 {
672 case WXK_DOWN:
673 case WXK_RIGHT: action = wxACTION_SCROLL_LINE_DOWN; break;
674 case WXK_UP:
675 case WXK_LEFT: action = wxACTION_SCROLL_LINE_UP; break;
676 case WXK_HOME: action = wxACTION_SCROLL_START; break;
677 case WXK_END: action = wxACTION_SCROLL_END; break;
678 case WXK_PAGEUP:
679 case WXK_PRIOR: action = wxACTION_SCROLL_PAGE_UP; break;
680 case WXK_PAGEDOWN:
681 case WXK_NEXT: action = wxACTION_SCROLL_PAGE_DOWN; break;
682 }
683
684 if ( !!action )
685 {
686 consumer->PerformAction(action);
687
688 return TRUE;
689 }
690 }
691
692 return wxStdInputHandler::HandleKey(consumer, event, pressed);
693 }
694
695 bool wxStdScrollBarInputHandler::HandleMouse(wxInputConsumer *consumer,
696 const wxMouseEvent& event)
697 {
698 // is this a click event from an acceptable button?
699 int btn = event.GetButton();
700 if ( (btn != -1) && IsAllowedButton(btn) )
701 {
702 // determine which part of the window mouse is in
703 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
704 wxHitTest ht = m_renderer->HitTestScrollbar
705 (
706 scrollbar,
707 event.GetPosition()
708 );
709
710 // when the mouse is pressed on any scrollbar element, we capture it
711 // and hold capture until the same mouse button is released
712 if ( event.ButtonDown() || event.ButtonDClick() )
713 {
714 if ( !m_winCapture )
715 {
716 m_btnCapture = btn;
717 m_winCapture = consumer->GetInputWindow();
718 m_winCapture->CaptureMouse();
719
720 // generate the command
721 bool hasAction = TRUE;
722 wxControlAction action;
723 switch ( ht )
724 {
725 case wxHT_SCROLLBAR_ARROW_LINE_1:
726 action = wxACTION_SCROLL_LINE_UP;
727 break;
728
729 case wxHT_SCROLLBAR_ARROW_LINE_2:
730 action = wxACTION_SCROLL_LINE_DOWN;
731 break;
732
733 case wxHT_SCROLLBAR_BAR_1:
734 action = wxACTION_SCROLL_PAGE_UP;
735 m_ptStartScrolling = event.GetPosition();
736 break;
737
738 case wxHT_SCROLLBAR_BAR_2:
739 action = wxACTION_SCROLL_PAGE_DOWN;
740 m_ptStartScrolling = event.GetPosition();
741 break;
742
743 case wxHT_SCROLLBAR_THUMB:
744 consumer->PerformAction(wxACTION_SCROLL_THUMB_DRAG);
745 m_ofsMouse = GetMouseCoord(scrollbar, event) -
746 m_renderer->ScrollbarToPixel(scrollbar);
747
748 // fall through: there is no immediate action
749
750 default:
751 hasAction = FALSE;
752 }
753
754 // remove highlighting
755 Highlight(scrollbar, FALSE);
756 m_htLast = ht;
757
758 // and press the arrow or highlight thumb now instead
759 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
760 Highlight(scrollbar, TRUE);
761 else
762 Press(scrollbar, TRUE);
763
764 // start dragging
765 if ( hasAction )
766 {
767 m_timerScroll = new wxScrollBarTimer(this, action,
768 scrollbar);
769 m_timerScroll->StartAutoScroll();
770 }
771 //else: no (immediate) action
772
773 }
774 //else: mouse already captured, nothing to do
775 }
776 // release mouse if the *same* button went up
777 else if ( btn == m_btnCapture )
778 {
779 if ( m_winCapture )
780 {
781 StopScrolling(scrollbar);
782
783 // if we were dragging the thumb, send the last event
784 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
785 {
786 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_RELEASE);
787 }
788
789 m_htLast = ht;
790 Highlight(scrollbar, TRUE);
791 }
792 else
793 {
794 // this is not supposed to happen as the button can't go up
795 // without going down previously and then we'd have
796 // m_winCapture by now
797 wxFAIL_MSG( _T("logic error in mouse capturing code") );
798 }
799 }
800 }
801
802 return wxStdInputHandler::HandleMouse(consumer, event);
803 }
804
805 bool wxStdScrollBarInputHandler::HandleMouseMove(wxInputConsumer *consumer,
806 const wxMouseEvent& event)
807 {
808 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
809
810 if ( m_winCapture )
811 {
812 if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Moving() )
813 {
814 // make the thumb follow the mouse by keeping the same offset
815 // between the mouse position and the top/left of the thumb
816 HandleThumbMove(scrollbar, event);
817
818 return TRUE;
819 }
820
821 // no other changes are possible while the mouse is captured
822 return FALSE;
823 }
824
825 bool isArrow = scrollbar->GetArrows().HandleMouseMove(event);
826
827 if ( event.Moving() )
828 {
829 wxHitTest ht = m_renderer->HitTestScrollbar
830 (
831 scrollbar,
832 event.GetPosition()
833 );
834 if ( ht == m_htLast )
835 {
836 // nothing changed
837 return FALSE;
838 }
839
840 #ifdef DEBUG_MOUSE
841 wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
842 #endif // DEBUG_MOUSE
843
844 Highlight(scrollbar, FALSE);
845 m_htLast = ht;
846
847 if ( !isArrow )
848 Highlight(scrollbar, TRUE);
849 //else: already done by wxScrollArrows::HandleMouseMove
850 }
851 else if ( event.Leaving() )
852 {
853 if ( !isArrow )
854 Highlight(scrollbar, FALSE);
855
856 m_htLast = wxHT_NOWHERE;
857 }
858 else // event.Entering()
859 {
860 // we don't process this event
861 return FALSE;
862 }
863
864 // we did something
865 return TRUE;
866 }
867
868 #endif // wxUSE_SCROLLBAR
869
870 // ----------------------------------------------------------------------------
871 // wxScrollTimer
872 // ----------------------------------------------------------------------------
873
874 wxScrollTimer::wxScrollTimer()
875 {
876 m_skipNext = FALSE;
877 }
878
879 void wxScrollTimer::StartAutoScroll()
880 {
881 // start scrolling immediately
882 if ( !DoNotify() )
883 {
884 // ... and end it too
885 return;
886 }
887
888 // there is an initial delay before the scrollbar starts scrolling -
889 // implement it by ignoring the first timer expiration and only start
890 // scrolling from the second one
891 m_skipNext = TRUE;
892 Start(200); // FIXME: hardcoded delay
893 }
894
895 void wxScrollTimer::Notify()
896 {
897 if ( m_skipNext )
898 {
899 // scroll normally now - reduce the delay
900 Stop();
901 Start(50); // FIXME: hardcoded delay
902
903 m_skipNext = FALSE;
904 }
905 else
906 {
907 // if DoNotify() returns false, we're already deleted by the timer
908 // event handler, so don't do anything else here
909 (void)DoNotify();
910 }
911 }
912