1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/scrthumb.cpp
3 // Purpose: wxScrollThumb and related classes
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "univscrthumb.h"
24 #include "wx/wxprec.h"
31 #include "wx/window.h"
32 #include "wx/renderer.h"
35 #include "wx/univ/scrtimer.h"
36 #include "wx/univ/scrthumb.h"
38 // ----------------------------------------------------------------------------
39 // wxScrollThumbCaptureData: the struct used while dragging the scroll thumb
40 // ----------------------------------------------------------------------------
42 struct WXDLLEXPORT wxScrollThumbCaptureData
44 // start mouse capture after the user clicked the mouse button btn on this
45 // part of the control
46 wxScrollThumbCaptureData(wxScrollThumb::Shaft part
,
48 wxControlWithThumb
*control
)
54 m_window
= control
->GetWindow();
55 m_window
->CaptureMouse();
59 ~wxScrollThumbCaptureData()
63 m_window
->ReleaseMouse();
69 // the thumb part being held pressed
70 wxScrollThumb::Shaft m_shaftPart
;
72 // the mouse button which started the capture (-1 if none)
75 // the window which has captured the mouse
78 // the offset between the mouse position and the start of the thumb which
79 // is kept constant while dragging the thumb
82 // the timer for generating the scroll events when scrolling by page
83 wxScrollTimer
*m_timerScroll
;
86 // ----------------------------------------------------------------------------
87 // wxScrollTimer: the timer used when the arrow is kept pressed
88 // ----------------------------------------------------------------------------
90 class wxScrollThumbTimer
: public wxScrollTimer
93 wxScrollThumbTimer(wxControlWithThumb
*control
,
94 wxScrollThumb::Shaft shaftPart
)
99 case wxScrollThumb::Shaft_Above
:
104 wxFAIL_MSG(_T("unexpected shaft part in wxScrollThumbTimer"));
107 case wxScrollThumb::Shaft_Below
:
112 m_control
->OnPageScrollStart();
118 virtual bool DoNotify()
120 return m_control
->OnPageScroll(m_inc
);
123 wxControlWithThumb
*m_control
;
127 // ============================================================================
129 // ============================================================================
131 // ----------------------------------------------------------------------------
132 // wxScrollThumb constructor and dtor
133 // ----------------------------------------------------------------------------
135 wxScrollThumb::wxScrollThumb(wxControlWithThumb
*control
)
137 m_shaftPart
= Shaft_None
;
139 m_captureData
= NULL
;
142 wxScrollThumb::~wxScrollThumb()
144 // it should have been destroyed
145 wxASSERT_MSG( !m_captureData
, _T("memory leak in wxScrollThumb") );
148 // ----------------------------------------------------------------------------
149 // wxScrollThumb mouse handling
150 // ----------------------------------------------------------------------------
152 bool wxScrollThumb::HandleMouse(const wxMouseEvent
& event
) const
154 // is this a click event?
155 int btn
= event
.GetButton();
162 // when the mouse is pressed on any scrollbar element, we capture it
163 // and hold capture until the same mouse button is released
164 if ( event
.ButtonDown() || event
.ButtonDClick() )
168 // mouse already captured, nothing to do
172 // determine which part of the window the user clicked in
173 Shaft shaftPart
= m_control
->HitTest(event
.GetPosition());
175 if ( shaftPart
== Shaft_None
)
177 // mouse pressed over something else
182 wxConstCast(this, wxScrollThumb
)->m_captureData
=
183 new wxScrollThumbCaptureData(shaftPart
, btn
, m_control
);
185 // modify the visual appearance before sending the event which will
187 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
);
189 if ( shaftPart
== Shaft_Thumb
)
191 // save the mouse offset from the thumb position - we will keep it
192 // constant while dragging the thumb
193 m_captureData
->m_ofsMouse
=
194 GetMouseCoord(event
) - m_control
->ThumbPosToPixel();
196 // generate an additional event if we start dragging the thumb
197 m_control
->OnThumbDragStart(GetThumbPos(event
));
199 else // not the thumb
201 // start timer for auto scrolling when the user presses the mouse
202 // in the shaft above or below the thumb
203 m_captureData
->m_timerScroll
=
204 new wxScrollThumbTimer(m_control
, shaftPart
);
207 // release mouse if the *same* button went up
208 else if ( HasCapture() && (btn
== m_captureData
->m_btnCapture
) )
210 Shaft shaftPart
= m_captureData
->m_shaftPart
;
212 // if we were dragging the thumb, send the one last event
213 if ( shaftPart
== Shaft_Thumb
)
215 m_control
->OnThumbDragEnd(GetThumbPos(event
));
218 // release the mouse and free capture data
219 delete m_captureData
;
220 wxConstCast(this, wxScrollThumb
)->m_captureData
= NULL
;
222 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
, FALSE
);
224 else // another mouse button released
226 // we don't process this
233 bool wxScrollThumb::HandleMouseMove(const wxMouseEvent
& event
) const
237 if ( (m_captureData
->m_shaftPart
== Shaft_Thumb
) && event
.Moving() )
239 // make the thumb follow the mouse by keeping the same offset
240 // between the mouse position and the top/left of the thumb
241 m_control
->OnThumbDrag(GetThumbPos(event
));
244 // we process all mouse events while the mouse is captured by us
250 if ( event
.Leaving() )
252 // no part of the shaft has mouse if it left the window completely
253 shaftPart
= Shaft_None
;
255 else // Moving() or Entering(), treat them the same here
257 shaftPart
= m_control
->HitTest(event
.GetPosition());
260 if ( shaftPart
!= m_shaftPart
)
262 // update the highlighted state
263 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, FALSE
);
264 wxConstCast(this, wxScrollThumb
)->m_shaftPart
= shaftPart
;
265 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, TRUE
);
268 // if the event happened on the shaft, it was for us and we processed
270 return shaftPart
!= Shaft_None
;
274 wxCoord
wxScrollThumb::GetMouseCoord(const wxMouseEvent
& event
) const
276 wxPoint pt
= event
.GetPosition();
277 return m_control
->IsVertical() ? pt
.y
: pt
.x
;
280 int wxScrollThumb::GetThumbPos(const wxMouseEvent
& event
) const
282 wxCHECK_MSG( m_captureData
&& m_captureData
->m_shaftPart
== Shaft_Thumb
, 0,
283 _T("can't be called when thumb is not dragged") );
285 int x
= GetMouseCoord(event
) - m_captureData
->m_ofsMouse
;
286 return m_control
->PixelToThumbPos(x
);