Fix crash when getting or setting wxComboBox value in wxUniv.
[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 // ----------------------------------------------------------------------------
63 // wxCheckBox
64 // ----------------------------------------------------------------------------
65
66 void wxCheckBox::Init()
67 {
68 m_isPressed = false;
69 m_status = Status_Unchecked;
70 }
71
72 bool wxCheckBox::Create(wxWindow *parent,
73 wxWindowID id,
74 const wxString &label,
75 const wxPoint &pos,
76 const wxSize &size,
77 long style,
78 const wxValidator& validator,
79 const wxString &name)
80 {
81 WXValidateStyle( &style );
82 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
83 return false;
84
85 SetLabel(label);
86 SetInitialSize(size);
87
88 CreateInputHandler(wxINP_HANDLER_CHECKBOX);
89
90 return true;
91 }
92
93 // ----------------------------------------------------------------------------
94 // checkbox interface
95 // ----------------------------------------------------------------------------
96
97 bool wxCheckBox::GetValue() const
98 {
99 return (Get3StateValue() != wxCHK_UNCHECKED);
100 }
101
102 void wxCheckBox::SetValue(bool value)
103 {
104 Set3StateValue( value ? wxCHK_CHECKED : wxCHK_UNCHECKED );
105 }
106
107 void wxCheckBox::OnCheck()
108 {
109 // we do nothing here
110 }
111
112 // ----------------------------------------------------------------------------
113 // indicator bitmaps
114 // ----------------------------------------------------------------------------
115
116 wxBitmap wxCheckBox::GetBitmap(State state, Status status) const
117 {
118 wxBitmap bmp = m_bitmaps[state][status];
119 if ( !bmp.IsOk() )
120 bmp = m_bitmaps[State_Normal][status];
121
122 return bmp;
123 }
124
125 void wxCheckBox::SetBitmap(const wxBitmap& bmp, State state, Status status)
126 {
127 m_bitmaps[state][status] = bmp;
128 }
129
130 // ----------------------------------------------------------------------------
131 // drawing
132 // ----------------------------------------------------------------------------
133
134 wxCheckBox::State wxCheckBox::GetState(int flags) const
135 {
136 if ( flags & wxCONTROL_DISABLED )
137 return State_Disabled;
138 else if ( flags & wxCONTROL_PRESSED )
139 return State_Pressed;
140 else if ( flags & wxCONTROL_CURRENT )
141 return State_Current;
142 else
143 return State_Normal;
144 }
145
146 void wxCheckBox::DoDraw(wxControlRenderer *renderer)
147 {
148 int flags = GetStateFlags();
149
150 wxDC& dc = renderer->GetDC();
151 dc.SetFont(GetFont());
152 dc.SetTextForeground(GetForegroundColour());
153
154 switch ( Get3StateValue() )
155 {
156 case wxCHK_CHECKED: flags |= wxCONTROL_CHECKED; break;
157 case wxCHK_UNDETERMINED: flags |= wxCONTROL_UNDETERMINED; break;
158 default: /* do nothing */ break;
159 }
160
161 wxBitmap bitmap(GetBitmap(GetState(flags), m_status));
162
163 renderer->GetRenderer()->
164 DrawCheckButton(dc,
165 GetLabel(),
166 bitmap,
167 renderer->GetRect(),
168 flags,
169 GetWindowStyle() & wxALIGN_RIGHT ? wxALIGN_RIGHT
170 : wxALIGN_LEFT,
171 GetAccelIndex());
172 }
173
174 // ----------------------------------------------------------------------------
175 // geometry calculations
176 // ----------------------------------------------------------------------------
177
178 wxSize wxCheckBox::GetBitmapSize() const
179 {
180 wxBitmap bmp = GetBitmap(State_Normal, Status_Checked);
181 return bmp.IsOk() ? wxSize(bmp.GetWidth(), bmp.GetHeight())
182 : GetRenderer()->GetCheckBitmapSize();
183 }
184
185 wxSize wxCheckBox::DoGetBestClientSize() const
186 {
187 wxClientDC dc(wxConstCast(this, wxCheckBox));
188 dc.SetFont(GetFont());
189 wxCoord width, height;
190 dc.GetMultiLineTextExtent(GetLabel(), &width, &height);
191
192 wxSize sizeBmp = GetBitmapSize();
193 if ( height < sizeBmp.y )
194 height = sizeBmp.y;
195
196 #if defined(wxUNIV_COMPATIBLE_MSW) && wxUNIV_COMPATIBLE_MSW
197 // FIXME: flag nowhere defined so perhaps should be removed?
198
199 // this looks better but is different from what wxMSW does
200 height += GetCharHeight()/2;
201 #endif // wxUNIV_COMPATIBLE_MSW
202
203 width += sizeBmp.x + 2*GetCharWidth();
204
205 return wxSize(width, height);
206 }
207
208 // ----------------------------------------------------------------------------
209 // checkbox actions
210 // ----------------------------------------------------------------------------
211
212 void wxCheckBox::DoSet3StateValue(wxCheckBoxState state)
213 {
214 Status status;
215 switch ( state )
216 {
217 case wxCHK_UNCHECKED: status = Status_Unchecked; break;
218 case wxCHK_CHECKED: status = Status_Checked; break;
219 default: wxFAIL_MSG(wxT("Unknown checkbox state"));
220 case wxCHK_UNDETERMINED: status = Status_3rdState; break;
221 }
222 if ( status != m_status )
223 {
224 m_status = status;
225
226 if ( m_status == Status_Checked )
227 {
228 // invoke the hook
229 OnCheck();
230 }
231
232 Refresh();
233 }
234 }
235
236 wxCheckBoxState wxCheckBox::DoGet3StateValue() const
237 {
238 switch ( m_status )
239 {
240 case Status_Checked: return wxCHK_CHECKED;
241 case Status_Unchecked: return wxCHK_UNCHECKED;
242 default: /* go further */ break;
243 }
244 return wxCHK_UNDETERMINED;
245 }
246
247 void wxCheckBox::Press()
248 {
249 if ( !m_isPressed )
250 {
251 m_isPressed = true;
252
253 Refresh();
254 }
255 }
256
257 void wxCheckBox::Release()
258 {
259 if ( m_isPressed )
260 {
261 m_isPressed = false;
262
263 Refresh();
264 }
265 }
266
267 void wxCheckBox::Toggle()
268 {
269 m_isPressed = false;
270
271 Status status = m_status;
272
273 switch ( Get3StateValue() )
274 {
275 case wxCHK_CHECKED:
276 Set3StateValue(Is3rdStateAllowedForUser() ? wxCHK_UNDETERMINED : wxCHK_UNCHECKED);
277 break;
278
279 case wxCHK_UNCHECKED:
280 Set3StateValue(wxCHK_CHECKED);
281 break;
282
283 case wxCHK_UNDETERMINED:
284 Set3StateValue(wxCHK_UNCHECKED);
285 break;
286 }
287
288 if( status != m_status )
289 SendEvent();
290 }
291
292 void wxCheckBox::ChangeValue(bool value)
293 {
294 SetValue(value);
295
296 SendEvent();
297 }
298
299 void wxCheckBox::SendEvent()
300 {
301 wxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, GetId());
302 InitCommandEvent(event);
303 wxCheckBoxState state = Get3StateValue();
304
305 // If the style flag to allow the user setting the undetermined state
306 // is not set, then skip the undetermined state and set it to unchecked.
307 if ( state == wxCHK_UNDETERMINED && !Is3rdStateAllowedForUser() )
308 {
309 state = wxCHK_UNCHECKED;
310 Set3StateValue(state);
311 }
312
313 event.SetInt(state);
314 Command(event);
315 }
316
317 // ----------------------------------------------------------------------------
318 // input handling
319 // ----------------------------------------------------------------------------
320
321 bool wxCheckBox::PerformAction(const wxControlAction& action,
322 long numArg,
323 const wxString& strArg)
324 {
325 if ( action == wxACTION_BUTTON_PRESS )
326 Press();
327 else if ( action == wxACTION_BUTTON_RELEASE )
328 Release();
329 if ( action == wxACTION_CHECKBOX_CHECK )
330 ChangeValue(true);
331 else if ( action == wxACTION_CHECKBOX_CLEAR )
332 ChangeValue(false);
333 else if ( action == wxACTION_CHECKBOX_TOGGLE )
334 Toggle();
335 else
336 return wxControl::PerformAction(action, numArg, strArg);
337
338 return true;
339 }
340
341 /* static */
342 wxInputHandler *wxCheckBox::CreateStdInputHandler(wxInputHandler *handlerDef)
343 {
344 static wxStdCheckboxInputHandler s_handler(handlerDef);
345
346 return &s_handler;
347 }
348
349 // ----------------------------------------------------------------------------
350 // wxStdCheckboxInputHandler
351 // ----------------------------------------------------------------------------
352
353 wxStdCheckboxInputHandler::wxStdCheckboxInputHandler(wxInputHandler *def)
354 : wxStdInputHandler(wxButton::GetStdInputHandler(def))
355 {
356 }
357
358 bool wxStdCheckboxInputHandler::HandleActivation(wxInputConsumer *consumer,
359 bool WXUNUSED(activated))
360 {
361 // only the focused checkbox appearance changes when the app gains/loses
362 // activation
363 return consumer->GetInputWindow()->IsFocused();
364 }
365
366 #endif // wxUSE_CHECKBOX