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