]> git.saurik.com Git - wxWidgets.git/blame - src/univ/radiobox.cpp
wxMultiChoiceDialog uses now wxCheckListBox if possible, wxListBox if not
[wxWidgets.git] / src / univ / radiobox.cpp
CommitLineData
1e6feb95
VZ
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$
442b35b5 8// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// Licence: wxWindows licence
1e6feb95
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
1e6feb95
VZ
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"
584ad2a3 33 #include "wx/arrstr.h"
1e6feb95
VZ
34#endif
35
d4e5272b
JS
36#include "wx/tooltip.h"
37
1e6feb95
VZ
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
47static const int BUTTON_BORDER_X = 2;
48static const int BUTTON_BORDER_Y = 4;
49
50static const int BOX_BORDER_X = 2;
51static const int BOX_BORDER_Y = 2;
52
53// ----------------------------------------------------------------------------
54// wxRadioBox event handler
55// ----------------------------------------------------------------------------
56
57class wxRadioHookHandler : public wxEvtHandler
58{
59public:
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 {
a290fa5a 73 return true;
1e6feb95
VZ
74 }
75 }
76
77 // just pass it on
78 return GetNextHandler()->ProcessEvent(event);
79 }
80
81private:
82 wxRadioBox *m_radio;
83};
84
85// ============================================================================
86// implementation
87// ============================================================================
88
89IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
90
91// ----------------------------------------------------------------------------
92// wxRadioBox creation
93// ----------------------------------------------------------------------------
94
95void wxRadioBox::Init()
96{
97 m_selection = -1;
98 m_majorDim = 0;
99}
100
584ad2a3
MB
101wxRadioBox::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
0966aee3 111 (void)Create(parent, id, title, pos, size, chs.GetCount(),
584ad2a3
MB
112 chs.GetStrings(), majorDim, style, val, name);
113}
114
115bool 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
0966aee3 128 return Create(parent, id, title, pos, size, chs.GetCount(),
584ad2a3
MB
129 chs.GetStrings(), majorDim, style, val, name);
130}
131
1e6feb95
VZ
132bool 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,
1c16e6df 141 const wxValidator& wxVALIDATOR_PARAM(val),
1e6feb95
VZ
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) )
a290fa5a 168 return false;
1e6feb95
VZ
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
d2699196
JS
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
1e6feb95
VZ
189 // radiobox should already have selection so select at least one item
190 SetSelection(0);
191
a290fa5a 192 return true;
1e6feb95
VZ
193}
194
195wxRadioBox::~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 {
a290fa5a 204 m_buttons[n]->PopEventHandler(true /* delete it */);
1e6feb95
VZ
205
206 delete m_buttons[n];
207 }
208}
209
210// ----------------------------------------------------------------------------
211// wxRadioBox init
212// ----------------------------------------------------------------------------
213
214void 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
234void 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
a290fa5a 245 wxRadioButton *btn = new wxRadioButton(parent, wxID_ANY, choices[n],
1e6feb95
VZ
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
260void 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
a290fa5a 272 btn->SetValue(true);
1e6feb95
VZ
273}
274
275int wxRadioBox::GetSelection() const
276{
277 return m_selection;
278}
279
280void 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
292void 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
306wxString wxRadioBox::GetString(int n) const
307{
0966aee3 308 wxCHECK_MSG( IsValid(n), wxEmptyString,
1e6feb95
VZ
309 _T("invalid index in wxRadioBox::GetString") );
310
311 return m_buttons[n]->GetLabel();
312}
313
314void 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
1a87edf2 321bool wxRadioBox::Enable(int n, bool enable)
1e6feb95 322{
1a87edf2 323 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Enable") );
1e6feb95 324
1a87edf2 325 return m_buttons[n]->Enable(enable);
1e6feb95
VZ
326}
327
fa50c0e3 328bool wxRadioBox::Show(int n, bool show)
1e6feb95 329{
fa50c0e3 330 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Show") );
1e6feb95 331
fa50c0e3 332 return m_buttons[n]->Show(show);
1e6feb95
VZ
333}
334
335// ----------------------------------------------------------------------------
336// methods forwarded to the static box
337// ----------------------------------------------------------------------------
338
339bool wxRadioBox::Enable(bool enable)
340{
528a5fe4 341 if ( !wxStaticBox::Enable(enable) )
a290fa5a 342 return false;
528a5fe4
VZ
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
a290fa5a 351 return true;
1e6feb95
VZ
352}
353
354bool wxRadioBox::Show(bool show)
355{
528a5fe4 356 if ( !wxStaticBox::Show(show) )
a290fa5a 357 return false;
528a5fe4
VZ
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
a290fa5a 366 return true;
1e6feb95
VZ
367}
368
369wxString wxRadioBox::GetLabel() const
370{
371 return wxStaticBox::GetLabel();
372}
373
374void wxRadioBox::SetLabel(const wxString& label)
375{
376 wxStaticBox::SetLabel(label);
377}
378
d4e5272b
JS
379#if wxUSE_TOOLTIPS
380void 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
1e6feb95
VZ
396// ----------------------------------------------------------------------------
397// buttons positioning
398// ----------------------------------------------------------------------------
399
400wxSize 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
419wxSize 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
438void 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();
c47addef 444 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
1e6feb95 445
e3f3984b
VS
446 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
447 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
1e6feb95
VZ
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
494bool 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:
a290fa5a 516 return false;
1e6feb95
VZ
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
a290fa5a 529 return true;
1e6feb95
VZ
530}
531
532#endif // wxUSE_RADIOBOX
533