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