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