]> git.saurik.com Git - wxWidgets.git/blame - src/univ/scrolbar.cpp
do NOT hard code univ sources in x11 port
[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
cff7ef89
VS
52#if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
53#include "wx/msw/private.h"
54#endif
55
1e6feb95
VZ
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
62class wxScrollBarTimer : public wxScrollTimer
63{
64public:
65 wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
66 const wxControlAction& action,
67 wxScrollBar *control);
68
69protected:
70 virtual bool DoNotify();
71
72private:
73 wxStdScrollBarInputHandler *m_handler;
74 wxControlAction m_action;
75 wxScrollBar *m_control;
76};
77
78// ============================================================================
79// implementation
80// ============================================================================
81
82IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
83
84BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
85 EVT_IDLE(wxScrollBar::OnIdle)
86END_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
97wxScrollBar::wxScrollBar()
98 : m_arrows(this)
99{
100 Init();
101}
102
103wxScrollBar::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
122void 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
139bool 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
163wxScrollBar::~wxScrollBar()
164{
165}
166
167// ----------------------------------------------------------------------------
168// scrollbar API
169// ----------------------------------------------------------------------------
170
171void 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
206int wxScrollBar::GetThumbPosition() const
207{
208 return m_thumbPos;
209}
210
211int wxScrollBar::GetThumbSize() const
212{
213 return m_thumbSize;
214}
215
216int wxScrollBar::GetPageSize() const
217{
218 return m_pageSize;
219}
220
221int wxScrollBar::GetRange() const
222{
223 return m_range;
224}
225
226void 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
233void 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
265wxSize 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
283wxScrollArrows::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
302void wxScrollBar::OnIdle(wxIdleEvent& event)
21c3670f
VS
303{
304 UpdateThumb();
305 event.Skip();
306}
307
308void wxScrollBar::UpdateThumb()
1e6feb95
VZ
309{
310 if ( m_dirty )
311 {
312 for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
313 {
314 if ( m_elementsState[n] & wxCONTROL_DIRTY )
315 {
316 wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
317
318 if ( rect.width && rect.height )
319 {
320 // we try to avoid redrawing the entire shaft (which might
321 // be quite long) if possible by only redrawing the area
322 // wich really changed
323 if ( (n == Element_Bar_1 || n == Element_Bar_2) &&
324 (m_thumbPosOld != -1) )
325 {
326 // the less efficient but more reliable (i.e. this will
327 // probably work everywhere) version: refresh the
328 // distance covered by thumb since the last update
329#if 0
330 wxRect rectOld =
331 GetRenderer()->GetScrollbarRect(this,
332 (Element)n,
333 m_thumbPosOld);
334 if ( IsVertical() )
335 {
336 if ( n == Element_Bar_1 )
337 rect.SetTop(rectOld.GetBottom());
338 else
339 rect.SetBottom(rectOld.GetBottom());
340 }
341 else // horizontal
342 {
343 if ( n == Element_Bar_1 )
344 rect.SetLeft(rectOld.GetRight());
345 else
346 rect.SetRight(rectOld.GetRight());
347 }
348#else // efficient version: only repaint the area occupied by
349 // the thumb previously - we can't do better than this
350 rect = GetRenderer()->GetScrollbarRect(this,
351 Element_Thumb,
352 m_thumbPosOld);
353#endif // 0/1
354 }
355
356#ifdef WXDEBUG_SCROLLBAR
357 static bool s_refreshDebug = FALSE;
358 if ( s_refreshDebug )
359 {
360 wxClientDC dc(this);
361 dc.SetBrush(*wxCYAN_BRUSH);
362 dc.SetPen(*wxTRANSPARENT_PEN);
363 dc.DrawRectangle(rect);
364
365 // under Unix we use "--sync" X option for this
8cb172b4 366 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1e6feb95
VZ
367 ::GdiFlush();
368 ::Sleep(200);
369 #endif // __WXMSW__
370 }
371#endif // WXDEBUG_SCROLLBAR
372
373 Refresh(TRUE, &rect);
374 }
375
376 m_elementsState[n] &= ~wxCONTROL_DIRTY;
377 }
378 }
379
380 m_dirty = FALSE;
381 }
1e6feb95
VZ
382}
383
384void wxScrollBar::DoDraw(wxControlRenderer *renderer)
385{
386 renderer->DrawScrollbar(this, m_thumbPosOld);
387
388 // clear all dirty flags
389 m_dirty = FALSE;
390 m_thumbPosOld = -1;
391}
392
393// ----------------------------------------------------------------------------
394// state flags
395// ----------------------------------------------------------------------------
396
397static inline wxScrollBar::Element ElementForArrow(wxScrollArrows::Arrow arrow)
398{
399 return arrow == wxScrollArrows::Arrow_First
400 ? wxScrollBar::Element_Arrow_Line_1
401 : wxScrollBar::Element_Arrow_Line_2;
402}
403
404int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow) const
405{
406 return GetState(ElementForArrow(arrow));
407}
408
409void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
410{
411 Element which = ElementForArrow(arrow);
412 int state = GetState(which);
413 if ( set )
414 state |= flag;
415 else
416 state &= ~flag;
417
418 SetState(which, state);
419}
420
421int wxScrollBar::GetState(Element which) const
422{
423 // if the entire scrollbar is disabled, all of its elements are too
424 int flags = m_elementsState[which];
425 if ( !IsEnabled() )
426 flags |= wxCONTROL_DISABLED;
427
428 return flags;
429}
430
431void wxScrollBar::SetState(Element which, int flags)
432{
433 if ( (int)(m_elementsState[which] & ~wxCONTROL_DIRTY) != flags )
434 {
435 m_elementsState[which] = flags | wxCONTROL_DIRTY;
436
437 m_dirty = TRUE;
438 }
439}
440
441// ----------------------------------------------------------------------------
442// input processing
443// ----------------------------------------------------------------------------
444
445bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow)
446{
447 int oldThumbPos = GetThumbPosition();
448 PerformAction(arrow == wxScrollArrows::Arrow_First
449 ? wxACTION_SCROLL_LINE_UP
450 : wxACTION_SCROLL_LINE_DOWN);
451
452 // did we scroll till the end?
453 return GetThumbPosition() != oldThumbPos;
454}
455
456bool wxScrollBar::PerformAction(const wxControlAction& action,
457 long numArg,
458 const wxString& strArg)
459{
460 int thumbOld = m_thumbPos;
461
462 bool notify = FALSE; // send an event about the change?
463
464 wxEventType scrollType;
465
466 // test for thumb move first as these events happen in quick succession
467 if ( action == wxACTION_SCROLL_THUMB_MOVE )
468 {
469 DoSetThumb(numArg);
470
21c3670f
VS
471 // VS: we have to force redraw here, otherwise the thumb will lack
472 // behind mouse cursor
473 UpdateThumb();
474
1e6feb95
VZ
475 scrollType = wxEVT_SCROLLWIN_THUMBTRACK;
476 }
477 else if ( action == wxACTION_SCROLL_LINE_UP )
478 {
479 scrollType = wxEVT_SCROLLWIN_LINEUP;
480 ScrollLines(-1);
481 }
482 else if ( action == wxACTION_SCROLL_LINE_DOWN )
483 {
484 scrollType = wxEVT_SCROLLWIN_LINEDOWN;
485 ScrollLines(1);
486 }
487 else if ( action == wxACTION_SCROLL_PAGE_UP )
488 {
489 scrollType = wxEVT_SCROLLWIN_PAGEUP;
490 ScrollPages(-1);
491 }
492 else if ( action == wxACTION_SCROLL_PAGE_DOWN )
493 {
494 scrollType = wxEVT_SCROLLWIN_PAGEDOWN;
495 ScrollPages(1);
496 }
497 else if ( action == wxACTION_SCROLL_START )
498 {
499 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
500 ScrollToStart();
501 }
502 else if ( action == wxACTION_SCROLL_END )
503 {
504 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
505 ScrollToEnd();
506 }
507 else if ( action == wxACTION_SCROLL_THUMB_DRAG )
508 {
509 // we won't use it but this line suppresses the compiler
510 // warning about "variable may be used without having been
511 // initialized"
512 scrollType = wxEVT_NULL;
513 }
514 else if ( action == wxACTION_SCROLL_THUMB_RELEASE )
515 {
516 // always notify about this
517 notify = TRUE;
518 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE;
519 }
520 else
521 return wxControl::PerformAction(action, numArg, strArg);
522
523 // has scrollbar position changed?
524 bool changed = m_thumbPos != thumbOld;
525 if ( notify || changed )
526 {
527 wxScrollWinEvent event(scrollType, m_thumbPos,
528 IsVertical() ? wxVERTICAL : wxHORIZONTAL);
529 event.SetEventObject(this);
530 GetParent()->GetEventHandler()->ProcessEvent(event);
531 }
532
533 return TRUE;
534}
535
536void wxScrollBar::ScrollToStart()
537{
538 DoSetThumb(0);
539}
540
541void wxScrollBar::ScrollToEnd()
542{
543 DoSetThumb(m_range - m_thumbSize);
544}
545
2b92b572 546bool wxScrollBar::ScrollLines(int nLines)
1e6feb95
VZ
547{
548 DoSetThumb(m_thumbPos + nLines);
2b92b572 549 return TRUE;
1e6feb95
VZ
550}
551
2b92b572 552bool wxScrollBar::ScrollPages(int nPages)
1e6feb95
VZ
553{
554 DoSetThumb(m_thumbPos + nPages*m_pageSize);
2b92b572 555 return TRUE;
1e6feb95
VZ
556}
557
558// ============================================================================
559// scroll bar input handler
560// ============================================================================
561
562// ----------------------------------------------------------------------------
563// wxScrollBarTimer
564// ----------------------------------------------------------------------------
565
566wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
567 const wxControlAction& action,
568 wxScrollBar *control)
569{
570 m_handler = handler;
571 m_action = action;
572 m_control = control;
573}
574
575bool wxScrollBarTimer::DoNotify()
576{
577 return m_handler->OnScrollTimer(m_control, m_action);
578}
579
580// ----------------------------------------------------------------------------
581// wxStdScrollBarInputHandler
582// ----------------------------------------------------------------------------
583
584wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
585 wxInputHandler *handler)
586 : wxStdInputHandler(handler)
587{
588 m_renderer = renderer;
589 m_winCapture = NULL;
590 m_htLast = wxHT_NOWHERE;
591 m_timerScroll = NULL;
592}
593
594wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler()
595{
596 // normally, it's NULL by now but just in case the user somehow managed to
597 // keep the mouse captured until now...
598 delete m_timerScroll;
599}
600
601void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
602 int flag,
603 bool doIt)
604{
605 if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
606 {
607 wxScrollBar::Element
608 elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
609
610 int flags = control->GetState(elem);
611 if ( doIt )
612 flags |= flag;
613 else
614 flags &= ~flag;
615 control->SetState(elem, flags);
616 }
617}
618
619bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
620 const wxControlAction& action)
621{
622 int oldThumbPos = scrollbar->GetThumbPosition();
623 scrollbar->PerformAction(action);
624 if ( scrollbar->GetThumbPosition() != oldThumbPos )
625 return TRUE;
626
627 // we scrolled till the end
628 m_timerScroll->Stop();
629
630 return FALSE;
631}
632
633void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar *control)
634{
635 // return everything to the normal state
636 if ( m_winCapture )
637 {
638 m_winCapture->ReleaseMouse();
639 m_winCapture = NULL;
640 }
641
642 m_btnCapture = -1;
643
644 if ( m_timerScroll )
645 {
646 delete m_timerScroll;
647 m_timerScroll = NULL;
648 }
649
650 // unpress the arrow and highlight the current element
651 Press(control, FALSE);
652}
653
654wxCoord
655wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar *scrollbar,
656 const wxMouseEvent& event) const
657{
658 wxPoint pt = event.GetPosition();
659 return scrollbar->GetWindowStyle() & wxVERTICAL ? pt.y : pt.x;
660}
661
662void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar *scrollbar,
663 const wxMouseEvent& event)
664{
665 int thumbPos = GetMouseCoord(scrollbar, event) - m_ofsMouse;
666 thumbPos = m_renderer->PixelToScrollbar(scrollbar, thumbPos);
667 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, thumbPos);
668}
669
23645bfa 670bool wxStdScrollBarInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
671 const wxKeyEvent& event,
672 bool pressed)
673{
674 // we only react to the key presses here
675 if ( pressed )
676 {
677 wxControlAction action;
678 switch ( event.GetKeyCode() )
679 {
680 case WXK_DOWN:
681 case WXK_RIGHT: action = wxACTION_SCROLL_LINE_DOWN; break;
682 case WXK_UP:
683 case WXK_LEFT: action = wxACTION_SCROLL_LINE_UP; break;
684 case WXK_HOME: action = wxACTION_SCROLL_START; break;
685 case WXK_END: action = wxACTION_SCROLL_END; break;
187c183c 686 case WXK_PAGEUP:
1e6feb95 687 case WXK_PRIOR: action = wxACTION_SCROLL_PAGE_UP; break;
187c183c 688 case WXK_PAGEDOWN:
1e6feb95
VZ
689 case WXK_NEXT: action = wxACTION_SCROLL_PAGE_DOWN; break;
690 }
691
692 if ( !!action )
693 {
23645bfa 694 consumer->PerformAction(action);
1e6feb95
VZ
695
696 return TRUE;
697 }
698 }
699
23645bfa 700 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
701}
702
23645bfa 703bool wxStdScrollBarInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
704 const wxMouseEvent& event)
705{
706 // is this a click event from an acceptable button?
707 int btn = event.GetButton();
708 if ( (btn != -1) && IsAllowedButton(btn) )
709 {
710 // determine which part of the window mouse is in
23645bfa 711 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
1e6feb95
VZ
712 wxHitTest ht = m_renderer->HitTestScrollbar
713 (
714 scrollbar,
715 event.GetPosition()
716 );
717
718 // when the mouse is pressed on any scrollbar element, we capture it
719 // and hold capture until the same mouse button is released
720 if ( event.ButtonDown() || event.ButtonDClick() )
721 {
722 if ( !m_winCapture )
723 {
724 m_btnCapture = btn;
23645bfa 725 m_winCapture = consumer->GetInputWindow();
1e6feb95
VZ
726 m_winCapture->CaptureMouse();
727
728 // generate the command
729 bool hasAction = TRUE;
730 wxControlAction action;
731 switch ( ht )
732 {
733 case wxHT_SCROLLBAR_ARROW_LINE_1:
734 action = wxACTION_SCROLL_LINE_UP;
735 break;
736
737 case wxHT_SCROLLBAR_ARROW_LINE_2:
738 action = wxACTION_SCROLL_LINE_DOWN;
739 break;
740
741 case wxHT_SCROLLBAR_BAR_1:
742 action = wxACTION_SCROLL_PAGE_UP;
743 m_ptStartScrolling = event.GetPosition();
744 break;
745
746 case wxHT_SCROLLBAR_BAR_2:
747 action = wxACTION_SCROLL_PAGE_DOWN;
748 m_ptStartScrolling = event.GetPosition();
749 break;
750
751 case wxHT_SCROLLBAR_THUMB:
23645bfa 752 consumer->PerformAction(wxACTION_SCROLL_THUMB_DRAG);
1e6feb95
VZ
753 m_ofsMouse = GetMouseCoord(scrollbar, event) -
754 m_renderer->ScrollbarToPixel(scrollbar);
755
756 // fall through: there is no immediate action
757
758 default:
759 hasAction = FALSE;
760 }
761
762 // remove highlighting
763 Highlight(scrollbar, FALSE);
764 m_htLast = ht;
765
766 // and press the arrow or highlight thumb now instead
767 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
768 Highlight(scrollbar, TRUE);
769 else
770 Press(scrollbar, TRUE);
771
772 // start dragging
773 if ( hasAction )
774 {
775 m_timerScroll = new wxScrollBarTimer(this, action,
776 scrollbar);
777 m_timerScroll->StartAutoScroll();
778 }
779 //else: no (immediate) action
780
781 }
782 //else: mouse already captured, nothing to do
783 }
784 // release mouse if the *same* button went up
785 else if ( btn == m_btnCapture )
786 {
787 if ( m_winCapture )
788 {
789 StopScrolling(scrollbar);
790
791 // if we were dragging the thumb, send the last event
792 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
793 {
794 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_RELEASE);
795 }
796
797 m_htLast = ht;
798 Highlight(scrollbar, TRUE);
799 }
800 else
801 {
802 // this is not supposed to happen as the button can't go up
803 // without going down previously and then we'd have
804 // m_winCapture by now
805 wxFAIL_MSG( _T("logic error in mouse capturing code") );
806 }
807 }
808 }
809
23645bfa 810 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
811}
812
23645bfa 813bool wxStdScrollBarInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
814 const wxMouseEvent& event)
815{
23645bfa 816 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
1e6feb95
VZ
817
818 if ( m_winCapture )
819 {
820 if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Moving() )
821 {
822 // make the thumb follow the mouse by keeping the same offset
823 // between the mouse position and the top/left of the thumb
824 HandleThumbMove(scrollbar, event);
825
826 return TRUE;
827 }
828
829 // no other changes are possible while the mouse is captured
830 return FALSE;
831 }
832
833 bool isArrow = scrollbar->GetArrows().HandleMouseMove(event);
834
835 if ( event.Moving() )
836 {
837 wxHitTest ht = m_renderer->HitTestScrollbar
838 (
839 scrollbar,
840 event.GetPosition()
841 );
842 if ( ht == m_htLast )
843 {
844 // nothing changed
845 return FALSE;
846 }
847
848#ifdef DEBUG_MOUSE
849 wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
850#endif // DEBUG_MOUSE
851
852 Highlight(scrollbar, FALSE);
853 m_htLast = ht;
854
855 if ( !isArrow )
856 Highlight(scrollbar, TRUE);
857 //else: already done by wxScrollArrows::HandleMouseMove
858 }
859 else if ( event.Leaving() )
860 {
861 if ( !isArrow )
862 Highlight(scrollbar, FALSE);
863
864 m_htLast = wxHT_NOWHERE;
865 }
866 else // event.Entering()
867 {
868 // we don't process this event
869 return FALSE;
870 }
871
872 // we did something
873 return TRUE;
874}
875
876#endif // wxUSE_SCROLLBAR
877
878// ----------------------------------------------------------------------------
879// wxScrollTimer
880// ----------------------------------------------------------------------------
881
882wxScrollTimer::wxScrollTimer()
883{
884 m_skipNext = FALSE;
885}
886
887void wxScrollTimer::StartAutoScroll()
888{
889 // start scrolling immediately
890 if ( !DoNotify() )
891 {
892 // ... and end it too
893 return;
894 }
895
896 // there is an initial delay before the scrollbar starts scrolling -
897 // implement it by ignoring the first timer expiration and only start
898 // scrolling from the second one
899 m_skipNext = TRUE;
900 Start(200); // FIXME: hardcoded delay
901}
902
903void wxScrollTimer::Notify()
904{
905 if ( m_skipNext )
906 {
907 // scroll normally now - reduce the delay
908 Stop();
909 Start(50); // FIXME: hardcoded delay
910
911 m_skipNext = FALSE;
912 }
913 else
914 {
915 // if DoNotify() returns false, we're already deleted by the timer
916 // event handler, so don't do anything else here
917 (void)DoNotify();
918 }
919}
920