1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: univ/spinbutt.cpp
3 // Purpose: implementation of the universal version of wxSpinButton
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
29 #include "wx/spinbutt.h"
33 #include "wx/univ/renderer.h"
34 #include "wx/univ/inphand.h"
35 #include "wx/univ/theme.h"
37 // ============================================================================
38 // implementation of wxSpinButton
39 // ============================================================================
41 IMPLEMENT_DYNAMIC_CLASS(wxSpinEvent
, wxNotifyEvent
)
42 IMPLEMENT_DYNAMIC_CLASS(wxSpinButton
, wxControl
)
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
49 // warning C4355: 'this' : used in base member initializer list
50 #pragma warning(disable:4355) // so what? disable it...
53 wxSpinButton::wxSpinButton()
59 wxSpinButton::wxSpinButton(wxWindow
*parent
,
69 (void)Create(parent
, id
, pos
, size
, style
, name
);
73 // warning C4355: 'this' : used in base member initializer list
74 #pragma warning(default:4355)
77 void wxSpinButton::Init()
79 for ( size_t n
= 0; n
< WXSIZEOF(m_arrowsState
); n
++ )
87 bool wxSpinButton::Create(wxWindow
*parent
,
94 // the spin buttons never have the border
95 style
&= ~wxBORDER_MASK
;
97 if ( !wxSpinButtonBase::Create(parent
, id
, pos
, size
, style
,
98 wxDefaultValidator
, name
) )
103 CreateInputHandler(wxINP_HANDLER_SPINBTN
);
108 // ----------------------------------------------------------------------------
110 // ----------------------------------------------------------------------------
112 void wxSpinButton::SetRange(int minVal
, int maxVal
)
114 wxSpinButtonBase::SetRange(minVal
, maxVal
);
116 // because the arrows disabled state might have changed - we don't check if
117 // it really changed or not because SetRange() is called rarely enough and
118 // son an extre refresh here doesn't really hurt
122 int wxSpinButton::GetValue() const
127 void wxSpinButton::SetValue(int val
)
129 if ( val
!= m_value
)
137 int wxSpinButton::NormalizeValue(int value
) const
141 if ( GetWindowStyleFlag() & wxSP_WRAP
)
142 value
= m_min
+ (value
- m_max
- 1) % (m_max
- m_min
+ 1);
146 else if ( value
< m_min
)
148 if ( GetWindowStyleFlag() & wxSP_WRAP
)
149 value
= m_max
- (m_min
- value
- 1) % (m_max
- m_min
+ 1);
157 bool wxSpinButton::ChangeValue(int inc
)
159 int valueNew
= NormalizeValue(m_value
+ inc
);
161 if ( valueNew
== m_value
)
163 // nothing changed - most likely because we are already at min/max
168 wxSpinEvent
event(inc
> 0 ? wxEVT_SCROLL_LINEUP
: wxEVT_SCROLL_LINEDOWN
,
170 event
.SetPosition(valueNew
);
171 event
.SetEventObject(this);
173 if ( GetEventHandler()->ProcessEvent(event
) && !event
.IsAllowed() )
175 // programm has vetoed the event
181 // send wxEVT_SCROLL_THUMBTRACK as well
182 event
.SetEventType(wxEVT_SCROLL_THUMBTRACK
);
183 (void)GetEventHandler()->ProcessEvent(event
);
188 // ----------------------------------------------------------------------------
190 // ----------------------------------------------------------------------------
192 wxSize
wxSpinButton::DoGetBestClientSize() const
194 // a spin button has by default the same size as two scrollbar arrows put
196 wxSize size
= m_renderer
->GetScrollbarArrowSize();
209 // ----------------------------------------------------------------------------
210 // wxControlWithArrows methods
211 // ----------------------------------------------------------------------------
213 int wxSpinButton::GetArrowState(wxScrollArrows::Arrow arrow
) const
215 int state
= m_arrowsState
[arrow
];
217 // the arrow may also be disabled: either because the control is completely
219 bool disabled
= !IsEnabled();
221 if ( !disabled
&& !(GetWindowStyleFlag() & wxSP_WRAP
) )
223 // ... or because we can't go any further - note that this never
224 // happens if we just wrap
227 if ( arrow
== wxScrollArrows::Arrow_First
)
228 disabled
= m_value
== m_max
;
230 disabled
= m_value
== m_min
;
234 if ( arrow
== wxScrollArrows::Arrow_First
)
235 disabled
= m_value
== m_min
;
237 disabled
= m_value
== m_max
;
243 state
|= wxCONTROL_DISABLED
;
249 void wxSpinButton::SetArrowFlag(wxScrollArrows::Arrow arrow
, int flag
, bool set
)
251 int state
= m_arrowsState
[arrow
];
257 if ( state
!= m_arrowsState
[arrow
] )
259 m_arrowsState
[arrow
] = state
;
264 bool wxSpinButton::OnArrow(wxScrollArrows::Arrow arrow
)
266 int valueOld
= GetValue();
268 wxControlAction action
;
269 if ( arrow
== wxScrollArrows::Arrow_First
)
270 action
= IsVertical() ? wxACTION_SPIN_INC
: wxACTION_SPIN_DEC
;
272 action
= IsVertical() ? wxACTION_SPIN_DEC
: wxACTION_SPIN_INC
;
274 PerformAction(action
);
276 // did we scroll to the end?
277 return GetValue() != valueOld
;
280 // ----------------------------------------------------------------------------
282 // ----------------------------------------------------------------------------
284 void wxSpinButton::DoDraw(wxControlRenderer
*renderer
)
286 wxRect rectArrow1
, rectArrow2
;
287 CalcArrowRects(&rectArrow1
, &rectArrow2
);
289 wxDC
& dc
= renderer
->GetDC();
290 m_arrows
.DrawArrow(wxScrollArrows::Arrow_First
, dc
, rectArrow1
);
291 m_arrows
.DrawArrow(wxScrollArrows::Arrow_Second
, dc
, rectArrow2
);
294 // ----------------------------------------------------------------------------
296 // ----------------------------------------------------------------------------
298 void wxSpinButton::CalcArrowRects(wxRect
*rect1
, wxRect
*rect2
) const
300 // calculate the rectangles for both arrows: note that normally the 2
301 // arrows are adjacent to each other but if the total control width/height
302 // is odd, we can have 1 pixel between them
303 wxRect rectTotal
= GetClientRect();
312 rect2
->y
+= rect1
->height
;
313 if ( rectTotal
.height
% 2 )
321 rect2
->x
+= rect1
->width
;
322 if ( rectTotal
.width
% 2 )
327 wxScrollArrows::Arrow
wxSpinButton::HitTestArrow(const wxPoint
& pt
) const
329 wxRect rectArrow1
, rectArrow2
;
330 CalcArrowRects(&rectArrow1
, &rectArrow2
);
332 if ( rectArrow1
.Contains(pt
) )
333 return wxScrollArrows::Arrow_First
;
334 else if ( rectArrow2
.Contains(pt
) )
335 return wxScrollArrows::Arrow_Second
;
337 return wxScrollArrows::Arrow_None
;
340 // ----------------------------------------------------------------------------
342 // ----------------------------------------------------------------------------
344 bool wxSpinButton::PerformAction(const wxControlAction
& action
,
346 const wxString
& strArg
)
348 if ( action
== wxACTION_SPIN_INC
)
350 else if ( action
== wxACTION_SPIN_DEC
)
353 return wxControl::PerformAction(action
, numArg
, strArg
);
359 wxInputHandler
*wxSpinButton::GetStdInputHandler(wxInputHandler
*handlerDef
)
361 static wxStdSpinButtonInputHandler
s_handler(handlerDef
);
366 // ----------------------------------------------------------------------------
367 // wxStdSpinButtonInputHandler
368 // ----------------------------------------------------------------------------
370 wxStdSpinButtonInputHandler::
371 wxStdSpinButtonInputHandler(wxInputHandler
*inphand
)
372 : wxStdInputHandler(inphand
)
376 bool wxStdSpinButtonInputHandler::HandleKey(wxInputConsumer
*consumer
,
377 const wxKeyEvent
& event
,
382 wxControlAction action
;
383 switch ( event
.GetKeyCode() )
387 action
= wxACTION_SPIN_DEC
;
392 action
= wxACTION_SPIN_INC
;
396 if ( !action
.IsEmpty() )
398 consumer
->PerformAction(action
);
404 return wxStdInputHandler::HandleKey(consumer
, event
, pressed
);
407 bool wxStdSpinButtonInputHandler::HandleMouse(wxInputConsumer
*consumer
,
408 const wxMouseEvent
& event
)
410 wxSpinButton
*spinbtn
= wxStaticCast(consumer
->GetInputWindow(), wxSpinButton
);
412 if ( spinbtn
->GetArrows().HandleMouse(event
) )
414 // don't refresh, everything is already done
418 return wxStdInputHandler::HandleMouse(consumer
, event
);
421 bool wxStdSpinButtonInputHandler::HandleMouseMove(wxInputConsumer
*consumer
,
422 const wxMouseEvent
& event
)
424 wxSpinButton
*spinbtn
= wxStaticCast(consumer
->GetInputWindow(), wxSpinButton
);
426 if ( spinbtn
->GetArrows().HandleMouseMove(event
) )
428 // processed by the arrows
432 return wxStdInputHandler::HandleMouseMove(consumer
, event
);
436 #endif // wxUSE_SPINBTN