1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/scrolbar.cpp
3 // Purpose: wxScrollBar implementation
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
28 #include "wx/scrolbar.h"
32 #include "wx/dcclient.h"
33 #include "wx/validate.h"
37 #include "wx/univ/scrtimer.h"
39 #include "wx/univ/renderer.h"
40 #include "wx/univ/inphand.h"
41 #include "wx/univ/theme.h"
43 #define WXDEBUG_SCROLLBAR
46 #undef WXDEBUG_SCROLLBAR
47 #endif // !__WXDEBUG__
49 #if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
50 #include "wx/msw/private.h"
53 // ----------------------------------------------------------------------------
54 // wxScrollBarTimer: this class is used to repeatedly scroll the scrollbar
55 // when the mouse is help pressed on the arrow or on the bar. It generates the
56 // given scroll action command periodically.
57 // ----------------------------------------------------------------------------
59 class wxScrollBarTimer
: public wxScrollTimer
62 wxScrollBarTimer(wxStdScrollBarInputHandler
*handler
,
63 const wxControlAction
& action
,
64 wxScrollBar
*control
);
67 virtual bool DoNotify();
70 wxStdScrollBarInputHandler
*m_handler
;
71 wxControlAction m_action
;
72 wxScrollBar
*m_control
;
75 // ============================================================================
77 // ============================================================================
79 IMPLEMENT_DYNAMIC_CLASS(wxScrollBar
, wxControl
)
81 BEGIN_EVENT_TABLE(wxScrollBar
, wxScrollBarBase
)
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
89 // warning C4355: 'this' : used in base member initializer list
90 #pragma warning(disable:4355) // so what? disable it...
93 wxScrollBar::wxScrollBar()
99 wxScrollBar::wxScrollBar(wxWindow
*parent
,
104 const wxValidator
& validator
,
105 const wxString
& name
)
110 (void)Create(parent
, id
, pos
, size
, style
, validator
, name
);
114 // warning C4355: 'this' : used in base member initializer list
115 #pragma warning(default:4355)
118 void wxScrollBar::Init()
127 for ( size_t n
= 0; n
< WXSIZEOF(m_elementsState
); n
++ )
129 m_elementsState
[n
] = 0;
135 bool wxScrollBar::Create(wxWindow
*parent
,
140 const wxValidator
& validator
,
141 const wxString
&name
)
143 // the scrollbars never have the border
144 style
&= ~wxBORDER_MASK
;
146 if ( !wxControl::Create(parent
, id
, pos
, size
, style
, validator
, name
) )
151 // override the cursor of the target window (if any)
152 SetCursor(wxCURSOR_ARROW
);
154 CreateInputHandler(wxINP_HANDLER_SCROLLBAR
);
159 wxScrollBar::~wxScrollBar()
163 // ----------------------------------------------------------------------------
165 // ----------------------------------------------------------------------------
167 bool wxScrollBar::IsStandalone() const
169 wxWindow
*parent
= GetParent();
175 return (parent
->GetScrollbar(wxHORIZONTAL
) != this) &&
176 (parent
->GetScrollbar(wxVERTICAL
) != this);
179 bool wxScrollBar::AcceptsFocus() const
181 // the window scrollbars never accept focus
182 return wxScrollBarBase::AcceptsFocus() && IsStandalone();
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 void wxScrollBar::DoSetThumb(int pos
)
191 // don't assert hecks here, we're a private function which is meant to be
192 // called with any args at all
197 else if ( pos
> m_range
- m_thumbSize
)
199 pos
= m_range
- m_thumbSize
;
202 if ( m_thumbPos
== pos
)
204 // nothing changed, avoid refreshes which would provoke flicker
208 if ( m_thumbPosOld
== -1 )
210 // remember the old thumb position
211 m_thumbPosOld
= m_thumbPos
;
216 // we have to refresh the part of the bar which was under the thumb and the
218 m_elementsState
[Element_Thumb
] |= wxCONTROL_DIRTY
;
219 m_elementsState
[m_thumbPos
> m_thumbPosOld
220 ? Element_Bar_1
: Element_Bar_2
] |= wxCONTROL_DIRTY
;
224 int wxScrollBar::GetThumbPosition() const
229 int wxScrollBar::GetThumbSize() const
234 int wxScrollBar::GetPageSize() const
239 int wxScrollBar::GetRange() const
244 void wxScrollBar::SetThumbPosition(int pos
)
246 wxCHECK_RET( pos
>= 0 && pos
<= m_range
, _T("thumb position out of range") );
251 void wxScrollBar::SetScrollbar(int position
, int thumbSize
,
252 int range
, int pageSize
,
255 // we only refresh everything when the range changes, thumb position
256 // changes are handled in OnIdle
257 bool needsRefresh
= (range
!= m_range
) ||
258 (thumbSize
!= m_thumbSize
) ||
259 (pageSize
!= m_pageSize
);
261 // set all parameters
263 m_thumbSize
= thumbSize
;
264 SetThumbPosition(position
);
265 m_pageSize
= pageSize
;
267 // ignore refresh parameter unless we really need to refresh everything -
268 // there ir a lot of existing code which just calls SetScrollbar() without
269 // specifying the last parameter even though it doesn't need at all to
270 // refresh the window immediately
271 if ( refresh
&& needsRefresh
)
273 // and update the window
279 // ----------------------------------------------------------------------------
281 // ----------------------------------------------------------------------------
283 wxSize
wxScrollBar::DoGetBestClientSize() const
285 // this dimension is completely arbitrary
286 static const wxCoord SIZE
= 140;
288 wxSize size
= m_renderer
->GetScrollbarArrowSize();
301 wxScrollArrows::Arrow
wxScrollBar::HitTestArrow(const wxPoint
& pt
) const
303 switch ( HitTestBar(pt
) )
305 case wxHT_SCROLLBAR_ARROW_LINE_1
:
306 return wxScrollArrows::Arrow_First
;
308 case wxHT_SCROLLBAR_ARROW_LINE_2
:
309 return wxScrollArrows::Arrow_Second
;
312 return wxScrollArrows::Arrow_None
;
316 wxHitTest
wxScrollBar::HitTestBar(const wxPoint
& pt
) const
318 // we only need to work with either x or y coord depending on the
319 // orientation, choose one (but still check the other one to verify if the
320 // mouse is in the window at all)
321 const wxSize sizeArrowSB
= m_renderer
->GetScrollbarArrowSize();
323 wxCoord coord
, sizeArrow
, sizeTotal
;
324 wxSize size
= GetSize();
325 if ( GetWindowStyle() & wxVERTICAL
)
327 if ( pt
.x
< 0 || pt
.x
> size
.x
)
331 sizeArrow
= sizeArrowSB
.y
;
336 if ( pt
.y
< 0 || pt
.y
> size
.y
)
340 sizeArrow
= sizeArrowSB
.x
;
344 // test for the arrows first as it's faster
345 if ( coord
< 0 || coord
> sizeTotal
)
349 else if ( coord
< sizeArrow
)
351 return wxHT_SCROLLBAR_ARROW_LINE_1
;
353 else if ( coord
> sizeTotal
- sizeArrow
)
355 return wxHT_SCROLLBAR_ARROW_LINE_2
;
359 // calculate the thumb position in pixels
360 sizeTotal
-= 2*sizeArrow
;
361 wxCoord thumbStart
, thumbEnd
;
362 int range
= GetRange();
365 // clicking the scrollbar without range has no effect
370 GetScrollBarThumbSize(sizeTotal
,
378 // now compare with the thumb position
380 if ( coord
< thumbStart
)
381 return wxHT_SCROLLBAR_BAR_1
;
382 else if ( coord
> thumbEnd
)
383 return wxHT_SCROLLBAR_BAR_2
;
385 return wxHT_SCROLLBAR_THUMB
;
390 void wxScrollBar::GetScrollBarThumbSize(wxCoord length
,
397 // the thumb can't be made less than this number of pixels
398 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
400 *thumbStart
= (length
*thumbPos
) / range
;
401 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
403 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
405 // adjust the end if possible
406 if ( *thumbStart
<= length
- thumbMinWidth
)
408 // yes, just make it wider
409 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
411 else // it is at the bottom of the scrollbar
413 // so move it a bit up
414 *thumbStart
= length
- thumbMinWidth
;
420 wxRect
wxScrollBar::GetScrollbarRect(wxScrollBar::Element elem
,
423 if ( thumbPos
== -1 )
425 thumbPos
= GetThumbPosition();
428 const wxSize sizeArrow
= m_renderer
->GetScrollbarArrowSize();
430 wxSize sizeTotal
= GetClientSize();
431 wxCoord
*start
, *width
;
432 wxCoord length
, arrow
;
437 rect
.width
= sizeTotal
.x
;
438 length
= sizeTotal
.y
;
440 width
= &rect
.height
;
446 rect
.height
= sizeTotal
.y
;
447 length
= sizeTotal
.x
;
455 case wxScrollBar::Element_Arrow_Line_1
:
460 case wxScrollBar::Element_Arrow_Line_2
:
461 *start
= length
- arrow
;
465 case wxScrollBar::Element_Arrow_Page_1
:
466 case wxScrollBar::Element_Arrow_Page_2
:
467 // we don't have them at all
470 case wxScrollBar::Element_Thumb
:
471 case wxScrollBar::Element_Bar_1
:
472 case wxScrollBar::Element_Bar_2
:
473 // we need to calculate the thumb position - do it
476 wxCoord thumbStart
, thumbEnd
;
477 int range
= GetRange();
485 GetScrollBarThumbSize(length
,
493 if ( elem
== wxScrollBar::Element_Thumb
)
496 *width
= thumbEnd
- thumbStart
;
498 else if ( elem
== wxScrollBar::Element_Bar_1
)
503 else // elem == wxScrollBar::Element_Bar_2
506 *width
= length
- thumbEnd
;
509 // everything is relative to the start of the shaft so far
514 case wxScrollBar::Element_Max
:
516 wxFAIL_MSG( _T("unknown scrollbar element") );
522 wxCoord
wxScrollBar::GetScrollbarSize() const
524 const wxSize sizeArrowSB
= m_renderer
->GetScrollbarArrowSize();
526 wxCoord sizeArrow
, sizeTotal
;
527 if ( GetWindowStyle() & wxVERTICAL
)
529 sizeArrow
= sizeArrowSB
.y
;
530 sizeTotal
= GetSize().y
;
534 sizeArrow
= sizeArrowSB
.x
;
535 sizeTotal
= GetSize().x
;
538 return sizeTotal
- 2*sizeArrow
;
542 wxCoord
wxScrollBar::ScrollbarToPixel(int thumbPos
)
544 int range
= GetRange();
547 // the only valid position anyhow
551 if ( thumbPos
== -1 )
553 // by default use the current thumb position
554 thumbPos
= GetThumbPosition();
557 const wxSize sizeArrow
= m_renderer
->GetScrollbarArrowSize();
558 return (thumbPos
* GetScrollbarSize()) / range
559 + (IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
562 int wxScrollBar::PixelToScrollbar(wxCoord coord
)
564 const wxSize sizeArrow
= m_renderer
->GetScrollbarArrowSize();
565 return ((coord
- (IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
566 GetRange() ) / GetScrollbarSize();
569 // ----------------------------------------------------------------------------
571 // ----------------------------------------------------------------------------
573 void wxScrollBar::OnInternalIdle()
576 wxControl::OnInternalIdle();
579 void wxScrollBar::UpdateThumb()
583 for ( size_t n
= 0; n
< WXSIZEOF(m_elementsState
); n
++ )
585 if ( m_elementsState
[n
] & wxCONTROL_DIRTY
)
587 wxRect rect
= GetScrollbarRect((Element
)n
);
589 if ( rect
.width
&& rect
.height
)
591 // we try to avoid redrawing the entire shaft (which might
592 // be quite long) if possible by only redrawing the area
593 // wich really changed
594 if ( (n
== Element_Bar_1
|| n
== Element_Bar_2
) &&
595 (m_thumbPosOld
!= -1) )
597 // the less efficient but more reliable (i.e. this will
598 // probably work everywhere) version: refresh the
599 // distance covered by thumb since the last update
602 GetRenderer()->GetScrollbarRect(this,
607 if ( n
== Element_Bar_1
)
608 rect
.SetTop(rectOld
.GetBottom());
610 rect
.SetBottom(rectOld
.GetBottom());
614 if ( n
== Element_Bar_1
)
615 rect
.SetLeft(rectOld
.GetRight());
617 rect
.SetRight(rectOld
.GetRight());
619 #else // efficient version: only repaint the area occupied by
620 // the thumb previously - we can't do better than this
621 rect
= GetScrollbarRect(Element_Thumb
, m_thumbPosOld
);
625 #ifdef WXDEBUG_SCROLLBAR
626 static bool s_refreshDebug
= false;
627 if ( s_refreshDebug
)
630 dc
.SetBrush(*wxCYAN_BRUSH
);
631 dc
.SetPen(*wxTRANSPARENT_PEN
);
632 dc
.DrawRectangle(rect
);
634 // under Unix we use "--sync" X option for this
635 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
640 #endif // WXDEBUG_SCROLLBAR
642 Refresh(false, &rect
);
645 m_elementsState
[n
] &= ~wxCONTROL_DIRTY
;
653 void wxScrollBar::DoDraw(wxControlRenderer
*renderer
)
655 renderer
->DrawScrollbar(this, m_thumbPosOld
);
657 // clear all dirty flags
662 // ----------------------------------------------------------------------------
664 // ----------------------------------------------------------------------------
666 static inline wxScrollBar::Element
ElementForArrow(wxScrollArrows::Arrow arrow
)
668 return arrow
== wxScrollArrows::Arrow_First
669 ? wxScrollBar::Element_Arrow_Line_1
670 : wxScrollBar::Element_Arrow_Line_2
;
673 int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow
) const
675 return GetState(ElementForArrow(arrow
));
678 void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow
, int flag
, bool set
)
680 Element which
= ElementForArrow(arrow
);
681 int state
= GetState(which
);
687 SetState(which
, state
);
690 int wxScrollBar::GetState(Element which
) const
692 // if the entire scrollbar is disabled, all of its elements are too
693 int flags
= m_elementsState
[which
];
695 flags
|= wxCONTROL_DISABLED
;
700 void wxScrollBar::SetState(Element which
, int flags
)
702 if ( (int)(m_elementsState
[which
] & ~wxCONTROL_DIRTY
) != flags
)
704 m_elementsState
[which
] = flags
| wxCONTROL_DIRTY
;
710 // ----------------------------------------------------------------------------
712 // ----------------------------------------------------------------------------
714 bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow
)
716 int oldThumbPos
= GetThumbPosition();
717 PerformAction(arrow
== wxScrollArrows::Arrow_First
718 ? wxACTION_SCROLL_LINE_UP
719 : wxACTION_SCROLL_LINE_DOWN
);
721 // did we scroll till the end?
722 return GetThumbPosition() != oldThumbPos
;
725 bool wxScrollBar::PerformAction(const wxControlAction
& action
,
727 const wxString
& strArg
)
729 int thumbOld
= m_thumbPos
;
731 bool notify
= false; // send an event about the change?
733 wxEventType scrollType
;
735 // test for thumb move first as these events happen in quick succession
736 if ( action
== wxACTION_SCROLL_THUMB_MOVE
)
740 // VS: we have to force redraw here, otherwise the thumb will lack
741 // behind mouse cursor
744 scrollType
= wxEVT_SCROLLWIN_THUMBTRACK
;
746 else if ( action
== wxACTION_SCROLL_LINE_UP
)
748 scrollType
= wxEVT_SCROLLWIN_LINEUP
;
751 else if ( action
== wxACTION_SCROLL_LINE_DOWN
)
753 scrollType
= wxEVT_SCROLLWIN_LINEDOWN
;
756 else if ( action
== wxACTION_SCROLL_PAGE_UP
)
758 scrollType
= wxEVT_SCROLLWIN_PAGEUP
;
761 else if ( action
== wxACTION_SCROLL_PAGE_DOWN
)
763 scrollType
= wxEVT_SCROLLWIN_PAGEDOWN
;
766 else if ( action
== wxACTION_SCROLL_START
)
768 scrollType
= wxEVT_SCROLLWIN_THUMBRELEASE
; // anything better?
771 else if ( action
== wxACTION_SCROLL_END
)
773 scrollType
= wxEVT_SCROLLWIN_THUMBRELEASE
; // anything better?
776 else if ( action
== wxACTION_SCROLL_THUMB_DRAG
)
778 // we won't use it but this line suppresses the compiler
779 // warning about "variable may be used without having been
781 scrollType
= wxEVT_NULL
;
783 else if ( action
== wxACTION_SCROLL_THUMB_RELEASE
)
785 // always notify about this
787 scrollType
= wxEVT_SCROLLWIN_THUMBRELEASE
;
790 return wxControl::PerformAction(action
, numArg
, strArg
);
792 // has scrollbar position changed?
793 bool changed
= m_thumbPos
!= thumbOld
;
794 if ( notify
|| changed
)
796 if ( IsStandalone() )
798 // we should generate EVT_SCROLL events for the standalone
799 // scrollbars and not the EVT_SCROLLWIN ones
801 // NB: we assume that scrollbar events are sequentially numbered
802 // but this should be ok as other code relies on this as well
803 scrollType
+= wxEVT_SCROLL_TOP
- wxEVT_SCROLLWIN_TOP
;
804 wxScrollEvent
event(scrollType
, this->GetId(), m_thumbPos
,
805 IsVertical() ? wxVERTICAL
: wxHORIZONTAL
);
806 event
.SetEventObject(this);
807 GetEventHandler()->ProcessEvent(event
);
809 else // part of the window
811 wxScrollWinEvent
event(scrollType
, m_thumbPos
,
812 IsVertical() ? wxVERTICAL
: wxHORIZONTAL
);
813 event
.SetEventObject(this);
814 GetParent()->GetEventHandler()->ProcessEvent(event
);
821 void wxScrollBar::ScrollToStart()
826 void wxScrollBar::ScrollToEnd()
828 DoSetThumb(m_range
- m_thumbSize
);
831 bool wxScrollBar::ScrollLines(int nLines
)
833 DoSetThumb(m_thumbPos
+ nLines
);
837 bool wxScrollBar::ScrollPages(int nPages
)
839 DoSetThumb(m_thumbPos
+ nPages
*m_pageSize
);
844 wxInputHandler
*wxScrollBar::GetStdInputHandler(wxInputHandler
*handlerDef
)
846 static wxStdScrollBarInputHandler
847 s_handler(wxTheme::Get()->GetRenderer(), handlerDef
);
852 // ============================================================================
853 // scroll bar input handler
854 // ============================================================================
856 // ----------------------------------------------------------------------------
858 // ----------------------------------------------------------------------------
860 wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler
*handler
,
861 const wxControlAction
& action
,
862 wxScrollBar
*control
)
869 bool wxScrollBarTimer::DoNotify()
871 return m_handler
->OnScrollTimer(m_control
, m_action
);
874 // ----------------------------------------------------------------------------
875 // wxStdScrollBarInputHandler
876 // ----------------------------------------------------------------------------
878 wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer
*renderer
,
879 wxInputHandler
*handler
)
880 : wxStdInputHandler(handler
)
882 m_renderer
= renderer
;
884 m_htLast
= wxHT_NOWHERE
;
885 m_timerScroll
= NULL
;
888 wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler()
890 // normally, it's NULL by now but just in case the user somehow managed to
891 // keep the mouse captured until now...
892 delete m_timerScroll
;
895 void wxStdScrollBarInputHandler::SetElementState(wxScrollBar
*control
,
899 if ( m_htLast
> wxHT_SCROLLBAR_FIRST
&& m_htLast
< wxHT_SCROLLBAR_LAST
)
902 elem
= (wxScrollBar::Element
)(m_htLast
- wxHT_SCROLLBAR_FIRST
- 1);
904 int flags
= control
->GetState(elem
);
909 control
->SetState(elem
, flags
);
913 bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar
*scrollbar
,
914 const wxControlAction
& action
)
916 int oldThumbPos
= scrollbar
->GetThumbPosition();
917 scrollbar
->PerformAction(action
);
918 if ( scrollbar
->GetThumbPosition() != oldThumbPos
)
921 // we scrolled till the end
922 m_timerScroll
->Stop();
927 void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar
*control
)
929 // return everything to the normal state
932 m_winCapture
->ReleaseMouse();
940 delete m_timerScroll
;
941 m_timerScroll
= NULL
;
944 // unpress the arrow and highlight the current element
945 Press(control
, false);
949 wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar
*scrollbar
,
950 const wxMouseEvent
& event
) const
952 wxPoint pt
= event
.GetPosition();
953 return scrollbar
->GetWindowStyle() & wxVERTICAL
? pt
.y
: pt
.x
;
956 void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar
*scrollbar
,
957 const wxMouseEvent
& event
)
959 int thumbPos
= GetMouseCoord(scrollbar
, event
) - m_ofsMouse
;
960 thumbPos
= scrollbar
->PixelToScrollbar(thumbPos
);
961 scrollbar
->PerformAction(wxACTION_SCROLL_THUMB_MOVE
, thumbPos
);
964 bool wxStdScrollBarInputHandler::HandleKey(wxInputConsumer
*consumer
,
965 const wxKeyEvent
& event
,
968 // we only react to the key presses here
971 wxControlAction action
;
972 switch ( event
.GetKeyCode() )
975 case WXK_RIGHT
: action
= wxACTION_SCROLL_LINE_DOWN
; break;
977 case WXK_LEFT
: action
= wxACTION_SCROLL_LINE_UP
; break;
978 case WXK_HOME
: action
= wxACTION_SCROLL_START
; break;
979 case WXK_END
: action
= wxACTION_SCROLL_END
; break;
980 case WXK_PAGEUP
: action
= wxACTION_SCROLL_PAGE_UP
; break;
981 case WXK_PAGEDOWN
: action
= wxACTION_SCROLL_PAGE_DOWN
; break;
984 if ( !action
.IsEmpty() )
986 consumer
->PerformAction(action
);
992 return wxStdInputHandler::HandleKey(consumer
, event
, pressed
);
995 bool wxStdScrollBarInputHandler::HandleMouse(wxInputConsumer
*consumer
,
996 const wxMouseEvent
& event
)
998 // is this a click event from an acceptable button?
999 int btn
= event
.GetButton();
1000 if ( btn
== wxMOUSE_BTN_LEFT
)
1002 // determine which part of the window mouse is in
1003 wxScrollBar
*scrollbar
= wxStaticCast(consumer
->GetInputWindow(), wxScrollBar
);
1004 wxHitTest ht
= scrollbar
->HitTest(event
.GetPosition());
1006 // when the mouse is pressed on any scrollbar element, we capture it
1007 // and hold capture until the same mouse button is released
1008 if ( event
.ButtonDown() || event
.ButtonDClick() )
1010 if ( !m_winCapture
)
1013 m_winCapture
= consumer
->GetInputWindow();
1014 m_winCapture
->CaptureMouse();
1016 // generate the command
1017 bool hasAction
= true;
1018 wxControlAction action
;
1021 case wxHT_SCROLLBAR_ARROW_LINE_1
:
1022 action
= wxACTION_SCROLL_LINE_UP
;
1025 case wxHT_SCROLLBAR_ARROW_LINE_2
:
1026 action
= wxACTION_SCROLL_LINE_DOWN
;
1029 case wxHT_SCROLLBAR_BAR_1
:
1030 action
= wxACTION_SCROLL_PAGE_UP
;
1031 m_ptStartScrolling
= event
.GetPosition();
1034 case wxHT_SCROLLBAR_BAR_2
:
1035 action
= wxACTION_SCROLL_PAGE_DOWN
;
1036 m_ptStartScrolling
= event
.GetPosition();
1039 case wxHT_SCROLLBAR_THUMB
:
1040 consumer
->PerformAction(wxACTION_SCROLL_THUMB_DRAG
);
1041 m_ofsMouse
= GetMouseCoord(scrollbar
, event
) -
1042 scrollbar
->ScrollbarToPixel();
1044 // fall through: there is no immediate action
1050 // remove highlighting
1051 Highlight(scrollbar
, false);
1054 // and press the arrow or highlight thumb now instead
1055 if ( m_htLast
== wxHT_SCROLLBAR_THUMB
)
1056 Highlight(scrollbar
, true);
1058 Press(scrollbar
, true);
1063 m_timerScroll
= new wxScrollBarTimer(this, action
,
1065 m_timerScroll
->StartAutoScroll();
1067 //else: no (immediate) action
1070 //else: mouse already captured, nothing to do
1072 // release mouse if the *same* button went up
1073 else if ( btn
== m_btnCapture
)
1077 StopScrolling(scrollbar
);
1079 // if we were dragging the thumb, send the last event
1080 if ( m_htLast
== wxHT_SCROLLBAR_THUMB
)
1082 scrollbar
->PerformAction(wxACTION_SCROLL_THUMB_RELEASE
);
1086 Highlight(scrollbar
, true);
1090 // this is not supposed to happen as the button can't go up
1091 // without going down previously and then we'd have
1092 // m_winCapture by now
1093 wxFAIL_MSG( _T("logic error in mouse capturing code") );
1098 return wxStdInputHandler::HandleMouse(consumer
, event
);
1101 bool wxStdScrollBarInputHandler::HandleMouseMove(wxInputConsumer
*consumer
,
1102 const wxMouseEvent
& event
)
1104 wxScrollBar
*scrollbar
= wxStaticCast(consumer
->GetInputWindow(), wxScrollBar
);
1108 if ( (m_htLast
== wxHT_SCROLLBAR_THUMB
) && event
.Dragging() )
1110 // make the thumb follow the mouse by keeping the same offset
1111 // between the mouse position and the top/left of the thumb
1112 HandleThumbMove(scrollbar
, event
);
1117 // no other changes are possible while the mouse is captured
1121 bool isArrow
= scrollbar
->GetArrows().HandleMouseMove(event
);
1123 if ( event
.Dragging() )
1125 wxHitTest ht
= scrollbar
->HitTestBar(event
.GetPosition());
1126 if ( ht
== m_htLast
)
1133 wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht
);
1134 #endif // DEBUG_MOUSE
1136 Highlight(scrollbar
, false);
1140 Highlight(scrollbar
, true);
1141 //else: already done by wxScrollArrows::HandleMouseMove
1143 else if ( event
.Leaving() )
1146 Highlight(scrollbar
, false);
1148 m_htLast
= wxHT_NOWHERE
;
1150 else // event.Entering()
1152 // we don't process this event
1160 #endif // wxUSE_SCROLLBAR
1164 // ----------------------------------------------------------------------------
1166 // ----------------------------------------------------------------------------
1168 wxScrollTimer::wxScrollTimer()
1173 void wxScrollTimer::StartAutoScroll()
1175 // start scrolling immediately
1178 // ... and end it too
1182 // there is an initial delay before the scrollbar starts scrolling -
1183 // implement it by ignoring the first timer expiration and only start
1184 // scrolling from the second one
1186 Start(200); // FIXME: hardcoded delay
1189 void wxScrollTimer::Notify()
1193 // scroll normally now - reduce the delay
1195 Start(50); // FIXME: hardcoded delay
1201 // if DoNotify() returns false, we're already deleted by the timer
1202 // event handler, so don't do anything else here
1207 #endif // wxUSE_TIMER