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