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