]> git.saurik.com Git - wxWidgets.git/blame - src/univ/radiobox.cpp
Added wxWrapSizer (modified patch: [1826950] Wrapping Sizer) from Arne Steinarson
[wxWidgets.git] / src / univ / radiobox.cpp
CommitLineData
1e6feb95 1/////////////////////////////////////////////////////////////////////////////
8228b893 2// Name: src/univ/radiobox.cpp
1e6feb95
VZ
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
cc11cc69
WS
28#include "wx/radiobox.h"
29
1e6feb95
VZ
30#ifndef WX_PRECOMP
31 #include "wx/dcclient.h"
1e6feb95
VZ
32 #include "wx/radiobut.h"
33 #include "wx/validate.h"
584ad2a3 34 #include "wx/arrstr.h"
1e6feb95
VZ
35#endif
36
d4e5272b
JS
37#include "wx/tooltip.h"
38
1e6feb95
VZ
39#include "wx/univ/theme.h"
40#include "wx/univ/renderer.h"
41#include "wx/univ/inphand.h"
42#include "wx/univ/colschem.h"
43
44// ----------------------------------------------------------------------------
45// constants
46// ----------------------------------------------------------------------------
47
48static const int BUTTON_BORDER_X = 2;
49static const int BUTTON_BORDER_Y = 4;
50
51static const int BOX_BORDER_X = 2;
52static const int BOX_BORDER_Y = 2;
53
54// ----------------------------------------------------------------------------
55// wxRadioBox event handler
56// ----------------------------------------------------------------------------
57
58class wxRadioHookHandler : public wxEvtHandler
59{
60public:
61 wxRadioHookHandler(wxRadioBox *radio) { m_radio = radio; }
62
63 virtual bool ProcessEvent(wxEvent& event)
64 {
65 // we intercept the command events from radio buttons
66 if ( event.GetEventType() == wxEVT_COMMAND_RADIOBUTTON_SELECTED )
67 {
68 m_radio->OnRadioButton(event);
69 }
70 else if ( event.GetEventType() == wxEVT_KEY_DOWN )
71 {
72 if ( m_radio->OnKeyDown((wxKeyEvent &)event) )
73 {
a290fa5a 74 return true;
1e6feb95
VZ
75 }
76 }
77
78 // just pass it on
79 return GetNextHandler()->ProcessEvent(event);
80 }
81
82private:
83 wxRadioBox *m_radio;
84};
85
86// ============================================================================
87// implementation
88// ============================================================================
89
90IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
91
92// ----------------------------------------------------------------------------
93// wxRadioBox creation
94// ----------------------------------------------------------------------------
95
96void wxRadioBox::Init()
97{
98 m_selection = -1;
1e6feb95
VZ
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
21e0a4d5 177 SetMajorDim(majorDim == 0 ? n : majorDim, style);
1e6feb95
VZ
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
aa61d352
VZ
201 unsigned int count = m_buttons.GetCount();
202 for ( unsigned int n = 0; n < count; n++ )
1e6feb95 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
1e6feb95
VZ
214void wxRadioBox::Append(int count, const wxString *choices)
215{
216 if ( !count )
217 return;
218
219 wxWindow *parent = GetParent();
220 m_buttons.Alloc(count);
221 for ( int n = 0; n < count; n++ )
222 {
223 // make the first button in the box the start of new group by giving it
224 // wxRB_GROUP style
a290fa5a 225 wxRadioButton *btn = new wxRadioButton(parent, wxID_ANY, choices[n],
1e6feb95
VZ
226 wxDefaultPosition,
227 wxDefaultSize,
228 n == 0 ? wxRB_GROUP : 0);
229
230 // we want to get the events from the buttons to translate it into
231 btn->PushEventHandler(new wxRadioHookHandler(this));
232 m_buttons.Add(btn);
233 }
234}
235
236// ----------------------------------------------------------------------------
237// selection
238// ----------------------------------------------------------------------------
239
240void wxRadioBox::SetSelection(int n)
241{
242 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetSelection") );
243
244 m_selection = n;
245
246 wxRadioButton *btn = m_buttons[n];
247
248 // the selected button is always focused in the radiobox
249 btn->SetFocus();
250
251 // this will also unselect the previously selected button in our group
a290fa5a 252 btn->SetValue(true);
1e6feb95
VZ
253}
254
255int wxRadioBox::GetSelection() const
256{
257 return m_selection;
258}
259
260void wxRadioBox::SendRadioEvent()
261{
262 wxCHECK_RET( m_selection != -1, _T("no active radio button") );
263
264 wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, GetId());
265 InitCommandEvent(event);
266 event.SetInt(m_selection);
267 event.SetString(GetString(m_selection));
268
269 Command(event);
270}
271
272void wxRadioBox::OnRadioButton(wxEvent& event)
273{
274 int n = m_buttons.Index((wxRadioButton *)event.GetEventObject());
275 wxCHECK_RET( n != wxNOT_FOUND, _T("click from alien radio button") );
276
277 m_selection = n;
278
279 SendRadioEvent();
280}
281
282// ----------------------------------------------------------------------------
283// methods forwarded to the buttons
284// ----------------------------------------------------------------------------
285
aa61d352 286wxString wxRadioBox::GetString(unsigned int n) const
1e6feb95 287{
0966aee3 288 wxCHECK_MSG( IsValid(n), wxEmptyString,
1e6feb95
VZ
289 _T("invalid index in wxRadioBox::GetString") );
290
291 return m_buttons[n]->GetLabel();
292}
293
aa61d352 294void wxRadioBox::SetString(unsigned int n, const wxString& label)
1e6feb95
VZ
295{
296 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetString") );
297
298 m_buttons[n]->SetLabel(label);
299}
300
aa61d352 301bool wxRadioBox::Enable(unsigned int n, bool enable)
1e6feb95 302{
1a87edf2 303 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Enable") );
1e6feb95 304
1a87edf2 305 return m_buttons[n]->Enable(enable);
1e6feb95
VZ
306}
307
aa61d352 308bool wxRadioBox::IsItemEnabled(unsigned int n) const
1661354b
VZ
309{
310 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::IsItemEnabled") );
311
312 return m_buttons[n]->IsEnabled();
313}
314
aa61d352 315bool wxRadioBox::Show(unsigned int n, bool show)
1e6feb95 316{
fa50c0e3 317 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Show") );
1e6feb95 318
fa50c0e3 319 return m_buttons[n]->Show(show);
1e6feb95
VZ
320}
321
aa61d352 322bool wxRadioBox::IsItemShown(unsigned int n) const
1661354b
VZ
323{
324 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::IsItemShown") );
325
326 return m_buttons[n]->IsShown();
327}
328
1e6feb95
VZ
329// ----------------------------------------------------------------------------
330// methods forwarded to the static box
331// ----------------------------------------------------------------------------
332
333bool wxRadioBox::Enable(bool enable)
334{
528a5fe4 335 if ( !wxStaticBox::Enable(enable) )
a290fa5a 336 return false;
528a5fe4
VZ
337
338 // also enable/disable the buttons
aa61d352
VZ
339 const unsigned int count = m_buttons.GetCount();
340 for ( unsigned int n = 0; n < count; n++ )
528a5fe4
VZ
341 {
342 Enable(n, enable);
343 }
344
a290fa5a 345 return true;
1e6feb95
VZ
346}
347
348bool wxRadioBox::Show(bool show)
349{
528a5fe4 350 if ( !wxStaticBox::Show(show) )
a290fa5a 351 return false;
528a5fe4
VZ
352
353 // also show/hide the buttons
aa61d352
VZ
354 const unsigned int count = m_buttons.GetCount();
355 for ( unsigned int n = 0; n < count; n++ )
528a5fe4
VZ
356 {
357 Show(n, show);
358 }
359
a290fa5a 360 return true;
1e6feb95
VZ
361}
362
363wxString wxRadioBox::GetLabel() const
364{
365 return wxStaticBox::GetLabel();
366}
367
368void wxRadioBox::SetLabel(const wxString& label)
369{
370 wxStaticBox::SetLabel(label);
371}
372
d4e5272b
JS
373#if wxUSE_TOOLTIPS
374void wxRadioBox::DoSetToolTip(wxToolTip *tooltip)
375{
376 wxControl::DoSetToolTip(tooltip);
377
378 // Also set them for all Radio Buttons
aa61d352
VZ
379 const unsigned int count = m_buttons.GetCount();
380 for ( unsigned int n = 0; n < count; n++ )
d4e5272b
JS
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
1e6feb95
VZ
390// ----------------------------------------------------------------------------
391// buttons positioning
392// ----------------------------------------------------------------------------
393
394wxSize wxRadioBox::GetMaxButtonSize() const
395{
8d7eaf91 396 int widthMax, heightMax, width = 0, height = 0;
1e6feb95
VZ
397 widthMax = heightMax = 0;
398
aa61d352
VZ
399 const unsigned int count = GetCount();
400 for ( unsigned int n = 0; n < count; n++ )
1e6feb95
VZ
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
413wxSize wxRadioBox::DoGetBestClientSize() const
414{
415 wxSize sizeBtn = GetMaxButtonSize();
416
21e0a4d5
VZ
417 sizeBtn.x *= GetColumnCount();
418 sizeBtn.y *= GetRowCount();
1e6feb95
VZ
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
432void 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();
c47addef 438 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
1e6feb95 439
e3f3984b
VS
440 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
441 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
1e6feb95
VZ
442
443 int x = x0,
444 y = y0;
445
aa61d352
VZ
446 const unsigned int count = GetCount();
447 for ( unsigned int n = 0; n < count; n++ )
1e6feb95
VZ
448 {
449 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
450
451 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
452 {
453 // from top to bottom
21e0a4d5 454 if ( (n + 1) % GetRowCount() )
1e6feb95
VZ
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
21e0a4d5 469 if ( (n + 1) % GetColumnCount() )
1e6feb95
VZ
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
488bool 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:
a290fa5a 510 return false;
1e6feb95
VZ
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
a290fa5a 523 return true;
1e6feb95
VZ
524}
525
526#endif // wxUSE_RADIOBOX