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