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::HitTest(const wxPoint
& pt
) const 
 303     switch ( m_renderer
->HitTestScrollbar(this, 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 // ---------------------------------------------------------------------------- 
 318 // ---------------------------------------------------------------------------- 
 320 void wxScrollBar::OnInternalIdle() 
 323     wxControl::OnInternalIdle(); 
 326 void wxScrollBar::UpdateThumb() 
 330         for ( size_t n 
= 0; n 
< WXSIZEOF(m_elementsState
); n
++ ) 
 332             if ( m_elementsState
[n
] & wxCONTROL_DIRTY 
) 
 334                 wxRect rect 
= GetRenderer()->GetScrollbarRect(this, (Element
)n
); 
 336                 if ( rect
.width 
&& rect
.height 
) 
 338                     // we try to avoid redrawing the entire shaft (which might 
 339                     // be quite long) if possible by only redrawing the area 
 340                     // wich really changed 
 341                     if ( (n 
== Element_Bar_1 
|| n 
== Element_Bar_2
) && 
 342                             (m_thumbPosOld 
!= -1) ) 
 344                         // the less efficient but more reliable (i.e. this will 
 345                         // probably work everywhere) version: refresh the 
 346                         // distance covered by thumb since the last update 
 349                             GetRenderer()->GetScrollbarRect(this, 
 354                             if ( n 
== Element_Bar_1 
) 
 355                                 rect
.SetTop(rectOld
.GetBottom()); 
 357                                 rect
.SetBottom(rectOld
.GetBottom()); 
 361                             if ( n 
== Element_Bar_1 
) 
 362                                 rect
.SetLeft(rectOld
.GetRight()); 
 364                                 rect
.SetRight(rectOld
.GetRight()); 
 366 #else                   // efficient version: only repaint the area occupied by 
 367                         // the thumb previously - we can't do better than this 
 368                         rect 
= GetRenderer()->GetScrollbarRect(this, 
 374 #ifdef WXDEBUG_SCROLLBAR 
 375         static bool s_refreshDebug 
= false; 
 376         if ( s_refreshDebug 
) 
 379             dc
.SetBrush(*wxCYAN_BRUSH
); 
 380             dc
.SetPen(*wxTRANSPARENT_PEN
); 
 381             dc
.DrawRectangle(rect
); 
 383             // under Unix we use "--sync" X option for this 
 384             #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 389 #endif // WXDEBUG_SCROLLBAR 
 391                     Refresh(false, &rect
); 
 394                 m_elementsState
[n
] &= ~wxCONTROL_DIRTY
; 
 402 void wxScrollBar::DoDraw(wxControlRenderer 
*renderer
) 
 404     renderer
->DrawScrollbar(this, m_thumbPosOld
); 
 406     // clear all dirty flags 
 411 // ---------------------------------------------------------------------------- 
 413 // ---------------------------------------------------------------------------- 
 415 static inline wxScrollBar::Element 
ElementForArrow(wxScrollArrows::Arrow arrow
) 
 417     return arrow 
== wxScrollArrows::Arrow_First
 
 418             ? wxScrollBar::Element_Arrow_Line_1
 
 419             : wxScrollBar::Element_Arrow_Line_2
; 
 422 int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow
) const 
 424     return GetState(ElementForArrow(arrow
)); 
 427 void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow
, int flag
, bool set
) 
 429     Element which 
= ElementForArrow(arrow
); 
 430     int state 
= GetState(which
); 
 436     SetState(which
, state
); 
 439 int wxScrollBar::GetState(Element which
) const 
 441     // if the entire scrollbar is disabled, all of its elements are too 
 442     int flags 
= m_elementsState
[which
]; 
 444         flags 
|= wxCONTROL_DISABLED
; 
 449 void wxScrollBar::SetState(Element which
, int flags
) 
 451     if ( (int)(m_elementsState
[which
] & ~wxCONTROL_DIRTY
) != flags 
) 
 453         m_elementsState
[which
] = flags 
| wxCONTROL_DIRTY
; 
 459 // ---------------------------------------------------------------------------- 
 461 // ---------------------------------------------------------------------------- 
 463 bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow
) 
 465     int oldThumbPos 
= GetThumbPosition(); 
 466     PerformAction(arrow 
== wxScrollArrows::Arrow_First
 
 467                     ? wxACTION_SCROLL_LINE_UP
 
 468                     : wxACTION_SCROLL_LINE_DOWN
); 
 470     // did we scroll till the end? 
 471     return GetThumbPosition() != oldThumbPos
; 
 474 bool wxScrollBar::PerformAction(const wxControlAction
& action
, 
 476                                 const wxString
& strArg
) 
 478     int thumbOld 
= m_thumbPos
; 
 480     bool notify 
= false; // send an event about the change? 
 482     wxEventType scrollType
; 
 484     // test for thumb move first as these events happen in quick succession 
 485     if ( action 
== wxACTION_SCROLL_THUMB_MOVE 
) 
 489         // VS: we have to force redraw here, otherwise the thumb will lack 
 490         //     behind mouse cursor 
 493         scrollType 
= wxEVT_SCROLLWIN_THUMBTRACK
; 
 495     else if ( action 
== wxACTION_SCROLL_LINE_UP 
) 
 497         scrollType 
= wxEVT_SCROLLWIN_LINEUP
; 
 500     else if ( action 
== wxACTION_SCROLL_LINE_DOWN 
) 
 502         scrollType 
= wxEVT_SCROLLWIN_LINEDOWN
; 
 505     else if ( action 
== wxACTION_SCROLL_PAGE_UP 
) 
 507         scrollType 
= wxEVT_SCROLLWIN_PAGEUP
; 
 510     else if ( action 
== wxACTION_SCROLL_PAGE_DOWN 
) 
 512         scrollType 
= wxEVT_SCROLLWIN_PAGEDOWN
; 
 515     else if ( action 
== wxACTION_SCROLL_START 
) 
 517         scrollType 
= wxEVT_SCROLLWIN_THUMBRELEASE
; // anything better? 
 520     else if ( action 
== wxACTION_SCROLL_END 
) 
 522         scrollType 
= wxEVT_SCROLLWIN_THUMBRELEASE
; // anything better? 
 525     else if ( action 
== wxACTION_SCROLL_THUMB_DRAG 
) 
 527         // we won't use it but this line suppresses the compiler 
 528         // warning about "variable may be used without having been 
 530         scrollType 
= wxEVT_NULL
; 
 532     else if ( action 
== wxACTION_SCROLL_THUMB_RELEASE 
) 
 534         // always notify about this 
 536         scrollType 
= wxEVT_SCROLLWIN_THUMBRELEASE
; 
 539         return wxControl::PerformAction(action
, numArg
, strArg
); 
 541     // has scrollbar position changed? 
 542     bool changed 
= m_thumbPos 
!= thumbOld
; 
 543     if ( notify 
|| changed 
) 
 545         if ( IsStandalone() ) 
 547             // we should generate EVT_SCROLL events for the standalone 
 548             // scrollbars and not the EVT_SCROLLWIN ones 
 550             // NB: we assume that scrollbar events are sequentially numbered 
 551             //     but this should be ok as other code relies on this as well 
 552             scrollType 
+= wxEVT_SCROLL_TOP 
- wxEVT_SCROLLWIN_TOP
; 
 553             wxScrollEvent 
event(scrollType
, this->GetId(), m_thumbPos
, 
 554                                 IsVertical() ? wxVERTICAL 
: wxHORIZONTAL
); 
 555             event
.SetEventObject(this); 
 556             GetEventHandler()->ProcessEvent(event
); 
 558         else // part of the window 
 560             wxScrollWinEvent 
event(scrollType
, m_thumbPos
, 
 561                                    IsVertical() ? wxVERTICAL 
: wxHORIZONTAL
); 
 562             event
.SetEventObject(this); 
 563             GetParent()->GetEventHandler()->ProcessEvent(event
); 
 570 void wxScrollBar::ScrollToStart() 
 575 void wxScrollBar::ScrollToEnd() 
 577     DoSetThumb(m_range 
- m_thumbSize
); 
 580 bool wxScrollBar::ScrollLines(int nLines
) 
 582     DoSetThumb(m_thumbPos 
+ nLines
); 
 586 bool wxScrollBar::ScrollPages(int nPages
) 
 588     DoSetThumb(m_thumbPos 
+ nPages
*m_pageSize
); 
 593 wxInputHandler 
*wxScrollBar::GetStdInputHandler(wxInputHandler 
*handlerDef
) 
 595     static wxStdScrollBarInputHandler
 
 596         s_handler(wxTheme::Get()->GetRenderer(), handlerDef
); 
 601 // ============================================================================ 
 602 // scroll bar input handler 
 603 // ============================================================================ 
 605 // ---------------------------------------------------------------------------- 
 607 // ---------------------------------------------------------------------------- 
 609 wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler 
*handler
, 
 610                                    const wxControlAction
& action
, 
 611                                    wxScrollBar 
*control
) 
 618 bool wxScrollBarTimer::DoNotify() 
 620     return m_handler
