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