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