]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/univ/radiobox.cpp
Fix another crash when conversion fails in Unix PostScript code.
[wxWidgets.git] / src / univ / radiobox.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/univ/radiobox.cpp
3// Purpose: wxRadioBox implementation
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 11.09.00
7// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
25#if wxUSE_RADIOBOX
26
27#include "wx/radiobox.h"
28
29#ifndef WX_PRECOMP
30 #include "wx/dcclient.h"
31 #include "wx/radiobut.h"
32 #include "wx/validate.h"
33 #include "wx/arrstr.h"
34#endif
35
36#include "wx/tooltip.h"
37
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_RADIOBUTTON )
66 {
67 m_radio->OnRadioButton(event);
68 }
69 else if ( event.GetEventType() == wxEVT_KEY_DOWN )
70 {
71 if ( m_radio->OnKeyDown((wxKeyEvent &)event) )
72 {
73 return true;
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;
98}
99
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
110 (void)Create(parent, id, title, pos, size, chs.GetCount(),
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
127 return Create(parent, id, title, pos, size, chs.GetCount(),
128 chs.GetStrings(), majorDim, style, val, name);
129}
130
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,
140 const wxValidator& wxVALIDATOR_PARAM(val),
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_SPECIFY_COLS )
150 {
151 style |= wxRA_LEFTTORIGHT;
152 }
153 else if ( style & wxRA_SPECIFY_ROWS )
154 {
155 style |= wxRA_TOPTOBOTTOM;
156 }
157 else
158 {
159 wxFAIL_MSG( wxT("you must specify wxRA_XXX style!") );
160
161 // use default
162 style = wxRA_SPECIFY_COLS | wxRA_LEFTTORIGHT;
163 }
164 }
165
166 if ( !wxStaticBox::Create(parent, id, title, pos, size, style, name) )
167 return false;
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
176 SetMajorDim(majorDim == 0 ? n : majorDim, style);
177
178 if ( size == wxDefaultSize )
179 {
180 SetClientSize(DoGetBestClientSize());
181 }
182
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
188 // radiobox should already have selection so select at least one item
189 SetSelection(0);
190
191 return true;
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 unsigned int count = m_buttons.GetCount();
201 for ( unsigned int n = 0; n < count; n++ )
202 {
203 m_buttons[n]->PopEventHandler(true /* delete it */);
204
205 delete m_buttons[n];
206 }
207}
208
209// ----------------------------------------------------------------------------
210// wxRadioBox init
211// ----------------------------------------------------------------------------
212
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
224 wxRadioButton *btn = new wxRadioButton(parent, wxID_ANY, choices[n],
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), wxT("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
251 btn->SetValue(true);
252}
253
254int wxRadioBox::GetSelection() const
255{
256 return m_selection;
257}
258
259void wxRadioBox::SendRadioEvent()
260{
261 wxCHECK_RET( m_selection != -1, wxT("no active radio button") );
262
263 wxCommandEvent event(wxEVT_RADIOBOX, 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, wxT("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(unsigned int n) const
286{
287 wxCHECK_MSG( IsValid(n), wxEmptyString,
288 wxT("invalid index in wxRadioBox::GetString") );
289
290 return m_buttons[n]->GetLabel();
291}
292
293void wxRadioBox::SetString(unsigned int n, const wxString& label)
294{
295 wxCHECK_RET( IsValid(n), wxT("invalid index in wxRadioBox::SetString") );
296
297 m_buttons[n]->SetLabel(label);
298}
299
300bool wxRadioBox::Enable(unsigned int n, bool enable)
301{
302 wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxRadioBox::Enable") );
303
304 return m_buttons[n]->Enable(enable);
305}
306
307bool wxRadioBox::IsItemEnabled(unsigned int n) const
308{
309 wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxRadioBox::IsItemEnabled") );
310
311 return m_buttons[n]->IsEnabled();
312}
313
314bool wxRadioBox::Show(unsigned int n, bool show)
315{
316 wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxRadioBox::Show") );
317
318 return m_buttons[n]->Show(show);
319}
320
321bool wxRadioBox::IsItemShown(unsigned int n) const
322{
323 wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxRadioBox::IsItemShown") );
324
325 return m_buttons[n]->IsShown();
326}
327
328// ----------------------------------------------------------------------------
329// methods forwarded to the static box
330// ----------------------------------------------------------------------------
331
332bool wxRadioBox::Enable(bool enable)
333{
334 if ( !wxStaticBox::Enable(enable) )
335 return false;
336
337 // also enable/disable the buttons
338 const unsigned int count = m_buttons.GetCount();
339 for ( unsigned int n = 0; n < count; n++ )
340 {
341 Enable(n, enable);
342 }
343
344 return true;
345}
346
347bool wxRadioBox::Show(bool show)
348{
349 if ( !wxStaticBox::Show(show) )
350 return false;
351
352 // also show/hide the buttons
353 const unsigned int count = m_buttons.GetCount();
354 for ( unsigned int n = 0; n < count; n++ )
355 {
356 Show(n, show);
357 }
358
359 return true;
360}
361
362wxString wxRadioBox::GetLabel() const
363{
364 return wxStaticBox::GetLabel();
365}
366
367void wxRadioBox::SetLabel(const wxString& label)
368{
369 wxStaticBox::SetLabel(label);
370}
371
372#if wxUSE_TOOLTIPS
373void wxRadioBox::DoSetToolTip(wxToolTip *tooltip)
374{
375 wxControl::DoSetToolTip(tooltip);
376
377 // Also set them for all Radio Buttons
378 const unsigned int count = m_buttons.GetCount();
379 for ( unsigned int n = 0; n < count; n++ )
380 {
381 if (tooltip)
382 m_buttons[n]->SetToolTip(tooltip->GetTip());
383 else
384 m_buttons[n]->SetToolTip(NULL);
385 }
386}
387#endif // wxUSE_TOOLTIPS
388
389// ----------------------------------------------------------------------------
390// buttons positioning
391// ----------------------------------------------------------------------------
392
393wxSize wxRadioBox::GetMaxButtonSize() const
394{
395 int widthMax, heightMax, width = 0, height = 0;
396 widthMax = heightMax = 0;
397
398 const unsigned int count = GetCount();
399 for ( unsigned int n = 0; n < count; n++ )
400 {
401 m_buttons[n]->GetBestSize(&width, &height);
402
403 if ( width > widthMax )
404 widthMax = width;
405 if ( height > heightMax )
406 heightMax = height;
407 }
408
409 return wxSize(widthMax + BUTTON_BORDER_X, heightMax + BUTTON_BORDER_Y);
410}
411
412wxSize wxRadioBox::DoGetBestClientSize() const
413{
414 wxSize sizeBtn = GetMaxButtonSize();
415
416 sizeBtn.x *= GetColumnCount();
417 sizeBtn.y *= GetRowCount();
418
419 // add a border around all buttons
420 sizeBtn.x += 2*BOX_BORDER_X;
421 sizeBtn.y += 2*BOX_BORDER_Y;
422
423 // account for the area taken by static box
424 wxRect rect = GetBorderGeometry();
425 sizeBtn.x += rect.x + rect.width;
426 sizeBtn.y += rect.y + rect.height;
427
428 return sizeBtn;
429}
430
431void wxRadioBox::DoMoveWindow(int x0, int y0, int width, int height)
432{
433 wxStaticBox::DoMoveWindow(x0, y0, width, height);
434
435 wxSize sizeBtn = GetMaxButtonSize();
436 wxPoint ptOrigin = GetBoxAreaOrigin();
437 wxPoint clientOrigin = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
438
439 x0 += ptOrigin.x + BOX_BORDER_X - clientOrigin.x;
440 y0 += ptOrigin.y + BOX_BORDER_Y - clientOrigin.y;
441
442 int x = x0,
443 y = y0;
444
445 const unsigned int count = GetCount();
446 for ( unsigned int n = 0; n < count; n++ )
447 {
448 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
449
450 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
451 {
452 // from top to bottom
453 if ( (n + 1) % GetRowCount() )
454 {
455 // continue in this column
456 y += sizeBtn.y;
457 }
458 else
459 {
460 // start a new column
461 x += sizeBtn.x;
462 y = y0;
463 }
464 }
465 else // wxRA_LEFTTORIGHT: mirror the code above
466 {
467 // from left to right
468 if ( (n + 1) % GetColumnCount() )
469 {
470 // continue in this row
471 x += sizeBtn.x;
472 }
473 else
474 {
475 // start a new row
476 y += sizeBtn.y;
477 x = x0;
478 }
479 }
480 }
481}
482
483// ----------------------------------------------------------------------------
484// keyboard navigation
485// ----------------------------------------------------------------------------
486
487bool wxRadioBox::OnKeyDown(wxKeyEvent& event)
488{
489 wxDirection dir;
490 switch ( event.GetKeyCode() )
491 {
492 case WXK_UP:
493 dir = wxUP;
494 break;
495
496 case WXK_LEFT:
497 dir = wxLEFT;
498 break;
499
500 case WXK_DOWN:
501 dir = wxDOWN;
502 break;
503
504 case WXK_RIGHT:
505 dir = wxRIGHT;
506 break;
507
508 default:
509 return false;
510 }
511
512 int selOld = GetSelection();
513 int selNew = GetNextItem(selOld, dir, GetWindowStyle());
514 if ( selNew != selOld )
515 {
516 SetSelection(selNew);
517
518 // emulate the button click
519 SendRadioEvent();
520 }
521
522 return true;
523}
524
525#endif // wxUSE_RADIOBOX