->OnScrollTimer(m_control
, m_action
); 
 623 // ---------------------------------------------------------------------------- 
 624 // wxStdScrollBarInputHandler 
 625 // ---------------------------------------------------------------------------- 
 627 wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer 
*renderer
, 
 628                                                        wxInputHandler 
*handler
) 
 629                           : wxStdInputHandler(handler
) 
 631     m_renderer 
= renderer
; 
 633     m_htLast 
= wxHT_NOWHERE
; 
 634     m_timerScroll 
= NULL
; 
 637 wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler() 
 639     // normally, it's NULL by now but just in case the user somehow managed to 
 640     // keep the mouse captured until now... 
 641     delete m_timerScroll
; 
 644 void wxStdScrollBarInputHandler::SetElementState(wxScrollBar 
*control
, 
 648     if ( m_htLast 
> wxHT_SCROLLBAR_FIRST 
&& m_htLast 
< wxHT_SCROLLBAR_LAST 
) 
 651             elem 
= (wxScrollBar::Element
)(m_htLast 
- wxHT_SCROLLBAR_FIRST 
- 1); 
 653         int flags 
= control
->GetState(elem
); 
 658         control
->SetState(elem
, flags
); 
 662 bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar 
*scrollbar
, 
 663                                                const wxControlAction
& action
) 
 665     int oldThumbPos 
