reverted Julians changes to the pragmas
[wxWidgets.git] / src / univ / radiobox.cpp
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$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "univradiobox.h"
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
48 static const int BUTTON_BORDER_X = 2;
49 static const int BUTTON_BORDER_Y = 4;
50
51 static const int BOX_BORDER_X = 2;
52 static const int BOX_BORDER_Y = 2;
53
54 // ----------------------------------------------------------------------------
55 // wxRadioBox event handler
56 // ----------------------------------------------------------------------------
57
58 class wxRadioHookHandler : public wxEvtHandler
59 {
60 public:
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
82 private:
83 wxRadioBox *m_radio;
84 };
85
86 // ============================================================================
87 // implementation
88 // ============================================================================
89
90 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
91
92 // ----------------------------------------------------------------------------
93 // wxRadioBox creation
94 // ----------------------------------------------------------------------------
95
96 void wxRadioBox::Init()
97 {
98 m_selection = -1;
99 m_majorDim = 0;
100 }
101
102 bool 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
160 wxRadioBox::~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
179 void 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
199 void 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
225 void 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
240 int wxRadioBox::GetSelection() const
241 {
242 return m_selection;
243 }
244
245 void 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
257 void 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
271 wxString 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
279 void 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
286 void 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
293 void 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
304 bool wxRadioBox::Enable(bool enable)
305 {
306 return wxStaticBox::Enable(enable);
307 }
308
309 bool wxRadioBox::Show(bool show)
310 {
311 return wxStaticBox::Show(show);
312 }
313
314 wxString wxRadioBox::GetLabel() const
315 {
316 return wxStaticBox::GetLabel();
317 }
318
319 void wxRadioBox::SetLabel(const wxString& label)
320 {
321 wxStaticBox::SetLabel(label);
322 }
323
324 // ----------------------------------------------------------------------------
325 // buttons positioning
326 // ----------------------------------------------------------------------------
327
328 wxSize wxRadioBox::GetMaxButtonSize() const
329 {
330 int widthMax, heightMax, width, height;
331 widthMax = heightMax = 0;
332
333 int count = GetCount();
334 for ( int n = 0; n < count; n++ )
335 {
336 m_buttons[n]->GetBestSize(&width, &height);
337
338 if ( width > widthMax )
339 widthMax = width;
340 if ( height > heightMax )
341 heightMax = height;
342 }
343
344 return wxSize(widthMax + BUTTON_BORDER_X, heightMax + BUTTON_BORDER_Y);
345 }
346
347 wxSize wxRadioBox::DoGetBestClientSize() const
348 {
349 wxSize sizeBtn = GetMaxButtonSize();
350
351 sizeBtn.x *= m_numCols;
352 sizeBtn.y *= m_numRows;
353
354 // add a border around all buttons
355 sizeBtn.x += 2*BOX_BORDER_X;
356 sizeBtn.y += 2*BOX_BORDER_Y;
357
358 // account for the area taken by static box
359 wxRect rect = GetBorderGeometry();
360 sizeBtn.x += rect.x + rect.width;
361 sizeBtn.y += rect.y + rect.height;
362
363 return sizeBtn;
364 }
365
366 void wxRadioBox::DoMoveWindow(int x0, int y0, int width, int height)
367 {
368 wxStaticBox::DoMoveWindow(x0, y0, width, height);
369
370 wxSize sizeBtn = GetMaxButtonSize();
371 wxPoint ptOrigin = GetBoxAreaOrigin();
372
373 x0 += ptOrigin.x + BOX_BORDER_X;
374 y0 += ptOrigin.y + BOX_BORDER_Y;
375
376 int x = x0,
377 y = y0;
378
379 int count = GetCount();
380 for ( int n = 0; n < count; n++ )
381 {
382 m_buttons[n]->SetSize(x, y, sizeBtn.x, sizeBtn.y);
383
384 if ( GetWindowStyle() & wxRA_TOPTOBOTTOM )
385 {
386 // from top to bottom
387 if ( (n + 1) % m_numRows )
388 {
389 // continue in this column
390 y += sizeBtn.y;
391 }
392 else
393 {
394 // start a new column
395 x += sizeBtn.x;
396 y = y0;
397 }
398 }
399 else // wxRA_LEFTTORIGHT: mirror the code above
400 {
401 // from left to right
402 if ( (n + 1) % m_numCols )
403 {
404 // continue in this row
405 x += sizeBtn.x;
406 }
407 else
408 {
409 // start a new row
410 y += sizeBtn.y;
411 x = x0;
412 }
413 }
414 }
415 }
416
417 // ----------------------------------------------------------------------------
418 // keyboard navigation
419 // ----------------------------------------------------------------------------
420
421 bool wxRadioBox::OnKeyDown(wxKeyEvent& event)
422 {
423 wxDirection dir;
424 switch ( event.GetKeyCode() )
425 {
426 case WXK_UP:
427 dir = wxUP;
428 break;
429
430 case WXK_LEFT:
431 dir = wxLEFT;
432 break;
433
434 case WXK_DOWN:
435 dir = wxDOWN;
436 break;
437
438 case WXK_RIGHT:
439 dir = wxRIGHT;
440 break;
441
442 default:
443 return FALSE;
444 }
445
446 int selOld = GetSelection();
447 int selNew = GetNextItem(selOld, dir, GetWindowStyle());
448 if ( selNew != selOld )
449 {
450 SetSelection(selNew);
451
452 // emulate the button click
453 SendRadioEvent();
454 }
455
456 return TRUE;
457 }
458
459 #endif // wxUSE_RADIOBOX
460