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