]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/univ/spinbutt.cpp
Fix horizontal mouse wheel scrolling in wxGTK.
[wxWidgets.git] / src / univ / spinbutt.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/univ/spinbutt.cpp
3// Purpose: implementation of the universal version of wxSpinButton
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 21.01.01
7// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
25#ifndef WX_PRECOMP
26#endif
27
28#include "wx/spinbutt.h"
29
30#if wxUSE_SPINBTN
31
32#include "wx/univ/renderer.h"
33#include "wx/univ/inphand.h"
34#include "wx/univ/theme.h"
35
36// ============================================================================
37// implementation of wxSpinButton
38// ============================================================================
39
40// ----------------------------------------------------------------------------
41// creation
42// ----------------------------------------------------------------------------
43
44#ifdef __VISUALC__
45 // warning C4355: 'this' : used in base member initializer list
46 #pragma warning(disable:4355) // so what? disable it...
47#endif
48
49wxSpinButton::wxSpinButton()
50 : m_arrows(this)
51{
52 Init();
53}
54
55wxSpinButton::wxSpinButton(wxWindow *parent,
56 wxWindowID id,
57 const wxPoint& pos,
58 const wxSize& size,
59 long style,
60 const wxString& name)
61 : m_arrows(this)
62{
63 Init();
64
65 (void)Create(parent, id, pos, size, style, name);
66}
67
68#ifdef __VISUALC__
69 // warning C4355: 'this' : used in base member initializer list
70 #pragma warning(default:4355)
71#endif
72
73void wxSpinButton::Init()
74{
75 for ( size_t n = 0; n < WXSIZEOF(m_arrowsState); n++ )
76 {
77 m_arrowsState[n] = 0;
78 }
79
80 m_value = 0;
81}
82
83bool wxSpinButton::Create(wxWindow *parent,
84 wxWindowID id,
85 const wxPoint& pos,
86 const wxSize& size,
87 long style,
88 const wxString& name)
89{
90 // the spin buttons never have the border
91 style &= ~wxBORDER_MASK;
92
93 if ( !wxSpinButtonBase::Create(parent, id, pos, size, style,
94 wxDefaultValidator, name) )
95 return false;
96
97 SetInitialSize(size);
98
99 CreateInputHandler(wxINP_HANDLER_SPINBTN);
100
101 return true;
102}
103
104// ----------------------------------------------------------------------------
105// value access
106// ----------------------------------------------------------------------------
107
108void wxSpinButton::SetRange(int minVal, int maxVal)
109{
110 wxSpinButtonBase::SetRange(minVal, maxVal);
111
112 // because the arrows disabled state might have changed - we don't check if
113 // it really changed or not because SetRange() is called rarely enough and
114 // son an extre refresh here doesn't really hurt
115 Refresh();
116}
117
118int wxSpinButton::GetValue() const
119{
120 return m_value;
121}
122
123void wxSpinButton::SetValue(int val)
124{
125 if ( val != m_value )
126 {
127 m_value = val;
128
129 Refresh();
130 }
131}
132
133int wxSpinButton::NormalizeValue(int value) const
134{
135 if ( value > m_max )
136 {
137 if ( GetWindowStyleFlag() & wxSP_WRAP )
138 value = m_min + (value - m_max - 1) % (m_max - m_min + 1);
139 else
140 value = m_max;
141 }
142 else if ( value < m_min )
143 {
144 if ( GetWindowStyleFlag() & wxSP_WRAP )
145 value = m_max - (m_min - value - 1) % (m_max - m_min + 1);
146 else
147 value = m_min;
148 }
149
150 return value;
151}
152
153bool wxSpinButton::ChangeValue(int inc)
154{
155 int valueNew = NormalizeValue(m_value + inc);
156
157 if ( valueNew == m_value )
158 {
159 // nothing changed - most likely because we are already at min/max
160 // value
161 return false;
162 }
163
164 wxSpinEvent event(inc > 0 ? wxEVT_SCROLL_LINEUP : wxEVT_SCROLL_LINEDOWN,
165 GetId());
166 event.SetPosition(valueNew);
167 event.SetEventObject(this);
168
169 if ( GetEventHandler()->ProcessEvent(event) && !event.IsAllowed() )
170 {
171 // programm has vetoed the event
172 return false;
173 }
174
175 m_value = valueNew;
176
177 // send wxEVT_SCROLL_THUMBTRACK as well
178 event.SetEventType(wxEVT_SCROLL_THUMBTRACK);
179 (void)GetEventHandler()->ProcessEvent(event);
180
181 return true;
182}
183
184// ----------------------------------------------------------------------------
185// size calculations
186// ----------------------------------------------------------------------------
187
188wxSize wxSpinButton::DoGetBestClientSize() const
189{
190 // a spin button has by default the same size as two scrollbar arrows put
191 // together
192 wxSize size = m_renderer->GetScrollbarArrowSize();
193 if ( IsVertical() )
194 {
195 size.y *= 2;
196 }
197 else
198 {
199 size.x *= 2;
200 }
201
202 return size;
203}
204
205// ----------------------------------------------------------------------------
206// wxControlWithArrows methods
207// ----------------------------------------------------------------------------
208
209int wxSpinButton::GetArrowState(wxScrollArrows::Arrow arrow) const
210{
211 int state = m_arrowsState[arrow];
212
213 // the arrow may also be disabled: either because the control is completely
214 // disabled
215 bool disabled = !IsEnabled();
216
217 if ( !disabled && !(GetWindowStyleFlag() & wxSP_WRAP) )
218 {
219 // ... or because we can't go any further - note that this never
220 // happens if we just wrap
221 if ( IsVertical() )
222 {
223 if ( arrow == wxScrollArrows::Arrow_First )
224 disabled = m_value == m_max;
225 else
226 disabled = m_value == m_min;
227 }
228 else // horizontal
229 {
230 if ( arrow == wxScrollArrows::Arrow_First )
231 disabled = m_value == m_min;
232 else
233 disabled = m_value == m_max;
234 }
235 }
236
237 if ( disabled )
238 {
239 state |= wxCONTROL_DISABLED;
240 }
241
242 return state;
243}
244
245void wxSpinButton::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
246{
247 int state = m_arrowsState[arrow];
248 if ( set )
249 state |= flag;
250 else
251 state &= ~flag;
252
253 if ( state != m_arrowsState[arrow] )
254 {
255 m_arrowsState[arrow] = state;
256 Refresh();
257 }
258}
259
260bool wxSpinButton::OnArrow(wxScrollArrows::Arrow arrow)
261{
262 int valueOld = GetValue();
263
264 wxControlAction action;
265 if ( arrow == wxScrollArrows::Arrow_First )
266 action = IsVertical() ? wxACTION_SPIN_INC : wxACTION_SPIN_DEC;
267 else
268 action = IsVertical() ? wxACTION_SPIN_DEC : wxACTION_SPIN_INC;
269
270 PerformAction(action);
271
272 // did we scroll to the end?
273 return GetValue() != valueOld;
274}
275
276// ----------------------------------------------------------------------------
277// drawing
278// ----------------------------------------------------------------------------
279
280void wxSpinButton::DoDraw(wxControlRenderer *renderer)
281{
282 wxRect rectArrow1, rectArrow2;
283 CalcArrowRects(&rectArrow1, &rectArrow2);
284
285 wxDC& dc = renderer->GetDC();
286 m_arrows.DrawArrow(wxScrollArrows::Arrow_First, dc, rectArrow1);
287 m_arrows.DrawArrow(wxScrollArrows::Arrow_Second, dc, rectArrow2);
288}
289
290// ----------------------------------------------------------------------------
291// geometry
292// ----------------------------------------------------------------------------
293
294void wxSpinButton::CalcArrowRects(wxRect *rect1, wxRect *rect2) const
295{
296 // calculate the rectangles for both arrows: note that normally the 2
297 // arrows are adjacent to each other but if the total control width/height
298 // is odd, we can have 1 pixel between them
299 wxRect rectTotal = GetClientRect();
300
301 *rect1 =
302 *rect2 = rectTotal;
303 if ( IsVertical() )
304 {
305 rect1->height /= 2;
306 rect2->height /= 2;
307
308 rect2->y += rect1->height;
309 if ( rectTotal.height % 2 )
310 rect2->y++;
311 }
312 else // horizontal
313 {
314 rect1->width /= 2;
315 rect2->width /= 2;
316
317 rect2->x += rect1->width;
318 if ( rectTotal.width % 2 )
319 rect2->x++;
320 }
321}
322
323wxScrollArrows::Arrow wxSpinButton::HitTestArrow(const wxPoint& pt) const
324{
325 wxRect rectArrow1, rectArrow2;
326 CalcArrowRects(&rectArrow1, &rectArrow2);
327
328 if ( rectArrow1.Contains(pt) )
329 return wxScrollArrows::Arrow_First;
330 else if ( rectArrow2.Contains(pt) )
331 return wxScrollArrows::Arrow_Second;
332 else
333 return wxScrollArrows::Arrow_None;
334}
335
336// ----------------------------------------------------------------------------
337// input processing
338// ----------------------------------------------------------------------------
339
340bool wxSpinButton::PerformAction(const wxControlAction& action,
341 long numArg,
342 const wxString& strArg)
343{
344 if ( action == wxACTION_SPIN_INC )
345 ChangeValue(+1);
346 else if ( action == wxACTION_SPIN_DEC )
347 ChangeValue(-1);
348 else
349 return wxControl::PerformAction(action, numArg, strArg);
350
351 return true;
352}
353
354/* static */
355wxInputHandler *wxSpinButton::GetStdInputHandler(wxInputHandler *handlerDef)
356{
357 static wxStdSpinButtonInputHandler s_handler(handlerDef);
358
359 return &s_handler;
360}
361
362// ----------------------------------------------------------------------------
363// wxStdSpinButtonInputHandler
364// ----------------------------------------------------------------------------
365
366wxStdSpinButtonInputHandler::
367wxStdSpinButtonInputHandler(wxInputHandler *inphand)
368 : wxStdInputHandler(inphand)
369{
370}
371
372bool wxStdSpinButtonInputHandler::HandleKey(wxInputConsumer *consumer,
373 const wxKeyEvent& event,
374 bool pressed)
375{
376 if ( pressed )
377 {
378 wxControlAction action;
379 switch ( event.GetKeyCode() )
380 {
381 case WXK_DOWN:
382 case WXK_RIGHT:
383 action = wxACTION_SPIN_DEC;
384 break;
385
386 case WXK_UP:
387 case WXK_LEFT:
388 action = wxACTION_SPIN_INC;
389 break;
390 }
391
392 if ( !action.IsEmpty() )
393 {
394 consumer->PerformAction(action);
395
396 return true;
397 }
398 }
399
400 return wxStdInputHandler::HandleKey(consumer, event, pressed);
401}
402
403bool wxStdSpinButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
404 const wxMouseEvent& event)
405{
406 wxSpinButton *spinbtn = wxStaticCast(consumer->GetInputWindow(), wxSpinButton);
407
408 if ( spinbtn->GetArrows().HandleMouse(event) )
409 {
410 // don't refresh, everything is already done
411 return false;
412 }
413
414 return wxStdInputHandler::HandleMouse(consumer, event);
415}
416
417bool wxStdSpinButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
418 const wxMouseEvent& event)
419{
420 wxSpinButton *spinbtn = wxStaticCast(consumer->GetInputWindow(), wxSpinButton);
421
422 if ( spinbtn->GetArrows().HandleMouseMove(event) )
423 {
424 // processed by the arrows
425 return false;
426 }
427
428 return wxStdInputHandler::HandleMouseMove(consumer, event);
429}
430
431
432#endif // wxUSE_SPINBTN