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