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