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 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
46 // warning C4355: 'this' : used in base member initializer list
47 #pragma warning(disable:4355) // so what? disable it...
50 wxSpinButton::wxSpinButton()
56 wxSpinButton::wxSpinButton(wxWindow
*parent
,
66 (void)Create(parent
, id
, pos
, size
, style
, name
);
70 // warning C4355: 'this' : used in base member initializer list
71 #pragma warning(default:4355)
74 void wxSpinButton::Init()
76 for ( size_t n
= 0; n
< WXSIZEOF(m_arrowsState
); n
++ )
84 bool wxSpinButton::Create(wxWindow
*parent
,
91 // the spin buttons never have the border
92 style
&= ~wxBORDER_MASK
;
94 if ( !wxSpinButtonBase::Create(parent
, id
, pos
, size
, style
,
95 wxDefaultValidator
, name
) )
100 CreateInputHandler(wxINP_HANDLER_SPINBTN
);
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 void wxSpinButton::SetRange(int minVal
, int maxVal
)
111 wxSpinButtonBase::SetRange(minVal
, maxVal
);
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
119 int wxSpinButton::GetValue() const
124 void wxSpinButton::SetValue(int val
)
126 if ( val
!= m_value
)
134 int wxSpinButton::NormalizeValue(int value
) const
138 if ( GetWindowStyleFlag() & wxSP_WRAP
)
139 value
= m_min
+ (value
- m_max
- 1) % (m_max
- m_min
+ 1);
143 else if ( value
< m_min
)
145 if ( GetWindowStyleFlag() & wxSP_WRAP
)
146 value
= m_max
- (m_min
- value
- 1) % (m_max
- m_min
+ 1);
154 bool wxSpinButton::ChangeValue(int inc
)
156 int valueNew
= NormalizeValue(m_value
+ inc
);
158 if ( valueNew
== m_value
)
160 // nothing changed - most likely because we are already at min/max
165 wxSpinEvent
event(inc
> 0 ? wxEVT_SCROLL_LINEUP
: wxEVT_SCROLL_LINEDOWN
,
167 event
.SetPosition(valueNew
);
168 event
.SetEventObject(this);
170 if ( GetEventHandler()->ProcessEvent(event
) && !event
.IsAllowed() )
172 // programm has vetoed the event
178 // send wxEVT_SCROLL_THUMBTRACK as well
179 event
.SetEventType(wxEVT_SCROLL_THUMBTRACK
);
180 (void)GetEventHandler()->ProcessEvent(event
);
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 wxSize
wxSpinButton::DoGetBestClientSize() const
191 // a spin button has by default the same size as two scrollbar arrows put
193 wxSize size
= m_renderer
->GetScrollbarArrowSize();
206 // ----------------------------------------------------------------------------
207 // wxControlWithArrows methods
208 // ----------------------------------------------------------------------------
210 int wxSpinButton::GetArrowState(wxScrollArrows::Arrow arrow
) const
212 int state
= m_arrowsState
[arrow
];
214 // the arrow may also be disabled: either because the control is completely
216 bool disabled
= !IsEnabled();
218 if ( !disabled
&& !(GetWindowStyleFlag() & wxSP_WRAP
) )
220 // ... or because we can't go any further - note that this never
221 // happens if we just wrap
224 if ( arrow
== wxScrollArrows::Arrow_First
)
225 disabled
= m_value
== m_max
;
227 disabled
= m_value
== m_min
;
231 if ( arrow
== wxScrollArrows::Arrow_First
)
232 disabled
= m_value
== m_min
;
234 disabled
= m_value
== m_max
;
240 state
|= wxCONTROL_DISABLED
;
246 void wxSpinButton::SetArrowFlag(wxScrollArrows::Arrow arrow
, int flag
, bool set
)
248 int state
= m_arrowsState
[arrow
];
254 if ( state
!= m_arrowsState
[arrow
] )
256 m_arrowsState
[arrow
] = state
;
261 bool wxSpinButton::OnArrow(wxScrollArrows::Arrow arrow
)
263 int valueOld
= GetValue();
265 wxControlAction action
;
266 if ( arrow
== wxScrollArrows::Arrow_First
)
267 action
= IsVertical() ? wxACTION_SPIN_INC
: wxACTION_SPIN_DEC
;
269 action
= IsVertical() ? wxACTION_SPIN_DEC
: wxACTION_SPIN_INC
;
271 PerformAction(action
);
273 // did we scroll to the end?
274 return GetValue() != valueOld
;
277 // ----------------------------------------------------------------------------
279 // ----------------------------------------------------------------------------
281 void wxSpinButton::DoDraw(wxControlRenderer
*renderer
)
283 wxRect rectArrow1
, rectArrow2
;
284 CalcArrowRects(&rectArrow1
, &rectArrow2
);
286 wxDC
& dc
= renderer
->GetDC();
287 m_arrows
.DrawArrow(wxScrollArrows::Arrow_First
, dc
, rectArrow1
);
288 m_arrows
.DrawArrow(wxScrollArrows::Arrow_Second
, dc
, rectArrow2
);
291 // ----------------------------------------------------------------------------
293 // ----------------------------------------------------------------------------
295 void wxSpinButton::CalcArrowRects(wxRect
*rect1
, wxRect
*rect2
) const
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();
309 rect2
->y
+= rect1
->height
;
310 if ( rectTotal
.height
% 2 )
318 rect2
->x
+= rect1
->width
;
319 if ( rectTotal
.width
% 2 )
324 wxScrollArrows::Arrow
wxSpinButton::HitTestArrow(const wxPoint
& pt
) const
326 wxRect rectArrow1
, rectArrow2
;
327 CalcArrowRects(&rectArrow1
, &rectArrow2
);
329 if ( rectArrow1
.Contains(pt
) )
330 return wxScrollArrows::Arrow_First
;
331 else if ( rectArrow2
.Contains(pt
) )
332 return wxScrollArrows::Arrow_Second
;
334 return wxScrollArrows::Arrow_None
;
337 // ----------------------------------------------------------------------------
339 // ----------------------------------------------------------------------------
341 bool wxSpinButton::PerformAction(const wxControlAction
& action
,
343 const wxString
& strArg
)
345 if ( action
== wxACTION_SPIN_INC
)
347 else if ( action
== wxACTION_SPIN_DEC
)
350 return wxControl::PerformAction(action
, numArg
, strArg
);
356 wxInputHandler
*wxSpinButton::GetStdInputHandler(wxInputHandler
*handlerDef
)
358 static wxStdSpinButtonInputHandler
s_handler(handlerDef
);
363 // ----------------------------------------------------------------------------
364 // wxStdSpinButtonInputHandler
365 // ----------------------------------------------------------------------------
367 wxStdSpinButtonInputHandler::
368 wxStdSpinButtonInputHandler(wxInputHandler
*inphand
)
369 : wxStdInputHandler(inphand
)
373 bool wxStdSpinButtonInputHandler::HandleKey(wxInputConsumer
*consumer
,
374 const wxKeyEvent
& event
,
379 wxControlAction action
;
380 switch ( event
.GetKeyCode() )
384 action
= wxACTION_SPIN_DEC
;
389 action
= wxACTION_SPIN_INC
;
393 if ( !action
.IsEmpty() )
395 consumer
->PerformAction(action
);
401 return wxStdInputHandler::HandleKey(consumer
, event
, pressed
);
404 bool wxStdSpinButtonInputHandler::HandleMouse(wxInputConsumer
*consumer
,
405 const wxMouseEvent
& event
)
407 wxSpinButton
*spinbtn
= wxStaticCast(consumer
->GetInputWindow(), wxSpinButton
);
409 if ( spinbtn
->GetArrows().HandleMouse(event
) )
411 // don't refresh, everything is already done
415 return wxStdInputHandler::HandleMouse(consumer
, event
);
418 bool wxStdSpinButtonInputHandler::HandleMouseMove(wxInputConsumer
*consumer
,
419 const wxMouseEvent
& event
)
421 wxSpinButton
*spinbtn
= wxStaticCast(consumer
->GetInputWindow(), wxSpinButton
);
423 if ( spinbtn
->GetArrows().HandleMouseMove(event
) )
425 // processed by the arrows
429 return wxStdInputHandler::HandleMouseMove(consumer
, event
);
433 #endif // wxUSE_SPINBTN