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