]> git.saurik.com Git - wxWidgets.git/blame - src/univ/radiobox.cpp
1. derive wxGTK wxRadioBox from wxRadioBoxBase now, as in all other ports
[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
fa50c0e3 307bool wxRadioBox::Show(int n, bool show)
1e6feb95 308{
fa50c0e3 309 wxCHECK_MSG( IsValid(n), false, _T("invalid index in wxRadioBox::Show") );
1e6feb95 310
fa50c0e3 311 return m_buttons[n]->Show(show);
1e6feb95
VZ
312}
313
314// ----------------------------------------------------------------------------
315// methods forwarded to the static box
316// ----------------------------------------------------------------------------
317
318bool wxRadioBox::Enable(bool enable)
319{
528a5fe4 320 if ( !wxStaticBox::Enable(enable) )
a290fa5a 321 return false;
528a5fe4
VZ
322
323 // also enable/disable the buttons
324 size_t count = m_buttons.GetCount();
325 for ( size_t n = 0; n < count; n++ )
326 {
327 Enable(n, enable);
328 }
329
a290fa5a 330 return true;
1e6feb95
VZ
331}
332
333bool wxRadioBox::Show(bool show)
334{
528a5fe4 335 if ( !wxStaticBox::Show(show) )
a290fa5a 336 return false;
528a5fe4
VZ
337
338 // also show/hide the buttons
339 size_t count = m_buttons.GetCount();
340 for ( size_t n = 0; n < count; n++ )
341 {
342 Show(n, show);
343 }
344
a290fa5a 345 return true;
1e6feb95
VZ
346}
347
348wxString wxRadioBox::GetLabel() const
349{
350 return wxStaticBox::GetLabel();
351}
352
353void wxRadioBox::SetLabel(const wxString& label)
354{
355 wxStaticBox::SetLabel(label);
356}
357
d4e5272b
JS
358#if wxUSE_TOOLTIPS
359void wxRadioBox::DoSetToolTip(wxToolTip *tooltip)
360{
361 wxControl::DoSetToolTip(tooltip);
362
363 // Also set them for all Radio Buttons
364 size_t count = m_buttons.GetCount();
365 for ( size_t n = 0; n < count; n++ )
366 {
367 if (tooltip)
368 m_buttons[n]->SetToolTip(tooltip->GetTip());
369 else
370 m_buttons[n]->SetToolTip(NULL);
371 }
372}
373#endif // wxUSE_TOOLTIPS
374
1e6feb95
VZ
375// ----------------------------------------------------------------------------
376// buttons positioning
377// ----------------------------------------------------------------------------
378
379wxSize wxRadioBox::GetMaxButtonSize() const
380{
381 int widthMax, heightMax, width, height;
382 widthMax = heightMax = 0;
383
384 int count = GetCount();
385 for ( int n = 0; n < count; n++ )
386 {
387 m_buttons[n]->GetBestSize(&width, &height);
388
389 if ( width > widthMax )
390 widthMax = width;
391 if ( height > heightMax )
392 heightMax = height;
393 }
394
395 return wxSize(widthMax + BUTTON_BORDER_X, heightMax + BUTTON_BORDER_Y);
396}
397
398wxSize wxRadioBox::DoGetBestClientSize() const
399{
400 wxSize sizeBtn = GetMaxButtonSize();
401
21e0a4d5
VZ
402 sizeBtn.x *= GetColumnCount();
403 sizeBtn.y *= GetRowCount();
1e6feb95
VZ
404
405 // add a border around all buttons
406 sizeBtn.x += 2*BOX_BORDER_X;
407 sizeBtn.y += 2*BOX_BORDER_Y;
408
409 // account for the area taken by static box
410 wxRect rect = GetBorderGeometry();
411 sizeBtn.x += rect.x + rect.width;
412 sizeBtn.y += rect.y + rect.height;
413
414 return sizeBtn;
415}
416
417void wxRadioBox::DoMoveWindow(int x0, int y0, int width, int height)
418{
419 wxStaticBox::DoMoveWindow(x0, y0, width, height);
420
421 wxSize sizeBtn = GetMaxButtonSize();
422 wxPoint ptOrigin = GetBoxAreaOrigin();
c47addef 423 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
1e6feb95 424
e3f3984b
VS
425 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
426 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
1e6feb95
VZ
427
428 int x = x0,
429 y = y0;
430
431 int count = GetCount();
432 for ( int n = 0; n < count; n++ )
433 {
434 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
435
436 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
437 {
438 // from top to bottom
21e0a4d5 439 if ( (n + 1) % GetRowCount() )
1e6feb95
VZ
440 {
441 // continue in this column
442 y += sizeBtn.y;
443 }
444 else
445 {
446 // start a new column
447 x += sizeBtn.x;
448 y = y0;
449 }
450 }
451 else // wxRA_LEFTTORIGHT: mirror the code above
452 {
453 // from left to right
21e0a4d5 454 if ( (n + 1) % GetColumnCount() )
1e6feb95
VZ
455 {
456 // continue in this row
457 x += sizeBtn.x;
458 }
459 else
460 {
461 // start a new row
462 y += sizeBtn.y;
463 x = x0;
464 }
465 }
466 }
467}
468
469// ----------------------------------------------------------------------------
470// keyboard navigation
471// ----------------------------------------------------------------------------
472
473bool wxRadioBox::OnKeyDown(wxKeyEvent& event)
474{
475 wxDirection dir;
476 switch ( event.GetKeyCode() )
477 {
478 case WXK_UP:
479 dir = wxUP;
480 break;
481
482 case WXK_LEFT:
483 dir = wxLEFT;
484 break;
485
486 case WXK_DOWN:
487 dir = wxDOWN;
488 break;
489
490 case WXK_RIGHT:
491 dir = wxRIGHT;
492 break;
493
494 default:
a290fa5a 495 return false;
1e6feb95
VZ
496 }
497
498 int selOld = GetSelection();
499 int selNew = GetNextItem(selOld, dir, GetWindowStyle());
500 if ( selNew != selOld )
501 {
502 SetSelection(selNew);
503
504 // emulate the button click
505 SendRadioEvent();
506 }
507
a290fa5a 508 return true;
1e6feb95
VZ
509}
510
511#endif // wxUSE_RADIOBOX
512