Improve validation of wxCheckBox styles.
[wxWidgets.git] / src / univ / checkbox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/checkbox.cpp
3 // Purpose: wxCheckBox implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 25.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_CHECKBOX
27
28 #include "wx/checkbox.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/dcclient.h"
32 #include "wx/validate.h"
33
34 #include "wx/button.h" // for wxACTION_BUTTON_XXX
35 #endif
36
37 #include "wx/univ/theme.h"
38 #include "wx/univ/renderer.h"
39 #include "wx/univ/inphand.h"
40 #include "wx/univ/colschem.h"
41
42 // ----------------------------------------------------------------------------
43 // wxStdCheckboxInputHandler: handles the mouse events for the check and radio
44 // boxes (handling the keyboard input is simple, but its handling differs a
45 // lot between GTK and MSW, so a new class should be derived for this)
46 // ----------------------------------------------------------------------------
47
48 class WXDLLEXPORT wxStdCheckboxInputHandler : public wxStdInputHandler
49 {
50 public:
51 wxStdCheckboxInputHandler(wxInputHandler *inphand);
52
53 // we have to override this one as wxStdButtonInputHandler version works
54 // only with the buttons
55 virtual bool HandleActivation(wxInputConsumer *consumer, bool activated);
56 };
57
58 // ============================================================================
59 // implementation
60 // ============================================================================
61
62 IMPLEMENT_DYNAMIC_CLASS(wxCheckBox, wxControl)
63
64 // ----------------------------------------------------------------------------
65 // wxCheckBox
66 // ----------------------------------------------------------------------------
67
68 void wxCheckBox::Init()
69 {
70 m_isPressed = false;
71 m_status = Status_Unchecked;
72 }
73
74 bool wxCheckBox::Create(wxWindow *parent,
75 wxWindowID id,
76 const wxString &label,
77 const wxPoint &pos,
78 const wxSize &size,
79 long style,
80 const wxValidator& validator,
81 const wxString &name)
82 {
83 WXValidateStyle( &style );
84 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
85 return false;
86
87 SetLabel(label);
88 SetInitialSize(size);
89
90 CreateInputHandler(wxINP_HANDLER_CHECKBOX);
91
92 return true;
93 }
94
95 // ----------------------------------------------------------------------------
96 // checkbox interface
97 // ----------------------------------------------------------------------------
98
99 bool wxCheckBox::GetValue() const
100 {
101 return (Get3StateValue() != wxCHK_UNCHECKED);
102 }
103
104 void wxCheckBox::SetValue(bool value)
105 {
106 Set3StateValue( value ? wxCHK_CHECKED : wxCHK_UNCHECKED );
107 }
108
109 void wxCheckBox::OnCheck()
110 {
111 // we do nothing here
112 }
113
114 // ----------------------------------------------------------------------------
115 // indicator bitmaps
116 // ----------------------------------------------------------------------------
117
118 wxBitmap wxCheckBox::GetBitmap(State state, Status status) const
119 {
120 wxBitmap bmp = m_bitmaps[state][status];
121 if ( !bmp.Ok() )
122 bmp = m_bitmaps[State_Normal][status];
123
124 return bmp;
125 }
126
127 void wxCheckBox::SetBitmap(const wxBitmap& bmp, State state, Status status)
128 {
129 m_bitmaps[state][status] = bmp;
130 }
131
132 // ----------------------------------------------------------------------------
133 // drawing
134 // ----------------------------------------------------------------------------
135
136 wxCheckBox::State wxCheckBox::GetState(int flags) const
137 {
138 if ( flags & wxCONTROL_DISABLED )
139 return State_Disabled;
140 else if ( flags & wxCONTROL_PRESSED )
141 return State_Pressed;
142 else if ( flags & wxCONTROL_CURRENT )
143 return State_Current;
144 else
145 return State_Normal;
146 }
147
148 void wxCheckBox::DoDraw(wxControlRenderer *renderer)
149 {
150 int flags = GetStateFlags();
151
152 wxDC& dc = renderer->GetDC();
153 dc.SetFont(GetFont());
154 dc.SetTextForeground(GetForegroundColour());
155
156 switch ( Get3StateValue() )
157 {
158 case wxCHK_CHECKED: flags |= wxCONTROL_CHECKED; break;
159 case wxCHK_UNDETERMINED: flags |= wxCONTROL_UNDETERMINED; break;
160 default: /* do nothing */ break;
161 }
162
163 wxBitmap bitmap(GetBitmap(GetState(flags), m_status));
164
165 renderer->GetRenderer()->
166 DrawCheckButton(dc,
167 GetLabel(),
168 bitmap,
169 renderer->GetRect(),
170 flags,
171 GetWindowStyle() & wxALIGN_RIGHT ? wxALIGN_RIGHT
172 : wxALIGN_LEFT,
173 GetAccelIndex());
174 }
175
176 // ----------------------------------------------------------------------------
177 // geometry calculations
178 // ----------------------------------------------------------------------------
179
180 wxSize wxCheckBox::GetBitmapSize() const
181 {
182 wxBitmap bmp = GetBitmap(State_Normal, Status_Checked);
183 return bmp.Ok() ? wxSize(bmp.GetWidth(), bmp.GetHeight())
184 : GetRenderer()->GetCheckBitmapSize();
185 }
186
187 wxSize wxCheckBox::DoGetBestClientSize() const
188 {
189 wxClientDC dc(wxConstCast(this, wxCheckBox));
190 dc.SetFont(GetFont());
191 wxCoord width, height;
192 dc.GetMultiLineTextExtent(GetLabel(), &width, &height);
193
194 wxSize sizeBmp = GetBitmapSize();
195 if ( height < sizeBmp.y )
196 height = sizeBmp.y;
197
198 #if defined(wxUNIV_COMPATIBLE_MSW) && wxUNIV_COMPATIBLE_MSW
199 // FIXME: flag nowhere defined so perhaps should be removed?
200
201 // this looks better but is different from what wxMSW does
202 height += GetCharHeight()/2;
203 #endif // wxUNIV_COMPATIBLE_MSW
204
205 width += sizeBmp.x + 2*GetCharWidth();
206
207 return wxSize(width, height);
208 }
209
210 // ----------------------------------------------------------------------------
211 // checkbox actions
212 // ----------------------------------------------------------------------------
213
214 void wxCheckBox::DoSet3StateValue(wxCheckBoxState state)
215 {
216 Status status;
217 switch ( state )
218 {
219 case wxCHK_UNCHECKED: status = Status_Unchecked; break;
220 case wxCHK_CHECKED: status = Status_Checked; break;
221 default: wxFAIL_MSG(wxT("Unknown checkbox state"));
222 case wxCHK_UNDETERMINED: status = Status_3rdState; break;
223 }
224 if ( status != m_status )
225 {
226 m_status = status;
227
228 if ( m_status == Status_Checked )
229 {
230 // invoke the hook
231 OnCheck();
232 }
233
234 Refresh();
235 }
236 }
237
238 wxCheckBoxState wxCheckBox::DoGet3StateValue() const
239 {
240 switch ( m_status )
241 {
242 case Status_Checked: return wxCHK_CHECKED;
243 case Status_Unchecked: return wxCHK_UNCHECKED;
244 default: /* go further */ break;
245 }
246 return wxCHK_UNDETERMINED;
247 }
248
249 void wxCheckBox::Press()
250 {
251 if ( !m_isPressed )
252 {
253 m_isPressed = true;
254
255 Refresh();
256 }
257 }
258
259 void wxCheckBox::Release()
260 {
261 if ( m_isPressed )
262 {
263 m_isPressed = false;
264
265 Refresh();
266 }
267 }
268
269 void wxCheckBox::Toggle()
270 {
271 m_isPressed = false;
272
273 Status status = m_status;
274
275 switch ( Get3StateValue() )
276 {
277 case wxCHK_CHECKED:
278 Set3StateValue(Is3rdStateAllowedForUser() ? wxCHK_UNDETERMINED : wxCHK_UNCHECKED);
279 break;
280
281 case wxCHK_UNCHECKED:
282 Set3StateValue(wxCHK_CHECKED);
283 break;
284
285 case wxCHK_UNDETERMINED:
286 Set3StateValue(wxCHK_UNCHECKED);
287 break;
288 }
289
290 if( status != m_status )
291 SendEvent();
292 }
293
294 void wxCheckBox::ChangeValue(bool value)
295 {
296 SetValue(value);
297
298 SendEvent();
299 }
300
301 void wxCheckBox::SendEvent()
302 {
303 wxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, GetId());
304 InitCommandEvent(event);
305 wxCheckBoxState state = Get3StateValue();
306
307 // If the style flag to allow the user setting the undetermined state
308 // is not set, then skip the undetermined state and set it to unchecked.
309 if ( state == wxCHK_UNDETERMINED && !Is3rdStateAllowedForUser() )
310 {
311 state = wxCHK_UNCHECKED;
312 Set3StateValue(state);
313 }
314
315 event.SetInt(state);
316 Command(event);
317 }
318
319 // ----------------------------------------------------------------------------
320 // input handling
321 // ----------------------------------------------------------------------------
322
323 bool wxCheckBox::PerformAction(const wxControlAction& action,
324 long numArg,
325 const wxString& strArg)
326 {
327 if ( action == wxACTION_BUTTON_PRESS )
328 Press();
329 else if ( action == wxACTION_BUTTON_RELEASE )
330 Release();
331 if ( action == wxACTION_CHECKBOX_CHECK )
332 ChangeValue(true);
333 else if ( action == wxACTION_CHECKBOX_CLEAR )
334 ChangeValue(false);
335 else if ( action == wxACTION_CHECKBOX_TOGGLE )
336 Toggle();
337 else
338 return wxControl::PerformAction(action, numArg, strArg);
339
340 return true;
341 }
342
343 /* static */
344 wxInputHandler *wxCheckBox::CreateStdInputHandler(wxInputHandler *handlerDef)
345 {
346 static wxStdCheckboxInputHandler s_handler(handlerDef);
347
348 return &s_handler;
349 }
350
351 // ----------------------------------------------------------------------------
352 // wxStdCheckboxInputHandler
353 // ----------------------------------------------------------------------------
354
355 wxStdCheckboxInputHandler::wxStdCheckboxInputHandler(wxInputHandler *def)
356 : wxStdInputHandler(wxButton::GetStdInputHandler(def))
357 {
358 }
359
360 bool wxStdCheckboxInputHandler::HandleActivation(wxInputConsumer *consumer,
361 bool WXUNUSED(activated))
362 {
363 // only the focused checkbox appearance changes when the app gains/loses
364 // activation
365 return consumer->GetInputWindow()->IsFocused();
366 }
367
368 #endif // wxUSE_CHECKBOX