Implement most of wxRadioBox's methods.
[wxWidgets.git] / src / cocoa / radiobox.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/radiobox.mm
3 // Purpose:     wxRadioBox
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/02/15
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 //              (c) 2007 Software 2000 Ltd.
10 // Licence:     wxWidgets licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #include "wx/wxprec.h"
14
15 #if wxUSE_RADIOBOX
16
17 #include "wx/radiobox.h"
18
19 #ifndef WX_PRECOMP
20     #include "wx/app.h"
21     #include "wx/arrstr.h"
22 #endif //WX_PRECOMP
23
24 #include "wx/cocoa/string.h"
25 #include "wx/cocoa/autorelease.h"
26
27 #include "wx/cocoa/objc/NSView.h"
28 #import <AppKit/NSButton.h>
29 #import <AppKit/NSBox.h>
30 #import <AppKit/NSMatrix.h>
31
32 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
33 BEGIN_EVENT_TABLE(wxRadioBox, wxControl)
34 END_EVENT_TABLE()
35 // WX_IMPLEMENT_COCOA_OWNER(wxRadioBox,NSTextField,NSControl,NSView)
36
37 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
38             const wxString& title,
39             const wxPoint& pos,
40             const wxSize& size,
41             const wxArrayString& choices,
42             int majorDim,
43             long style, const wxValidator& validator,
44             const wxString& name)
45 {
46     wxCArrayString chs(choices);
47
48     return Create(parent, winid, title, pos, size, chs.GetCount(),
49                   chs.GetStrings(), majorDim, style, validator, name);
50 }
51
52 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
53             const wxString& title,
54             const wxPoint& pos,
55             const wxSize& size,
56             int n, const wxString choices[],
57             int majorDim,
58             long style, const wxValidator& validator,
59             const wxString& name)
60 {
61     // We autorelease heavily so we want our own pool
62     wxAutoNSAutoreleasePool pool;
63
64     if(!CreateControl(parent,winid,pos,size,style,validator,name))
65         return false;
66
67     majorDim = majorDim == 0 ? n : majorDim;
68     // TODO: Don't forget to call SetMajorDim
69     // We can't yet as we can't implement GetCount() until after
70     // we make the NSMatrix.
71     int minorDim = (n + majorDim - 1) / majorDim;
72
73
74     // Create a prototype cell for use with the NSMatrix build
75     NSCell *currCell = [[NSButtonCell alloc] initTextCell:@""];
76     [(NSButtonCell*)currCell setButtonType:NSRadioButton];
77
78     // Build up an array of all cells plus any extra empty cells
79     NSMutableArray *allCells = [NSMutableArray arrayWithCapacity:n];
80     for(int i=0; i<n; ++i)
81     {
82         [currCell setTitle: wxNSStringWithWxString(wxStripMenuCodes(choices[i], wxStrip_Mnemonics))];
83         [allCells addObject: currCell];
84         [currCell release];
85         // NOTE: We can still safely message currCell as the array has retained it.
86         currCell = [currCell copy];
87     }
88     [currCell release];
89
90     // NOTE: Although an image cell with no image is documented to return NSZeroSize from
91     // the cellSize method, the documentation is WRONG.  It will actually return a huge size
92     // (thousands) which makes every cell in the matrix that big. Not good.
93     // Be safe and initialize a text cell with an empty string.  That always works.
94     currCell = [[NSCell alloc] initTextCell:@""];
95     [currCell setEnabled:NO]; // Don't allow user to select this cell
96     for(int i=n; i < majorDim * minorDim; ++i)
97     {
98         [allCells addObject: currCell];
99         // NOTE: Use the same instance.. this should work and save some heap allocations.
100 #if 0
101         [currCell release];
102         currCell = [currCell copy];
103 #endif
104     }
105     [currCell release];
106     currCell = NULL;
107
108     // Although the documentation on addColumnWithCells:/addRowWithCells: explicitly
109     // states that it will determine the initial dimension upon the first call if
110     // the initial size is 0x0 it LIES.  It will fail an assertion in the code
111     // if you use the simpler initWithFrame: initializer.
112     // Therefore, we specify the major dimension and leave the minor dimension as 0
113     // so that we can add the rows/columns without failing the assertion.
114     NSMatrix* radioBox = [[NSMatrix alloc]
115                 initWithFrame:NSZeroRect
116                 mode:NSRadioModeMatrix
117                 cellClass:nil
118                 numberOfRows:style&wxRA_SPECIFY_COLS?0:majorDim
119                 numberOfColumns:style&wxRA_SPECIFY_COLS?majorDim:0
120         ];
121
122     SEL addMajorWithCellsSelector;
123     // If column count is the major dimension then we add by row
124     if( style & wxRA_SPECIFY_COLS )
125         addMajorWithCellsSelector = @selector(addRowWithCells:);
126     // If row count is the major dimension then we add by column
127     else
128         addMajorWithCellsSelector = @selector(addColumnWithCells:);
129
130     for(int i=0; i<minorDim; ++i)
131     {
132         [radioBox
133             performSelector:addMajorWithCellsSelector
134             withObject:[allCells subarrayWithRange:NSMakeRange(i*majorDim, majorDim)]];
135     }
136
137     //make and set up an NSBox (TODO: Just derive from wxStaticBox)
138     SetNSView([[NSBox alloc] initWithFrame:MakeDefaultNSRect(size)]);
139     [m_cocoaNSView release];
140
141     // Replace the box's content view with the NSMatrix we just created
142     [GetNSBox() setContentView:radioBox];
143     [radioBox release]; // The NSBox retains it for us.
144
145     [GetNSBox() setTitle:wxNSStringWithWxString(wxStripMenuCodes(title, wxStrip_Mnemonics))];
146 //    [GetNSBox() setBorderType:NSLineBorder]; // why??
147
148     SetMajorDim(majorDim, style);
149
150     if(m_parent)
151         m_parent->CocoaAddChild(this);
152
153     // Do the sizer dance
154     [GetNSBox() sizeToFit];
155     SetInitialFrameRect(pos, size);
156
157     return true;
158 }
159
160 wxRadioBox::~wxRadioBox()
161 {
162 }
163
164 WX_NSMatrix wxRadioBox::GetNSMatrix() const
165 {
166     return (NSMatrix*)[(NSBox*)m_cocoaNSView contentView];
167 }
168
169     // selection
170 void wxRadioBox::SetSelection(int n)
171 {
172     int r = GetRowForIndex(n);
173     int c = GetColumnForIndex(n);
174     [GetNSMatrix() selectCellAtRow:r column:c];
175 }
176
177 int wxRadioBox::GetSelection() const
178 {
179     NSMatrix *radioBox = GetNSMatrix();
180     NSInteger r = [radioBox selectedRow];
181     NSInteger c = [radioBox selectedColumn];
182     if(m_windowStyle & wxRA_SPECIFY_COLS)
183         return r * GetMajorDim() + c;
184     else
185         return c * GetMajorDim() + r;
186 }
187
188     // string access
189 unsigned int wxRadioBox::GetCount() const
190 {
191     NSMatrix *radioBox = GetNSMatrix();
192     NSInteger rowCount, columnCount;
193     [radioBox getNumberOfRows:&rowCount columns:&columnCount];
194
195     // FIXME: This is wrong if padding cells were made
196     return rowCount * columnCount;
197 }
198
199 wxString wxRadioBox::GetString(unsigned int n) const
200 {
201     int r = GetRowForIndex(n);
202     int c = GetColumnForIndex(n);
203     // FIXME: Cocoa stores the mnemonic-stripped title.
204     return wxStringWithNSString([[GetNSMatrix() cellAtRow:r column:c] title]);
205 }
206
207 void wxRadioBox::SetString(unsigned int n, const wxString& label)
208 {
209     int r = GetRowForIndex(n);
210     int c = GetColumnForIndex(n);
211     [[GetNSMatrix() cellAtRow:r column:c] setTitle:wxNSStringWithWxString(wxStripMenuCodes(label, wxStrip_Mnemonics))];
212 }
213
214     // change the individual radio button state
215 bool wxRadioBox::Enable(unsigned int n, bool enable)
216 {
217     int r = GetRowForIndex(n);
218     int c = GetColumnForIndex(n);
219     NSCell *cell = [GetNSMatrix() cellAtRow:r column:c];
220     if(cell == nil)
221         return false;
222     bool wasEnabled = [cell isEnabled];
223     [cell setEnabled:enable];
224     return (wasEnabled && !enable) || (!wasEnabled && enable);
225 }
226
227 bool wxRadioBox::Show(unsigned int n, bool show)
228 {
229     // TODO
230     // NOTE: Cocoa has no visible state for cells so we'd need to replace the
231     // cell with a dummy one to hide it or alternatively subclass NSButtonCell
232     // and add the behavior.
233     return false;
234 }
235
236 wxSize wxRadioBox::DoGetBestSize() const
237 {
238     // The NSBox responds to sizeToFit by sending sizeToFit to its contentView
239     // which is the NSMatrix and does the right thing.
240     return wxControl::DoGetBestSize();
241 }
242
243 #endif