1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
27 #include "wx/window.h"
30 #include "wx/renderer.h"
31 #include "wx/univ/scrtimer.h"
32 #include "wx/univ/scrthumb.h"
34 // ----------------------------------------------------------------------------
35 // wxScrollThumbCaptureData: the struct used while dragging the scroll thumb
36 // ----------------------------------------------------------------------------
38 struct WXDLLEXPORT wxScrollThumbCaptureData
40 // start mouse capture after the user clicked the mouse button btn on this
41 // part of the control
42 wxScrollThumbCaptureData(wxScrollThumb::Shaft part
,
44 wxControlWithThumb
*control
)
50 m_window
= control
->GetWindow();
51 m_window
->CaptureMouse();
55 ~wxScrollThumbCaptureData()
59 m_window
->ReleaseMouse();
67 // the thumb part being held pressed
68 wxScrollThumb::Shaft m_shaftPart
;
70 // the mouse button which started the capture (-1 if none)
73 // the window which has captured the mouse
76 // the offset between the mouse position and the start of the thumb which
77 // is kept constant while dragging the thumb
80 // the timer for generating the scroll events when scrolling by page
81 wxScrollTimer
*m_timerScroll
;
84 // ----------------------------------------------------------------------------
85 // wxScrollTimer: the timer used when the arrow is kept pressed
86 // ----------------------------------------------------------------------------
90 class wxScrollThumbTimer
: public wxScrollTimer
93 wxScrollThumbTimer(wxControlWithThumb
*control
,
94 wxScrollThumb::Shaft shaftPart
)
99 case wxScrollThumb::Shaft_Above
:
104 wxFAIL_MSG(wxT("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 #endif // wxUSE_TIMER
129 // ============================================================================
131 // ============================================================================
133 // ----------------------------------------------------------------------------
134 // wxScrollThumb constructor and dtor
135 // ----------------------------------------------------------------------------
137 wxScrollThumb::wxScrollThumb(wxControlWithThumb
*control
)
139 m_shaftPart
= Shaft_None
;
141 m_captureData
= NULL
;
144 wxScrollThumb::~wxScrollThumb()
146 // it should have been destroyed
147 wxASSERT_MSG( !m_captureData
, wxT("memory leak in wxScrollThumb") );
150 // ----------------------------------------------------------------------------
151 // wxScrollThumb mouse handling
152 // ----------------------------------------------------------------------------
154 bool wxScrollThumb::HandleMouse(const wxMouseEvent
& event
) const
156 // is this a click event?
157 int btn
= event
.GetButton();
164 // when the mouse is pressed on any scrollbar element, we capture it
165 // and hold capture until the same mouse button is released
166 if ( event
.ButtonDown() || event
.ButtonDClick() )
170 // mouse already captured, nothing to do
174 // determine which part of the window the user clicked in
175 Shaft shaftPart
= m_control
->HitTest(event
.GetPosition());
177 if ( shaftPart
== Shaft_None
)
179 // mouse pressed over something else
184 wxConstCast(this, wxScrollThumb
)->m_captureData
=
185 new wxScrollThumbCaptureData(shaftPart
, btn
, m_control
);
187 // modify the visual appearance before sending the event which will
189 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
);
191 if ( shaftPart
== Shaft_Thumb
)
193 // save the mouse offset from the thumb position - we will keep it
194 // constant while dragging the thumb
195 m_captureData
->m_ofsMouse
=
196 GetMouseCoord(event
) - m_control
->ThumbPosToPixel();
198 // generate an additional event if we start dragging the thumb
199 m_control
->OnThumbDragStart(GetThumbPos(event
));
202 else // not the thumb
204 // start timer for auto scrolling when the user presses the mouse
205 // in the shaft above or below the thumb
206 m_captureData
->m_timerScroll
=
207 new wxScrollThumbTimer(m_control
, shaftPart
);
209 #endif // wxUSE_TIMER
211 // release mouse if the *same* button went up
212 else if ( HasCapture() && (btn
== m_captureData
->m_btnCapture
) )
214 Shaft shaftPart
= m_captureData
->m_shaftPart
;
216 // if we were dragging the thumb, send the one last event
217 if ( shaftPart
== Shaft_Thumb
)
219 m_control
->OnThumbDragEnd(GetThumbPos(event
));
222 // release the mouse and free capture data
223 delete m_captureData
;
224 wxConstCast(this, wxScrollThumb
)->m_captureData
= NULL
;
226 m_control
->SetShaftPartState(shaftPart
, wxCONTROL_PRESSED
, false);
228 else // another mouse button released
230 // we don't process this
237 bool wxScrollThumb::HandleMouseMove(const wxMouseEvent
& event
) const
241 if ( (m_captureData
->m_shaftPart
== Shaft_Thumb
) && event
.Moving() )
243 // make the thumb follow the mouse by keeping the same offset
244 // between the mouse position and the top/left of the thumb
245 m_control
->OnThumbDrag(GetThumbPos(event
));
248 // we process all mouse events while the mouse is captured by us
254 if ( event
.Leaving() )
256 // no part of the shaft has mouse if it left the window completely
257 shaftPart
= Shaft_None
;
259 else // Moving() or Entering(), treat them the same here
261 shaftPart
= m_control
->HitTest(event
.GetPosition());
264 if ( shaftPart
!= m_shaftPart
)
266 // update the highlighted state
267 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, false);
268 wxConstCast(this, wxScrollThumb
)->m_shaftPart
= shaftPart
;
269 m_control
->SetShaftPartState(m_shaftPart
, wxCONTROL_CURRENT
, true);
272 // if the event happened on the shaft, it was for us and we processed
274 return shaftPart
!= Shaft_None
;
278 wxCoord
wxScrollThumb::GetMouseCoord(const wxMouseEvent
& event
) const
280 wxPoint pt
= event
.GetPosition();
281 return m_control
->IsVertical() ? pt
.y
: pt
.x
;
284 int wxScrollThumb::GetThumbPos(const wxMouseEvent
& event
) const
286 wxCHECK_MSG( m_captureData
&& m_captureData
->m_shaftPart
== Shaft_Thumb
, 0,
287 wxT("can't be called when thumb is not dragged") );
289 int x
= GetMouseCoord(event
) - m_captureData
->m_ofsMouse
;
290 return m_control
->PixelToThumbPos(x
);