1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/scrthumb.cpp
3 // Purpose: wxScrollThumb and related classes
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
26 #include "wx/window.h"
29 #include "wx/renderer.h"
30 #include "wx/univ/scrtimer.h"
31 #include "wx/univ/scrthumb.h"
33 // ----------------------------------------------------------------------------
34 // wxScrollThumbCaptureData: the struct used while dragging the scroll thumb
35 // ----------------------------------------------------------------------------
37 struct WXDLLEXPORT wxScrollThumbCaptureData
39 // start mouse capture after the user clicked the mouse button btn on this
40 // part of the control
41 wxScrollThumbCaptureData(wxScrollThumb::Shaft part
,
43 wxControlWithThumb
*control
)
49 m_window
= control
->GetWindow();
50 m_window
->CaptureMouse();
54 ~wxScrollThumbCaptureData()
58 m_window
->ReleaseMouse();
66 // the thumb part being held pressed
67 wxScrollThumb::Shaft m_shaftPart
;
69 // the mouse button which started the capture (-1 if none)
72 // the window which has captured the mouse
75 // the offset between the mouse position and the start of the thumb which
76 // is kept constant while dragging the thumb
79 // the timer for generating the scroll events when scrolling by page
80 wxScrollTimer
*m_timerScroll
;
83 // ----------------------------------------------------------------------------
84 // wxScrollTimer: the timer used when the arrow is kept pressed
85 // ----------------------------------------------------------------------------
89 class wxScrollThumbTimer
: public wxScrollTimer
92 wxScrollThumbTimer(wxControlWithThumb
*control
,
93 wxScrollThumb::Shaft shaftPart
)
98 case wxScrollThumb::Shaft_Above
:
103 wxFAIL_MSG(wxT("unexpected shaft part in wxScrollThumbTimer"));
106 case wxScrollThumb::Shaft_Below
:
111 m_control
->OnPageScrollStart();
117 virtual bool DoNotify()
119 return m_control
->OnPageScroll(m_inc
);
122 wxControlWithThumb
*m_control
;
126 #endif // wxUSE_TIMER
128 // ============================================================================
130 // ============================================================================
132 // ----------------------------------------------------------------------------
133 // wxScrollThumb constructor and dtor
134 // ----------------------------------------------------------------------------
136 wxScrollThumb::wxScrollThumb(wxControlWithThumb
*control
)
138 m_shaftPart
= Shaft_None
;
140 m_captureData
= NULL
;
143 wxScrollThumb::~wxScrollThumb()
145 // it should have been destroyed
146 wxASSERT_MSG( !m_captureData
, wxT("memory leak in wxScrollThumb") );
149 // ----------------------------------------------------------------------------
150 // wxScrollThumb mouse handling
151 // ----------------------------------------------------------------------------
153 bool wxScrollThumb::HandleMouse(const wxMouseEvent
& event
) const
155 // is this a click event?
156 int btn
= event
.GetButton();
163 // when the mouse is pressed on any scrollbar element, we capture it
164 // and hold capture until the same mouse button is released
165 if ( event
.ButtonDown() || event
.ButtonDClick() )
169 // mouse already captured, nothing to do
173 // determine which part of the window the user clicked in
174 Shaft shaftPart
= m_control
->HitTest(event
.GetPosition());
176 if ( shaftPart
== Shaft_None
)
178 // mouse pressed over something else
183 wxConstCast(this, wxScrollThumb
)->m_captureData
=
184 new wxScrollThumbCaptureData(shaftPart
, btn
, m_control
);
186 // modify the visual appearance before sending the event which will
188 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
);
190 if ( shaftPart
== Shaft_Thumb
)
192 // save the mouse offset from the thumb position - we will keep it
193 // constant while dragging the thumb
194 m_captureData
->m_ofsMouse
=
195 GetMouseCoord(event
) - m_control
->ThumbPosToPixel();
197 // generate an additional event if we start dragging the thumb
198 m_control
->OnThumbDragStart(GetThumbPos(event
));
201 else // not the thumb
203 // start timer for auto scrolling when the user presses the mouse
204 // in the shaft above or below the thumb
205 m_captureData
->m_timerScroll
=
206 new wxScrollThumbTimer(m_control
, shaftPart
);
208 #endif // wxUSE_TIMER
210 // release mouse if the *same* button went up
211 else if ( HasCapture() && (btn
== m_captureData
->m_btnCapture
) )
213 Shaft shaftPart
= m_captureData
->m_shaftPart
;
215 // if we were dragging the thumb, send the one last event
216 if ( shaftPart
== Shaft_Thumb
)
218 m_control
->OnThumbDragEnd(GetThumbPos(event
));
221 // release the mouse and free capture data
222 delete m_captureData
;
223 wxConstCast(this, wxScrollThumb
)->m_captureData
= NULL
;
225 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
, false);
227 else // another mouse button released
229 // we don't process this
236 bool wxScrollThumb::HandleMouseMove(const wxMouseEvent
& event
) const
240 if ( (m_captureData
->m_shaftPart
== Shaft_Thumb
) && event
.Moving() )
242 // make the thumb follow the mouse by keeping the same offset
243 // between the mouse position and the top/left of the thumb
244 m_control
->OnThumbDrag(GetThumbPos(event
));
247 // we process all mouse events while the mouse is captured by us
253 if ( event
.Leaving() )
255 // no part of the shaft has mouse if it left the window completely
256 shaftPart
= Shaft_None
;
258 else // Moving() or Entering(), treat them the same here
260 shaftPart
= m_control
->HitTest(event
.GetPosition());
263 if ( shaftPart
!= m_shaftPart
)
265 // update the highlighted state
266 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, false);
267 wxConstCast(this, wxScrollThumb
)->m_shaftPart
= shaftPart
;
268 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, true);
271 // if the event happened on the shaft, it was for us and we processed
273 return shaftPart
!= Shaft_None
;
277 wxCoord
wxScrollThumb::GetMouseCoord(const wxMouseEvent
& event
) const
279 wxPoint pt
= event
.GetPosition();
280 return m_control
->IsVertical() ? pt
.y
: pt
.x
;
283 int wxScrollThumb::GetThumbPos(const wxMouseEvent
& event
) const
285 wxCHECK_MSG( m_captureData
&& m_captureData
->m_shaftPart
== Shaft_Thumb
, 0,
286 wxT("can't be called when thumb is not dragged") );
288 int x
= GetMouseCoord(event
) - m_captureData
->m_ofsMouse
;
289 return m_control
->PixelToThumbPos(x
);