]> git.saurik.com Git - wxWidgets.git/blob - src/univ/radiobox.cpp
CGImage Creation is always available under OS X
[wxWidgets.git] / src / univ / radiobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/radiobox.cpp
3 // Purpose: wxRadioBox implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 11.09.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_RADIOBOX
27
28 #ifndef WX_PRECOMP
29 #include "wx/dcclient.h"
30 #include "wx/radiobox.h"
31 #include "wx/radiobut.h"
32 #include "wx/validate.h"
33 #include "wx/arrstr.h"
34 #endif
35
36 #include "wx/tooltip.h"
37
38 #include "wx/univ/theme.h"
39 #include "wx/univ/renderer.h"
40 #include "wx/univ/inphand.h"
41 #include "wx/univ/colschem.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 static const int BUTTON_BORDER_X = 2;
48 static const int BUTTON_BORDER_Y = 4;
49
50 static const int BOX_BORDER_X = 2;
51 static const int BOX_BORDER_Y = 2;
52
53 // ----------------------------------------------------------------------------
54 // wxRadioBox event handler
55 // ----------------------------------------------------------------------------
56
57 class wxRadioHookHandler : public wxEvtHandler
58 {
59 public:
60 wxRadioHookHandler(wxRadioBox *radio) { m_radio = radio; }
61
62 virtual bool ProcessEvent(wxEvent& event)
63 {
64 // we intercept the command events from radio buttons
65 if ( event.GetEventType() == wxEVT_COMMAND_RADIOBUTTON_SELECTED )
66 {
67 m_radio->OnRadioButton(event);
68 }
69 else if ( event.GetEventType() == wxEVT_KEY_DOWN )
70 {
71 if ( m_radio->OnKeyDown((wxKeyEvent &)event) )
72 {
73 return true;
74 }
75 }
76
77 // just pass it on
78 return GetNextHandler()->ProcessEvent(event);
79 }
80
81 private:
82 wxRadioBox *m_radio;
83 };
84
85 // ============================================================================
86 // implementation
87 // ============================================================================
88
89 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
90
91 // ----------------------------------------------------------------------------
92 // wxRadioBox creation
93 // ----------------------------------------------------------------------------
94
95 void wxRadioBox::Init()
96 {
97 m_selection = -1;
98 m_majorDim = 0;
99 }
100
101 wxRadioBox::wxRadioBox(wxWindow *parent, wxWindowID id, const wxString& title,
102 const wxPoint& pos, const wxSize& size,
103 const wxArrayString& choices,
104 int majorDim, long style,
105 const wxValidator& val, const wxString& name)
106 {
107 wxCArrayString chs(choices);
108
109 Init();
110
111 (void)Create(parent, id, title, pos, size, chs.GetCount(),
112 chs.GetStrings(), majorDim, style, val, name);
113 }
114
115 bool wxRadioBox::Create(wxWindow *parent,
116 wxWindowID id,
117 const wxString& title,
118 const wxPoint& pos,
119 const wxSize& size,
120 const wxArrayString& choices,
121 int majorDim,
122 long style,
123 const wxValidator& val,
124 const wxString& name)
125 {
126 wxCArrayString chs(choices);
127
128 return Create(parent, id, title, pos, size, chs.GetCount(),
129 chs.GetStrings(), majorDim, style, val, name);
130 }
131
132 bool wxRadioBox::Create(wxWindow *parent,
133 wxWindowID id,
134 const wxString& title,
135 const wxPoint& pos,
136 const wxSize& size,
137 int n,
138 const wxString *choices,
139 int majorDim,
140 long style,
141 const wxValidator& wxVALIDATOR_PARAM(val),
142 const wxString& name)
143 {
144 // for compatibility with the other ports which don't handle (yet?)
145 // wxRA_LEFTTORIGHT and wxRA_TOPTOBOTTOM flags, we add them ourselves if
146 // not specified
147 if ( !(style & (wxRA_LEFTTORIGHT | wxRA_TOPTOBOTTOM)) )
148 {
149 // horizontal radiobox use left to right layout
150 if ( style & wxRA_HORIZONTAL )
151 {
152 style |= wxRA_LEFTTORIGHT;
153 }
154 else if ( style & wxRA_VERTICAL )
155 {
156 style |= wxRA_TOPTOBOTTOM;
157 }
158 else
159 {
160 wxFAIL_MSG( _T("you must specify wxRA_XXX style!") );
161
162 // use default
163 style = wxRA_HORIZONTAL | wxRA_LEFTTORIGHT;
164 }
165 }
166
167 if ( !wxStaticBox::Create(parent, id, title, pos, size, style, name) )
168 return false;
169
170 #if wxUSE_VALIDATORS
171 SetValidator(val);
172 #endif // wxUSE_VALIDATORS
173
174 Append(n, choices);
175
176 // majorDim default value is 0 which means make one row/column
177 SetMajorDim(majorDim == 0 ? n : majorDim);
178
179 if ( size == wxDefaultSize )
180 {
181 SetClientSize(DoGetBestClientSize());
182 }
183
184 // Need to move the radiobox in order to move the radio buttons
185 wxPoint actualPos = GetPosition();
186 wxSize actualSize = GetSize();
187 DoMoveWindow(actualPos.x, actualPos.y, actualSize.x, actualSize.y);
188
189 // radiobox should already have selection so select at least one item
190 SetSelection(0);
191
192 return true;
193 }
194
195 wxRadioBox::~wxRadioBox()
196 {
197 // remove the event handlers we pushed on them from all buttons and delete
198 // the buttons themselves: this must be done as the user code expects them
199 // to disappear now and not some time later when they will be deleted by
200 // our (common) parent
201 size_t count = m_buttons.GetCount();
202 for ( size_t n = 0; n < count; n++ )
203 {
204 m_buttons[n]->PopEventHandler(true /* delete it */);
205
206 delete m_buttons[n];
207 }
208 }
209
210 // ----------------------------------------------------------------------------
211 // wxRadioBox init
212 // ----------------------------------------------------------------------------
213
214 void wxRadioBox::SetMajorDim(int majorDim)
215 {
216 wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") );
217
218 m_majorDim = majorDim;
219
220 int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim;
221
222 if ( GetWindowStyle() & wxRA_SPECIFY_COLS )
223 {
224 m_numCols = majorDim;
225 m_numRows = minorDim;
226 }
227 else // wxRA_SPECIFY_ROWS
228 {
229 m_numCols = minorDim;
230 m_numRows = majorDim;
231 }
232 }
233
234 void wxRadioBox::Append(int count, const wxString *choices)
235 {
236 if ( !count )
237 return;
238
239 wxWindow *parent = GetParent();
240 m_buttons.Alloc(count);
241 for ( int n = 0; n < count; n++ )
242 {
243 // make the first button in the box the start of new group by giving it
244 // wxRB_GROUP style
245 wxRadioButton *btn = new wxRadioButton(parent, wxID_ANY, choices[n],
246 wxDefaultPosition,
247 wxDefaultSize,
248 n == 0 ? wxRB_GROUP : 0);
249
250 // we want to get the events from the buttons to translate it into
251 btn->PushEventHandler(new wxRadioHookHandler(this));
252 m_buttons.Add(btn);
253 }
254 }
255
256 // ----------------------------------------------------------------------------
257 // selection
258 // ----------------------------------------------------------------------------
259
260 void wxRadioBox::SetSelection(int n)
261 {
262 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetSelection") );
263
264 m_selection = n;
265
266 wxRadioButton *btn = m_buttons[n];
267
268 // the selected button is always focused in the radiobox
269 btn->SetFocus();
270
271 // this will also unselect the previously selected button in our group
272 btn->SetValue(true);
273 }
274
275 int wxRadioBox::GetSelection() const
276 {
277 return m_selection;
278 }
279
280 void wxRadioBox::SendRadioEvent()
281 {
282 wxCHECK_RET( m_selection != -1, _T("no active radio button") );
283
284 wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, GetId());
285 InitCommandEvent(event);
286 event.SetInt(m_selection);
287 event.SetString(GetString(m_selection));
288
289 Command(event);
290 }
291
292 void wxRadioBox::OnRadioButton(wxEvent& event)
293 {
294 int n = m_buttons.Index((wxRadioButton *)event.GetEventObject());
295 wxCHECK_RET( n != wxNOT_FOUND, _T("click from alien radio button") );
296
297 m_selection = n;
298
299 SendRadioEvent();
300 }
301
302 // ----------------------------------------------------------------------------
303 // methods forwarded to the buttons
304 // ----------------------------------------------------------------------------
305
306 wxString wxRadioBox::GetString(int n) const
307 {
308 wxCHECK_MSG( IsValid(n), wxEmptyString,
309 _T("invalid index in wxRadioBox::GetString") );
310
311 return m_buttons[n]->GetLabel();
312 }
313
314 void wxRadioBox::SetString(int n, const wxString& label)
315 {
316 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetString") );
317
318 m_buttons[n]->SetLabel(label);
319 }
320
321 bool wxRadioBox::Enable(int n, bool enable)
322 {
323 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Enable") );
324
325 return m_buttons[n]->Enable(enable);
326 }
327
328 bool wxRadioBox::Show(int n, bool show)
329 {
330 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Show") );
331
332 return m_buttons[n]->Show(show);
333 }
334
335 // ----------------------------------------------------------------------------
336 // methods forwarded to the static box
337 // ----------------------------------------------------------------------------
338
339 bool wxRadioBox::Enable(bool enable)
340 {
341 if ( !wxStaticBox::Enable(enable) )
342 return false;
343
344 // also enable/disable the buttons
345 size_t count = m_buttons.GetCount();
346 for ( size_t n = 0; n < count; n++ )
347 {
348 Enable(n, enable);
349 }
350
351 return true;
352 }
353
354 bool wxRadioBox::Show(bool show)
355 {
356 if ( !wxStaticBox::Show(show) )
357 return false;
358
359 // also show/hide the buttons
360 size_t count = m_buttons.GetCount();
361 for ( size_t n = 0; n < count; n++ )
362 {
363 Show(n, show);
364 }
365
366 return true;
367 }
368
369 wxString wxRadioBox::GetLabel() const
370 {
371 return wxStaticBox::GetLabel();
372 }
373
374 void wxRadioBox::SetLabel(const wxString& label)
375 {
376 wxStaticBox::SetLabel(label);
377 }
378
379 #if wxUSE_TOOLTIPS
380 void wxRadioBox::DoSetToolTip(wxToolTip *tooltip)
381 {
382 wxControl::DoSetToolTip(tooltip);
383
384 // Also set them for all Radio Buttons
385 size_t count = m_buttons.GetCount();
386 for ( size_t n = 0; n < count; n++ )
387 {
388 if (tooltip)
389 m_buttons[n]->SetToolTip(tooltip->GetTip());
390 else
391 m_buttons[n]->SetToolTip(NULL);
392 }
393 }
394 #endif // wxUSE_TOOLTIPS
395
396 // ----------------------------------------------------------------------------
397 // buttons positioning
398 // ----------------------------------------------------------------------------
399
400 wxSize wxRadioBox::GetMaxButtonSize() const
401 {
402 int widthMax, heightMax, width, height;
403 widthMax = heightMax = 0;
404
405 int count = GetCount();
406 for ( int n = 0; n < count; n++ )
407 {
408 m_buttons[n]->GetBestSize(&width, &height);
409
410 if ( width > widthMax )
411 widthMax = width;
412 if ( height > heightMax )
413 heightMax = height;
414 }
415
416 return wxSize(widthMax + BUTTON_BORDER_X, heightMax + BUTTON_BORDER_Y);
417 }
418
419 wxSize wxRadioBox::DoGetBestClientSize() const
420 {
421 wxSize sizeBtn = GetMaxButtonSize();
422
423 sizeBtn.x *= m_numCols;
424 sizeBtn.y *= m_numRows;
425
426 // add a border around all buttons
427 sizeBtn.x += 2*BOX_BORDER_X;
428 sizeBtn.y += 2*BOX_BORDER_Y;
429
430 // account for the area taken by static box
431 wxRect rect = GetBorderGeometry();
432 sizeBtn.x += rect.x + rect.width;
433 sizeBtn.y += rect.y + rect.height;
434
435 return sizeBtn;
436 }
437
438 void wxRadioBox::DoMoveWindow(int x0, int y0, int width, int height)
439 {
440 wxStaticBox::DoMoveWindow(x0, y0, width, height);
441
442 wxSize sizeBtn = GetMaxButtonSize();
443 wxPoint ptOrigin = GetBoxAreaOrigin();
444 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
445
446 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
447 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
448
449 int x = x0,
450 y = y0;
451
452 int count = GetCount();
453 for ( int n = 0; n < count; n++ )
454 {
455 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
456
457 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
458 {
459 // from top to bottom
460 if ( (n + 1) % m_numRows )
461 {
462 // continue in this column
463 y += sizeBtn.y;
464 }
465 else
466 {
467 // start a new column
468 x += sizeBtn.x;
469 y = y0;
470 }
471 }
472 else // wxRA_LEFTTORIGHT: mirror the code above
473 {
474 // from left to right
475 if ( (n + 1) % m_numCols )
476 {
477 // continue in this row
478 x += sizeBtn.x;
479 }
480 else
481 {
482 // start a new row
483 y += sizeBtn.y;
484 x = x0;
485 }
486 }
487 }
488 }
489
490 // ----------------------------------------------------------------------------
491 // keyboard navigation
492 // ----------------------------------------------------------------------------
493
494 bool wxRadioBox::OnKeyDown(wxKeyEvent& event)
495 {
496 wxDirection dir;
497 switch ( event.GetKeyCode() )
498 {
499 case WXK_UP:
500 dir = wxUP;
501 break;
502
503 case WXK_LEFT:
504 dir = wxLEFT;
505 break;
506
507 case WXK_DOWN:
508 dir = wxDOWN;
509 break;
510
511 case WXK_RIGHT:
512 dir = wxRIGHT;
513 break;
514
515 default:
516 return false;
517 }
518
519 int selOld = GetSelection();
520 int selNew = GetNextItem(selOld, dir, GetWindowStyle());
521 if ( selNew != selOld )
522 {
523 SetSelection(selNew);
524
525 // emulate the button click
526 SendRadioEvent();
527 }
528
529 return true;
530 }
531
532 #endif // wxUSE_RADIOBOX
533