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