going private for m_peer to give a foundation for better encapsulation
[wxWidgets.git] / src / osx / radiobox_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/radiobox.cpp
3 // Purpose: wxRadioBox
4 // Author: Stefan Csomor
5 // Modified by: JS Lair (99/11/15) first implementation
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_RADIOBOX
15
16 #include "wx/radiobox.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/radiobut.h"
20 #include "wx/arrstr.h"
21 #endif
22
23 #include "wx/osx/private.h"
24
25 // regarding layout: note that there are differences in inter-control
26 // spacing between InterfaceBuild and the Human Interface Guidelines, we stick
27 // to the latter, as those are also used eg in the System Preferences Dialogs
28
29 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
30
31
32 BEGIN_EVENT_TABLE(wxRadioBox, wxControl)
33 EVT_RADIOBUTTON( wxID_ANY , wxRadioBox::OnRadioButton )
34 END_EVENT_TABLE()
35
36
37 void wxRadioBox::OnRadioButton( wxCommandEvent &outer )
38 {
39 if ( outer.IsChecked() )
40 {
41 wxCommandEvent event( wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId );
42 int i = GetSelection() ;
43 event.SetInt(i);
44 event.SetString(GetString(i));
45 event.SetEventObject( this );
46 ProcessCommand(event);
47 }
48 }
49
50 wxRadioBox::wxRadioBox()
51 {
52 m_noItems = 0;
53 m_noRowsOrCols = 0;
54 m_radioButtonCycle = NULL;
55 }
56
57 wxRadioBox::~wxRadioBox()
58 {
59 SendDestroyEvent();
60
61 wxRadioButton *next, *current;
62
63 current = m_radioButtonCycle->NextInCycle();
64 if (current != NULL)
65 {
66 while (current != m_radioButtonCycle)
67 {
68 next = current->NextInCycle();
69 delete current;
70
71 current = next;
72 }
73
74 delete current;
75 }
76 }
77
78 // Create the radiobox for two-step construction
79
80 bool wxRadioBox::Create( wxWindow *parent,
81 wxWindowID id, const wxString& label,
82 const wxPoint& pos, const wxSize& size,
83 const wxArrayString& choices,
84 int majorDim, long style,
85 const wxValidator& val, const wxString& name )
86 {
87 wxCArrayString chs(choices);
88
89 return Create(
90 parent, id, label, pos, size, chs.GetCount(),
91 chs.GetStrings(), majorDim, style, val, name);
92 }
93
94 bool wxRadioBox::Create( wxWindow *parent,
95 wxWindowID id, const wxString& label,
96 const wxPoint& pos, const wxSize& size,
97 int n, const wxString choices[],
98 int majorDim, long style,
99 const wxValidator& val, const wxString& name )
100 {
101 m_macIsUserPane = false ;
102
103 if ( !wxControl::Create( parent, id, pos, size, style, val, name ) )
104 return false;
105
106 int i;
107
108 m_noItems = (unsigned int)n;
109 m_noRowsOrCols = majorDim;
110 m_radioButtonCycle = NULL;
111
112 SetMajorDim( majorDim == 0 ? n : majorDim, style );
113
114 m_labelOrig = m_label = label;
115
116 SetPeer(wxWidgetImpl::CreateGroupBox( this, parent, id, label, pos, size, style, GetExtraStyle() ));
117
118 for (i = 0; i < n; i++)
119 {
120 wxRadioButton *radBtn = new wxRadioButton(
121 this,
122 wxID_ANY,
123 GetLabelText(choices[i]),
124 wxPoint( 5, 20 * i + 10 ),
125 wxDefaultSize,
126 i == 0 ? wxRB_GROUP : 0 );
127
128 if ( i == 0 )
129 m_radioButtonCycle = radBtn;
130 // m_radioButtonCycle = radBtn->AddInCycle( m_radioButtonCycle );
131 }
132
133 SetSelection( 0 );
134 MacPostControlCreate( pos, size );
135
136 return true;
137 }
138
139 // Enables or disables the entire radiobox
140 //
141 bool wxRadioBox::Enable(bool enable)
142 {
143 wxRadioButton *current;
144
145 if (!wxControl::Enable( enable ))
146 return false;
147
148 current = m_radioButtonCycle;
149 for (unsigned int i = 0; i < m_noItems; i++)
150 {
151 current->Enable( enable );
152 current = current->NextInCycle();
153 }
154
155 return true;
156 }
157
158 // Enables or disables an given button
159 //
160 bool wxRadioBox::Enable(unsigned int item, bool enable)
161 {
162 if (!IsValid( item ))
163 return false;
164
165 unsigned int i = 0;
166 wxRadioButton *current = m_radioButtonCycle;
167 while (i != item)
168 {
169 i++;
170 current = current->NextInCycle();
171 }
172
173 return current->Enable( enable );
174 }
175
176 bool wxRadioBox::IsItemEnabled(unsigned int item) const
177 {
178 if (!IsValid( item ))
179 return false;
180
181 unsigned int i = 0;
182 wxRadioButton *current = m_radioButtonCycle;
183 while (i != item)
184 {
185 i++;
186 current = current->NextInCycle();
187 }
188
189 return current->IsEnabled();
190 }
191
192 // Returns the radiobox label
193 //
194 wxString wxRadioBox::GetLabel() const
195 {
196 return wxControl::GetLabel();
197 }
198
199 // Returns the label for the given button
200 //
201 wxString wxRadioBox::GetString(unsigned int item) const
202 {
203 wxRadioButton *current;
204
205 if (!IsValid( item ))
206 return wxEmptyString;
207
208 unsigned int i = 0;
209 current = m_radioButtonCycle;
210 while (i != item)
211 {
212 i++;
213 current = current->NextInCycle();
214 }
215
216 return current->GetLabel();
217 }
218
219 // Returns the zero-based position of the selected button
220 //
221 int wxRadioBox::GetSelection() const
222 {
223 int i;
224 wxRadioButton *current;
225
226 i = 0;
227 current = m_radioButtonCycle;
228 while (!current->GetValue())
229 {
230 i++;
231 current = current->NextInCycle();
232 }
233
234 return i;
235 }
236
237 // Sets the radiobox label
238 //
239 void wxRadioBox::SetLabel(const wxString& label)
240 {
241 return wxControl::SetLabel( label );
242 }
243
244 // Sets the label of a given button
245 //
246 void wxRadioBox::SetString(unsigned int item,const wxString& label)
247 {
248 if (!IsValid( item ))
249 return;
250
251 unsigned int i = 0;
252 wxRadioButton *current = m_radioButtonCycle;
253 while (i != item)
254 {
255 i++;
256 current = current->NextInCycle();
257 }
258
259 return current->SetLabel( label );
260 }
261
262 // Sets a button by passing the desired position. This does not cause
263 // wxEVT_COMMAND_RADIOBOX_SELECTED event to get emitted
264 //
265 void wxRadioBox::SetSelection(int item)
266 {
267 int i;
268 wxRadioButton *current;
269
270 if (!IsValid( item ))
271 return;
272
273 i = 0;
274 current = m_radioButtonCycle;
275 while (i != item)
276 {
277 i++;
278 current = current->NextInCycle();
279 }
280
281 current->SetValue( true );
282 }
283
284 // Shows or hides the entire radiobox
285 //
286 bool wxRadioBox::Show(bool show)
287 {
288 wxRadioButton *current;
289
290 current = m_radioButtonCycle;
291 for (unsigned int i=0; i<m_noItems; i++)
292 {
293 current->Show( show );
294 current = current->NextInCycle();
295 }
296
297 wxControl::Show( show );
298
299 return true;
300 }
301
302 // Shows or hides the given button
303 //
304 bool wxRadioBox::Show(unsigned int item, bool show)
305 {
306 if (!IsValid( item ))
307 return false;
308
309 unsigned int i = 0;
310 wxRadioButton *current = m_radioButtonCycle;
311 while (i != item)
312 {
313 i++;
314 current = current->NextInCycle();
315 }
316
317 return current->Show( show );
318 }
319
320 bool wxRadioBox::IsItemShown(unsigned int item) const
321 {
322 if (!IsValid( item ))
323 return false;
324
325 unsigned int i = 0;
326 wxRadioButton *current = m_radioButtonCycle;
327 while (i != item)
328 {
329 i++;
330 current = current->NextInCycle();
331 }
332
333 return current->IsShown();
334 }
335
336
337 // Simulates the effect of the user issuing a command to the item
338 //
339 void wxRadioBox::Command( wxCommandEvent& event )
340 {
341 SetSelection( event.GetInt() );
342 ProcessCommand( event );
343 }
344
345 // Sets the selected button to receive keyboard input
346 //
347 void wxRadioBox::SetFocus()
348 {
349 wxRadioButton *current;
350
351 current = m_radioButtonCycle;
352 while (!current->GetValue())
353 {
354 current = current->NextInCycle();
355 }
356
357 current->SetFocus();
358 }
359
360 // Simulates the effect of the user issuing a command to the item
361 //
362 #if wxOSX_USE_CARBON
363 #define RADIO_SIZE 20
364 #else
365 // Cocoa has an additional border are of about 3 pixels
366 #define RADIO_SIZE 23
367 #endif
368
369 void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
370 {
371 int i;
372 wxRadioButton *current;
373
374 // define the position
375
376 int x_current, y_current;
377 int x_offset, y_offset;
378 int widthOld, heightOld;
379
380 GetSize( &widthOld, &heightOld );
381 GetPosition( &x_current, &y_current );
382
383 x_offset = x;
384 y_offset = y;
385 if (!(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
386 {
387 if (x == wxDefaultCoord)
388 x_offset = x_current;
389 if (y == wxDefaultCoord)
390 y_offset = y_current;
391 }
392
393 // define size
394 int charWidth, charHeight;
395 int maxWidth, maxHeight;
396 int eachWidth[128], eachHeight[128];
397 int totWidth, totHeight;
398
399 GetTextExtent(
400 wxT("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
401 &charWidth, &charHeight );
402
403 charWidth /= 52;
404
405 maxWidth = -1;
406 maxHeight = -1;
407 wxSize bestSizeRadio ;
408 if ( m_radioButtonCycle )
409 bestSizeRadio = m_radioButtonCycle->GetBestSize();
410
411 for (unsigned int i = 0 ; i < m_noItems; i++)
412 {
413 GetTextExtent(GetString(i), &eachWidth[i], &eachHeight[i] );
414 eachWidth[i] = eachWidth[i] + RADIO_SIZE;
415 eachHeight[i] = wxMax( eachHeight[i], bestSizeRadio.y );
416
417 if (maxWidth < eachWidth[i])
418 maxWidth = eachWidth[i];
419 if (maxHeight < eachHeight[i])
420 maxHeight = eachHeight[i];
421 }
422
423 // according to HIG (official space - 3 Pixels Diff between Frame and Layout size)
424 int space = 3;
425 if ( GetWindowVariant() == wxWINDOW_VARIANT_MINI )
426 space = 2;
427
428 totHeight = GetRowCount() * maxHeight + (GetRowCount() - 1) * space;
429 totWidth = GetColumnCount() * (maxWidth + charWidth);
430
431 wxSize sz = DoGetSizeFromClientSize( wxSize( totWidth, totHeight ) ) ;
432
433 // change the width / height only when specified
434 if ( width == wxDefaultCoord )
435 {
436 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
437 width = sz.x;
438 else
439 width = widthOld;
440 }
441
442 if ( height == wxDefaultCoord )
443 {
444 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
445 height = sz.y;
446 else
447 height = heightOld;
448 }
449
450 wxControl::DoSetSize( x_offset, y_offset, width, height, wxSIZE_AUTO );
451
452 // arrange radio buttons
453 int x_start, y_start;
454
455 x_start = ( width - sz.x ) / 2;
456 y_start = ( height - sz.y ) / 2;
457
458 x_offset = x_start;
459 y_offset = y_start;
460
461 current = m_radioButtonCycle;
462 for (i = 0 ; i < (int)m_noItems; i++)
463 {
464 // not to do for the zero button!
465 if ((i > 0) && ((i % GetMajorDim()) == 0))
466 {
467 if (m_windowStyle & wxRA_SPECIFY_ROWS)
468 {
469 x_offset += maxWidth + charWidth;
470 y_offset = y_start;
471 }
472 else
473 {
474 x_offset = x_start;
475 y_offset += maxHeight + space;
476 }
477 }
478
479 current->SetSize( x_offset, y_offset, eachWidth[i], eachHeight[i] );
480 current = current->NextInCycle();
481
482 if (m_windowStyle & wxRA_SPECIFY_ROWS)
483 y_offset += maxHeight + space;
484 else
485 x_offset += maxWidth + charWidth;
486 }
487 }
488
489 wxSize wxRadioBox::DoGetBestSize() const
490 {
491 int charWidth, charHeight;
492 int maxWidth, maxHeight;
493 int eachWidth, eachHeight;
494 int totWidth, totHeight;
495
496 wxFont font = GetFont(); // GetParent()->GetFont()
497 GetTextExtent(
498 wxT("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
499 &charWidth, &charHeight, NULL, NULL, &font );
500
501 charWidth /= 52;
502
503 maxWidth = -1;
504 maxHeight = -1;
505
506 wxSize bestSizeRadio ;
507 if ( m_radioButtonCycle )
508 bestSizeRadio = m_radioButtonCycle->GetBestSize();
509
510 for (unsigned int i = 0 ; i < m_noItems; i++)
511 {
512 GetTextExtent(GetString(i), &eachWidth, &eachHeight, NULL, NULL, &font );
513 eachWidth = (eachWidth + RADIO_SIZE);
514 eachHeight = wxMax(eachHeight, bestSizeRadio.y );
515 if (maxWidth < eachWidth)
516 maxWidth = eachWidth;
517 if (maxHeight < eachHeight)
518 maxHeight = eachHeight;
519 }
520
521 // according to HIG (official space - 3 Pixels Diff between Frame and Layout size)
522 int space = 3;
523 if ( GetWindowVariant() == wxWINDOW_VARIANT_MINI )
524 space = 2;
525
526 totHeight = GetRowCount() * maxHeight + (GetRowCount() - 1) * space;
527 totWidth = GetColumnCount() * (maxWidth + charWidth);
528
529 wxSize sz = DoGetSizeFromClientSize( wxSize( totWidth, totHeight ) );
530 totWidth = sz.x;
531 totHeight = sz.y;
532
533 // optimum size is an additional 5 pt border to all sides
534 totWidth += 10;
535 totHeight += 10;
536
537 // handle radio box title as well
538 GetTextExtent( GetLabel(), &eachWidth, NULL );
539 eachWidth = (int)(eachWidth + RADIO_SIZE) + 3 * charWidth;
540 if (totWidth < eachWidth)
541 totWidth = eachWidth;
542
543 return wxSize( totWidth, totHeight );
544 }
545
546 bool wxRadioBox::SetFont(const wxFont& font)
547 {
548 bool retval = wxWindowBase::SetFont( font );
549
550 // dont' update the native control, it has its own small font
551
552 // should we iterate over the children ?
553
554 return retval;
555 }
556
557 #endif // wxUSE_RADIOBOX