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