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