]> git.saurik.com Git - wxWidgets.git/blob - src/univ/scrthumb.cpp
Fixed bug which prevented toplevel window from reacting
[wxWidgets.git] / src / univ / scrthumb.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/scrthumb.cpp
3 // Purpose: wxScrollThumb and related classes
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 13.02.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "univscrthumb.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/window.h"
32 #endif // WX_PRECOMP
33
34 #include "wx/univ/scrtimer.h"
35 #include "wx/univ/scrthumb.h"
36
37 // ----------------------------------------------------------------------------
38 // wxScrollThumbCaptureData: the struct used while dragging the scroll thumb
39 // ----------------------------------------------------------------------------
40
41 struct WXDLLEXPORT wxScrollThumbCaptureData
42 {
43 // start mouse capture after the user clicked the mouse button btn on this
44 // part of the control
45 wxScrollThumbCaptureData(wxScrollThumb::Shaft part,
46 int btn,
47 wxControlWithThumb *control)
48 {
49 m_shaftPart = part;
50 m_btnCapture = btn;
51 m_timerScroll = NULL;
52
53 m_window = control->GetWindow();
54 m_window->CaptureMouse();
55 }
56
57 // release mouse
58 ~wxScrollThumbCaptureData()
59 {
60 if ( m_window )
61 {
62 m_window->ReleaseMouse();
63 }
64
65 delete m_timerScroll;
66 }
67
68 // the thumb part being held pressed
69 wxScrollThumb::Shaft m_shaftPart;
70
71 // the mouse button which started the capture (-1 if none)
72 int m_btnCapture;
73
74 // the window which has captured the mouse
75 wxWindow *m_window;
76
77 // the offset between the mouse position and the start of the thumb which
78 // is kept constant while dragging the thumb
79 wxCoord m_ofsMouse;
80
81 // the timer for generating the scroll events when scrolling by page
82 wxScrollTimer *m_timerScroll;
83 };
84
85 // ----------------------------------------------------------------------------
86 // wxScrollTimer: the timer used when the arrow is kept pressed
87 // ----------------------------------------------------------------------------
88
89 class wxScrollThumbTimer : public wxScrollTimer
90 {
91 public:
92 wxScrollThumbTimer(wxControlWithThumb *control,
93 wxScrollThumb::Shaft shaftPart)
94 {
95 m_control = control;
96 switch ( shaftPart )
97 {
98 case wxScrollThumb::Shaft_Above:
99 m_inc = -1;
100 break;
101
102 default:
103 wxFAIL_MSG(_T("unexpected shaft part in wxScrollThumbTimer"));
104 // fall through
105
106 case wxScrollThumb::Shaft_Below:
107 m_inc = 1;
108 break;
109 }
110
111 m_control->OnPageScrollStart();
112
113 StartAutoScroll();
114 }
115
116 protected:
117 virtual bool DoNotify()
118 {
119 return m_control->OnPageScroll(m_inc);
120 }
121
122 wxControlWithThumb *m_control;
123 int m_inc;
124 };
125
126 // ============================================================================
127 // implementation
128 // ============================================================================
129
130 // ----------------------------------------------------------------------------
131 // wxScrollThumb constructor and dtor
132 // ----------------------------------------------------------------------------
133
134 wxScrollThumb::wxScrollThumb(wxControlWithThumb *control)
135 {
136 m_shaftPart = Shaft_None;
137 m_control = control;
138 m_captureData = NULL;
139 }
140
141 wxScrollThumb::~wxScrollThumb()
142 {
143 // it should have been destroyed
144 wxASSERT_MSG( !m_captureData, _T("memory leak in wxScrollThumb") );
145 }
146
147 // ----------------------------------------------------------------------------
148 // wxScrollThumb mouse handling
149 // ----------------------------------------------------------------------------
150
151 bool wxScrollThumb::HandleMouse(const wxMouseEvent& event) const
152 {
153 // is this a click event?
154 int btn = event.GetButton();
155 if ( btn == -1 )
156 {
157 // no...
158 return FALSE;
159 }
160
161 // when the mouse is pressed on any scrollbar element, we capture it
162 // and hold capture until the same mouse button is released
163 if ( event.ButtonDown() || event.ButtonDClick() )
164 {
165 if ( HasCapture() )
166 {
167 // mouse already captured, nothing to do
168 return FALSE;
169 }
170
171 // determine which part of the window the user clicked in
172 Shaft shaftPart = m_control->HitTest(event.GetPosition());
173
174 if ( shaftPart == Shaft_None )
175 {
176 // mouse pressed over something else
177 return FALSE;
178 }
179
180 // capture the mouse
181 wxConstCast(this, wxScrollThumb)->m_captureData =
182 new wxScrollThumbCaptureData(shaftPart, btn, m_control);
183
184 // modify the visual appearance before sending the event which will
185 // cause a redraw
186 m_control->SetShaftPartState(shaftPart, wxCONTROL_PRESSED);
187
188 if ( shaftPart == Shaft_Thumb )
189 {
190 // save the mouse offset from the thumb position - we will keep it
191 // constant while dragging the thumb
192 m_captureData->m_ofsMouse =
193 GetMouseCoord(event) - m_control->ThumbPosToPixel();
194
195 // generate an additional event if we start dragging the thumb
196 m_control->OnThumbDragStart(GetThumbPos(event));
197 }
198 else // not the thumb
199 {
200 // start timer for auto scrolling when the user presses the mouse
201 // in the shaft above or below the thumb
202 m_captureData->m_timerScroll =
203 new wxScrollThumbTimer(m_control, shaftPart);
204 }
205 }
206 // release mouse if the *same* button went up
207 else if ( HasCapture() && (btn == m_captureData->m_btnCapture) )
208 {
209 Shaft shaftPart = m_captureData->m_shaftPart;
210
211 // if we were dragging the thumb, send the one last event
212 if ( shaftPart == Shaft_Thumb )
213 {
214 m_control->OnThumbDragEnd(GetThumbPos(event));
215 }
216
217 // release the mouse and free capture data
218 delete m_captureData;
219 wxConstCast(this, wxScrollThumb)->m_captureData = NULL;
220
221 m_control->SetShaftPartState(shaftPart, wxCONTROL_PRESSED, FALSE);
222 }
223 else // another mouse button released
224 {
225 // we don't process this
226 return FALSE;
227 }
228
229 return TRUE;
230 }
231
232 bool wxScrollThumb::HandleMouseMove(const wxMouseEvent& event) const
233 {
234 if ( HasCapture() )
235 {
236 if ( (m_captureData->m_shaftPart == Shaft_Thumb) && event.Moving() )
237 {
238 // make the thumb follow the mouse by keeping the same offset
239 // between the mouse position and the top/left of the thumb
240 m_control->OnThumbDrag(GetThumbPos(event));
241 }
242
243 // we process all mouse events while the mouse is captured by us
244 return TRUE;
245 }
246 else // no capture
247 {
248 Shaft shaftPart;
249 if ( event.Leaving() )
250 {
251 // no part of the shaft has mouse if it left the window completely
252 shaftPart = Shaft_None;
253 }
254 else // Moving() or Entering(), treat them the same here
255 {
256 shaftPart = m_control->HitTest(event.GetPosition());
257 }
258
259 if ( shaftPart != m_shaftPart )
260 {
261 // update the highlighted state
262 m_control->SetShaftPartState(m_shaftPart, wxCONTROL_CURRENT, FALSE);
263 wxConstCast(this, wxScrollThumb)->m_shaftPart = shaftPart;
264 m_control->SetShaftPartState(m_shaftPart, wxCONTROL_CURRENT, TRUE);
265 }
266
267 // if the event happened on the shaft, it was for us and we processed
268 // it
269 return shaftPart != Shaft_None;
270 }
271 }
272
273 wxCoord wxScrollThumb::GetMouseCoord(const wxMouseEvent& event) const
274 {
275 wxPoint pt = event.GetPosition();
276 return m_control->IsVertical() ? pt.y : pt.x;
277 }
278
279 int wxScrollThumb::GetThumbPos(const wxMouseEvent& event) const
280 {
281 wxCHECK_MSG( m_captureData && m_captureData->m_shaftPart == Shaft_Thumb, 0,
282 _T("can't be called when thumb is not dragged") );
283
284 int x = GetMouseCoord(event) - m_captureData->m_ofsMouse;
285 return m_control->PixelToThumbPos(x);
286 }