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