= scrollbar
->GetThumbPosition(); 
 666     scrollbar
->PerformAction(action
); 
 667     if ( scrollbar
->GetThumbPosition() != oldThumbPos 
) 
 670     // we scrolled till the end 
 671     m_timerScroll
->Stop(); 
 676 void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar 
*control
) 
 678     // return everything to the normal state 
 681         m_winCapture
->ReleaseMouse(); 
 689         delete m_timerScroll
; 
 690         m_timerScroll 
= NULL
; 
 693     // unpress the arrow and highlight the current element 
 694     Press(control
, false); 
 698 wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar 
*scrollbar
, 
 699                                           const wxMouseEvent
& event
) const 
 701     wxPoint pt 
= event
.GetPosition(); 
 702     return scrollbar
->GetWindowStyle() & wxVERTICAL 
? pt
.y 
: pt
.x
; 
 705 void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar 
*scrollbar
, 
 706                                                  const wxMouseEvent
& event
) 
 708     int thumbPos 
= GetMouseCoord(scrollbar
, event
) - m_ofsMouse
; 
 709     thumbPos 
= m_renderer
->PixelToScrollbar(scrollbar
, thumbPos
); 
 710     scrollbar
->PerformAction(wxACTION_SCROLL_THUMB_MOVE
, thumbPos
); 
 713 bool wxStdScrollBarInputHandler::HandleKey(wxInputConsumer 
*consumer
, 
 714                                            const wxKeyEvent
& event
, 
 717     // we only react to the key presses here 
 720         wxControlAction action
; 
 721         switch ( event
.GetKeyCode() ) 
 724             case WXK_RIGHT
:     action 
= wxACTION_SCROLL_LINE_DOWN
; break; 
 726             case WXK_LEFT
:      action 
= wxACTION_SCROLL_LINE_UP
;   break; 
 727             case WXK_HOME
:      action 
= wxACTION_SCROLL_START
;     break; 
 728             case WXK_END
:       action 
= wxACTION_SCROLL_END
;       break; 
 729             case WXK_PAGEUP
:    action 
= wxACTION_SCROLL_PAGE_UP
;   break; 
 730             case WXK_PAGEDOWN
:  action 
= wxACTION_SCROLL_PAGE_DOWN
; break; 
 733         if ( !action
.IsEmpty() ) 
 735             consumer
->PerformAction(action
); 
 741     return wxStdInputHandler::HandleKey(consumer
, event
, pressed
); 
 744 bool wxStdScrollBarInputHandler::HandleMouse(wxInputConsumer 
*consumer
, 
 745                                              const wxMouseEvent
& event
) 
 747     // is this a click event from an acceptable button? 
 748     int btn 
= event
.GetButton(); 
 749     if ( btn 
== wxMOUSE_BTN_LEFT 
) 
 751         // determine which part of the window mouse is in 
 752         wxScrollBar 
*scrollbar 
= wxStaticCast(consumer
->GetInputWindow(), wxScrollBar
); 
 753         wxHitTest ht 
= m_renderer
->HitTestScrollbar
 
 759         // when the mouse is pressed on any scrollbar element, we capture it 
 760         // and hold capture until the same mouse button is released 
 761         if ( event
.ButtonDown() || event
.ButtonDClick() ) 
 766                 m_winCapture 
= consumer
->GetInputWindow(); 
 767                 m_winCapture
->CaptureMouse(); 
 769                 // generate the command 
 770                 bool hasAction 
= true; 
 771                 wxControlAction action
; 
 774                     case wxHT_SCROLLBAR_ARROW_LINE_1
: 
 775                         action 
= wxACTION_SCROLL_LINE_UP
; 
 778                     case wxHT_SCROLLBAR_ARROW_LINE_2
: 
 779                         action 
= wxACTION_SCROLL_LINE_DOWN
; 
 782                     case wxHT_SCROLLBAR_BAR_1
: 
 783                         action 
= wxACTION_SCROLL_PAGE_UP
; 
 784                         m_ptStartScrolling 
= event
.GetPosition(); 
 787                     case wxHT_SCROLLBAR_BAR_2
: 
 788                         action 
= wxACTION_SCROLL_PAGE_DOWN
; 
 789                         m_ptStartScrolling 
= event
.GetPosition(); 
 792                     case wxHT_SCROLLBAR_THUMB
: 
 793                         consumer
->PerformAction(wxACTION_SCROLL_THUMB_DRAG
); 
 794                         m_ofsMouse 
= GetMouseCoord(scrollbar
, event
) - 
 795                                      m_renderer
->ScrollbarToPixel(scrollbar
); 
 797                         // fall through: there is no immediate action 
 803                 // remove highlighting 
 804                 Highlight(scrollbar
, false); 
 807                 // and press the arrow or highlight thumb now instead 
 808                 if ( m_htLast 
== wxHT_SCROLLBAR_THUMB 
) 
 809                     Highlight(scrollbar
, true); 
 811                     Press(scrollbar
, true); 
 816                     m_timerScroll 
= new wxScrollBarTimer(this, action
, 
 818                     m_timerScroll
->StartAutoScroll(); 
 820                 //else: no (immediate) action 
 823             //else: mouse already captured, nothing to do 
 825         // release mouse if the *same* button went up 
 826         else if ( btn 
== m_btnCapture 
) 
 830                 StopScrolling(scrollbar
); 
 832                 // if we were dragging the thumb, send the last event 
 833                 if ( m_htLast 
== wxHT_SCROLLBAR_THUMB 
) 
 835                     scrollbar
->PerformAction(wxACTION_SCROLL_THUMB_RELEASE
); 
 839                 Highlight(scrollbar
, true); 
 843                 // this is not supposed to happen as the button can't go up 
 844                 // without going down previously and then we'd have 
 845                 // m_winCapture by now 
 846                 wxFAIL_MSG( _T("logic error in mouse capturing code") ); 
 851     return wxStdInputHandler::HandleMouse(consumer
, event
); 
 854 bool wxStdScrollBarInputHandler::HandleMouseMove(wxInputConsumer 
*consumer
, 
 855                                                  const wxMouseEvent
& event
) 
 857     wxScrollBar 
*scrollbar 
= wxStaticCast(consumer
->GetInputWindow(), wxScrollBar
); 
 861         if ( (m_htLast 
== wxHT_SCROLLBAR_THUMB
) && event
.Dragging() ) 
 863             // make the thumb follow the mouse by keeping the same offset 
 864             // between the mouse position and the top/left of the thumb 
 865             HandleThumbMove(scrollbar
, event
); 
 870         // no other changes are possible while the mouse is captured 
 874     bool isArrow 
= scrollbar
->GetArrows().HandleMouseMove(event
); 
 876     if ( event
.Dragging() ) 
 878         wxHitTest ht 
= m_renderer
->HitTestScrollbar
 
 883         if ( ht 
== m_htLast 
) 
 890         wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht
); 
 891 #endif // DEBUG_MOUSE 
 893         Highlight(scrollbar
, false); 
 897             Highlight(scrollbar
, true); 
 898         //else: already done by wxScrollArrows::HandleMouseMove 
 900     else if ( event
.Leaving() ) 
 903             Highlight(scrollbar
, false); 
 905         m_htLast 
= wxHT_NOWHERE
; 
 907     else // event.Entering() 
 909         // we don't process this event 
 917 #endif // wxUSE_SCROLLBAR 
 921 // ---------------------------------------------------------------------------- 
 923 // ---------------------------------------------------------------------------- 
 925 wxScrollTimer::wxScrollTimer() 
 930 void wxScrollTimer::StartAutoScroll() 
 932     // start scrolling immediately 
 935         // ... and end it too 
 939     // there is an initial delay before the scrollbar starts scrolling - 
 940     // implement it by ignoring the first timer expiration and only start 
 941     // scrolling from the second one 
 943     Start(200); // FIXME: hardcoded delay 
 946 void wxScrollTimer::Notify() 
 950         // scroll normally now - reduce the delay 
 952         Start(50); // FIXME: hardcoded delay 
 958         // if DoNotify() returns false, we're already deleted by the timer 
 959         // event handler, so don't do anything else here 
 964 #endif // wxUSE_TIMER