]> git.saurik.com Git - wxWidgets.git/blame - src/univ/radiobox.cpp
only work on the focus if the control is shown
[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)
6aa89a22 9// Licence: wxWindows licence
1e6feb95
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
d2699196
JS
156 // Need to move the radiobox in order to move the radio buttons
157 wxPoint actualPos = GetPosition();
158 wxSize actualSize = GetSize();
159 DoMoveWindow(actualPos.x, actualPos.y, actualSize.x, actualSize.y);
160
1e6feb95
VZ
161 // radiobox should already have selection so select at least one item
162 SetSelection(0);
163
164 return TRUE;
165}
166
167wxRadioBox::~wxRadioBox()
168{
169 // remove the event handlers we pushed on them from all buttons and delete
170 // the buttons themselves: this must be done as the user code expects them
171 // to disappear now and not some time later when they will be deleted by
172 // our (common) parent
173 size_t count = m_buttons.GetCount();
174 for ( size_t n = 0; n < count; n++ )
175 {
176 m_buttons[n]->PopEventHandler(TRUE /* delete it */);
177
178 delete m_buttons[n];
179 }
180}
181
182// ----------------------------------------------------------------------------
183// wxRadioBox init
184// ----------------------------------------------------------------------------
185
186void wxRadioBox::SetMajorDim(int majorDim)
187{
188 wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") );
189
190 m_majorDim = majorDim;
191
192 int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim;
193
194 if ( GetWindowStyle() & wxRA_SPECIFY_COLS )
195 {
196 m_numCols = majorDim;
197 m_numRows = minorDim;
198 }
199 else // wxRA_SPECIFY_ROWS
200 {
201 m_numCols = minorDim;
202 m_numRows = majorDim;
203 }
204}
205
206void wxRadioBox::Append(int count, const wxString *choices)
207{
208 if ( !count )
209 return;
210
211 wxWindow *parent = GetParent();
212 m_buttons.Alloc(count);
213 for ( int n = 0; n < count; n++ )
214 {
215 // make the first button in the box the start of new group by giving it
216 // wxRB_GROUP style
217 wxRadioButton *btn = new wxRadioButton(parent, -1, choices[n],
218 wxDefaultPosition,
219 wxDefaultSize,
220 n == 0 ? wxRB_GROUP : 0);
221
222 // we want to get the events from the buttons to translate it into
223 btn->PushEventHandler(new wxRadioHookHandler(this));
224 m_buttons.Add(btn);
225 }
226}
227
228// ----------------------------------------------------------------------------
229// selection
230// ----------------------------------------------------------------------------
231
232void wxRadioBox::SetSelection(int n)
233{
234 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetSelection") );
235
236 m_selection = n;
237
238 wxRadioButton *btn = m_buttons[n];
239
240 // the selected button is always focused in the radiobox
241 btn->SetFocus();
242
243 // this will also unselect the previously selected button in our group
244 btn->SetValue(TRUE);
245}
246
247int wxRadioBox::GetSelection() const
248{
249 return m_selection;
250}
251
252void wxRadioBox::SendRadioEvent()
253{
254 wxCHECK_RET( m_selection != -1, _T("no active radio button") );
255
256 wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, GetId());
257 InitCommandEvent(event);
258 event.SetInt(m_selection);
259 event.SetString(GetString(m_selection));
260
261 Command(event);
262}
263
264void wxRadioBox::OnRadioButton(wxEvent& event)
265{
266 int n = m_buttons.Index((wxRadioButton *)event.GetEventObject());
267 wxCHECK_RET( n != wxNOT_FOUND, _T("click from alien radio button") );
268
269 m_selection = n;
270
271 SendRadioEvent();
272}
273
274// ----------------------------------------------------------------------------
275// methods forwarded to the buttons
276// ----------------------------------------------------------------------------
277
278wxString wxRadioBox::GetString(int n) const
279{
280 wxCHECK_MSG( IsValid(n), _T(""),
281 _T("invalid index in wxRadioBox::GetString") );
282
283 return m_buttons[n]->GetLabel();
284}
285
286void wxRadioBox::SetString(int n, const wxString& label)
287{
288 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::SetString") );
289
290 m_buttons[n]->SetLabel(label);
291}
292
293void wxRadioBox::Enable(int n, bool enable)
294{
295 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::Enable") );
296
297 m_buttons[n]->Enable(enable);
298}
299
300void wxRadioBox::Show(int n, bool show)
301{
302 wxCHECK_RET( IsValid(n), _T("invalid index in wxRadioBox::Show") );
303
304 m_buttons[n]->Show(show);
305}
306
307// ----------------------------------------------------------------------------
308// methods forwarded to the static box
309// ----------------------------------------------------------------------------
310
311bool wxRadioBox::Enable(bool enable)
312{
528a5fe4
VZ
313 if ( !wxStaticBox::Enable(enable) )
314 return FALSE;
315
316 // also enable/disable the buttons
317 size_t count = m_buttons.GetCount();
318 for ( size_t n = 0; n < count; n++ )
319 {
320 Enable(n, enable);
321 }
322
323 return TRUE;
1e6feb95
VZ
324}
325
326bool wxRadioBox::Show(bool show)
327{
528a5fe4
VZ
328 if ( !wxStaticBox::Show(show) )
329 return FALSE;
330
331 // also show/hide the buttons
332 size_t count = m_buttons.GetCount();
333 for ( size_t n = 0; n < count; n++ )
334 {
335 Show(n, show);
336 }
337
338 return TRUE;
1e6feb95
VZ
339}
340
341wxString wxRadioBox::GetLabel() const
342{
343 return wxStaticBox::GetLabel();
344}
345
346void wxRadioBox::SetLabel(const wxString& label)
347{
348 wxStaticBox::SetLabel(label);
349}
350
d4e5272b
JS
351#if wxUSE_TOOLTIPS
352void wxRadioBox::DoSetToolTip(wxToolTip *tooltip)
353{
354 wxControl::DoSetToolTip(tooltip);
355
356 // Also set them for all Radio Buttons
357 size_t count = m_buttons.GetCount();
358 for ( size_t n = 0; n < count; n++ )
359 {
360 if (tooltip)
361 m_buttons[n]->SetToolTip(tooltip->GetTip());
362 else
363 m_buttons[n]->SetToolTip(NULL);
364 }
365}
366#endif // wxUSE_TOOLTIPS
367
1e6feb95
VZ
368// ----------------------------------------------------------------------------
369// buttons positioning
370// ----------------------------------------------------------------------------
371
372wxSize wxRadioBox::GetMaxButtonSize() const
373{
374 int widthMax, heightMax, width, height;
375 widthMax = heightMax = 0;
376
377 int count = GetCount();
378 for ( int n = 0; n < count; n++ )
379 {
380 m_buttons[n]->GetBestSize(&width, &height);
381
382 if ( width > widthMax )
383 widthMax = width;
384 if ( height > heightMax )
385 heightMax = height;
386 }
387
388 return wxSize(widthMax + BUTTON_BORDER_X, heightMax + BUTTON_BORDER_Y);
389}
390
391wxSize wxRadioBox::DoGetBestClientSize() const
392{
393 wxSize sizeBtn = GetMaxButtonSize();
394
395 sizeBtn.x *= m_numCols;
396 sizeBtn.y *= m_numRows;
397
398 // add a border around all buttons
399 sizeBtn.x += 2*BOX_BORDER_X;
400 sizeBtn.y += 2*BOX_BORDER_Y;
401
402 // account for the area taken by static box
403 wxRect rect = GetBorderGeometry();
404 sizeBtn.x += rect.x + rect.width;
405 sizeBtn.y += rect.y + rect.height;
406
407 return sizeBtn;
408}
409
410void wxRadioBox::DoMoveWindow(int x0, int y0, int width, int height)
411{
412 wxStaticBox::DoMoveWindow(x0, y0, width, height);
413
414 wxSize sizeBtn = GetMaxButtonSize();
415 wxPoint ptOrigin = GetBoxAreaOrigin();
e3f3984b 416 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
1e6feb95 417
e3f3984b
VS
418 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
419 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
1e6feb95
VZ
420
421 int x = x0,
422 y = y0;
423
424 int count = GetCount();
425 for ( int n = 0; n < count; n++ )
426 {
427 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
428
429 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
430 {
431 // from top to bottom
432 if ( (n + 1) % m_numRows )
433 {
434 // continue in this column
435 y += sizeBtn.y;
436 }
437 else
438 {
439 // start a new column
440 x += sizeBtn.x;
441 y = y0;
442 }
443 }
444 else // wxRA_LEFTTORIGHT: mirror the code above
445 {
446 // from left to right
447 if ( (n + 1) % m_numCols )
448 {
449 // continue in this row
450 x += sizeBtn.x;
451 }
452 else
453 {
454 // start a new row
455 y += sizeBtn.y;
456 x = x0;
457 }
458 }
459 }
460}
461
462// ----------------------------------------------------------------------------
463// keyboard navigation
464// ----------------------------------------------------------------------------
465
466bool wxRadioBox::OnKeyDown(wxKeyEvent& event)
467{
468 wxDirection dir;
469 switch ( event.GetKeyCode() )
470 {
471 case WXK_UP:
472 dir = wxUP;
473 break;
474
475 case WXK_LEFT:
476 dir = wxLEFT;
477 break;
478
479 case WXK_DOWN:
480 dir = wxDOWN;
481 break;
482
483 case WXK_RIGHT:
484 dir = wxRIGHT;
485 break;
486
487 default:
488 return FALSE;
489 }
490
491 int selOld = GetSelection();
492 int selNew = GetNextItem(selOld, dir, GetWindowStyle());
493 if ( selNew != selOld )
494 {
495 SetSelection(selNew);
496
497 // emulate the button click
498 SendRadioEvent();
499 }
500
501 return TRUE;
502}
503
504#endif // wxUSE_RADIOBOX
505