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