Document domain parameter of wxTranslations::GetTranslatedString().
[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 // Copyright:   (c) 2003 David Elliott
8 //              (c) 2007 Software 2000 Ltd.
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/app.h"
20     #include "wx/arrstr.h"
21 #endif //WX_PRECOMP
22
23 #include "wx/cocoa/string.h"
24 #include "wx/cocoa/autorelease.h"
25
26 #import <Foundation/NSArray.h>
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
36 void wxRadioBox::AssociateNSBox(WX_NSBox cocoaObjcClass)
37 {
38     NSMatrix *radioBox = [(WX_NSBox)cocoaObjcClass contentView];
39     // Associate the NSMatrix (the NSBox's contentView) with the wxCocoaNSControl MI base class.
40     AssociateNSControl(radioBox);
41     // Set the target/action.. we don't really need to unset these
42     [radioBox setTarget:wxCocoaNSControl::sm_cocoaTarget];
43     [radioBox setAction:@selector(wxNSControlAction:)];
44 }
45
46 void wxRadioBox::DisassociateNSBox(WX_NSBox cocoaObjcClass)
47 {
48     DisassociateNSControl([(WX_NSBox)cocoaObjcClass contentView]);
49 }
50
51 WX_IMPLEMENT_COCOA_OWNER(wxRadioBox,NSBox,NSView,NSView)
52
53 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
54             const wxString& title,
55             const wxPoint& pos,
56             const wxSize& size,
57             const wxArrayString& choices,
58             int majorDim,
59             long style, const wxValidator& validator,
60             const wxString& name)
61 {
62     wxCArrayString chs(choices);
63
64     return Create(parent, winid, title, pos, size, chs.GetCount(),
65                   chs.GetStrings(), majorDim, style, validator, name);
66 }
67
68 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
69             const wxString& title,
70             const wxPoint& pos,
71             const wxSize& size,
72             int n, const wxString choices[],
73             int majorDim,
74             long style, const wxValidator& validator,
75             const wxString& name)
76 {
77     // We autorelease heavily so we want our own pool
78     wxAutoNSAutoreleasePool pool;
79
80     if(!CreateControl(parent,winid,pos,size,style,validator,name))
81         return false;
82
83     majorDim = majorDim == 0 ? n : majorDim;
84     // TODO: Don't forget to call SetMajorDim
85     // We can't yet as we can't implement GetCount() until after
86     // we make the NSMatrix.
87     int minorDim = (n + majorDim - 1) / majorDim;
88
89
90     // Create a prototype cell for use with the NSMatrix build
91     NSCell *currCell = [[NSButtonCell alloc] initTextCell:@""];
92     [(NSButtonCell*)currCell setButtonType:NSRadioButton];
93
94     // Build up an array of all cells plus any extra empty cells
95     NSMutableArray *allCells = [NSMutableArray arrayWithCapacity:n];
96     for(int i=0; i<n; ++i)
97     {
98         CocoaSetLabelForObject(choices[i], currCell);
99         [allCells addObject: currCell];
100         [currCell release];
101         // NOTE: We can still safely message currCell as the array has retained it.
102         currCell = [currCell copy];
103     }
104     [currCell release];
105
106     // NOTE: Although an image cell with no image is documented to return NSZeroSize from
107     // the cellSize method, the documentation is WRONG.  It will actually return a huge size
108     // (thousands) which makes every cell in the matrix that big. Not good.
109     // Be safe and initialize a text cell with an empty string.  That always works.
110     currCell = [[NSCell alloc] initTextCell:@""];
111     [currCell setEnabled:NO]; // Don't allow user to select this cell
112     for(int i=n; i < majorDim * minorDim; ++i)
113     {
114         [allCells addObject: currCell];
115         // NOTE: Use the same instance.. this should work and save some heap allocations.
116 #if 0
117         [currCell release];
118         currCell = [currCell copy];
119 #endif
120     }
121     [currCell release];
122     currCell = NULL;
123
124     // Although the documentation on addColumnWithCells:/addRowWithCells: explicitly
125     // states that it will determine the initial dimension upon the first call if
126     // the initial size is 0x0 it LIES.  It will fail an assertion in the code
127     // if you use the simpler initWithFrame: initializer.
128     // Therefore, we specify the major dimension and leave the minor dimension as 0
129     // so that we can add the rows/columns without failing the assertion.
130     NSMatrix* radioBox = [[NSMatrix alloc]
131                 initWithFrame:NSZeroRect
132                 mode:NSRadioModeMatrix
133                 cellClass:nil
134                 numberOfRows:style&wxRA_SPECIFY_COLS?0:majorDim
135                 numberOfColumns:style&wxRA_SPECIFY_COLS?majorDim:0
136         ];
137
138     SEL addMajorWithCellsSelector;
139     // If column count is the major dimension then we add by row
140     if( style & wxRA_SPECIFY_COLS )
141         addMajorWithCellsSelector = @selector(addRowWithCells:);
142     // If row count is the major dimension then we add by column
143     else
144         addMajorWithCellsSelector = @selector(addColumnWithCells:);
145
146     for(int i=0; i<minorDim; ++i)
147     {
148         [radioBox
149             performSelector:addMajorWithCellsSelector
150             withObject:[allCells subarrayWithRange:NSMakeRange(i*majorDim, majorDim)]];
151     }
152
153     NSBox *theBox = [[NSBox alloc] initWithFrame:MakeDefaultNSRect(size)];
154
155     // Replace the box's content view with the NSMatrix we just created
156     // IMPORTANT: This must be done before calling SetNSBox.
157     [theBox setContentView:radioBox];
158     [radioBox release]; // The NSBox retains it for us.
159
160     SetNSBox(theBox);
161     [theBox release];
162
163
164     CocoaSetLabelForObject(title, GetNSBox());
165 //    [GetNSBox() setBorderType:NSLineBorder]; // why??
166
167     SetMajorDim(majorDim, style);
168
169     // Set the selection to the first item if we have any items.
170     // This is for parity with other wx ports which do the same thing.
171     if(n > 0)
172         SetSelection(0);
173
174     if(m_parent)
175         m_parent->CocoaAddChild(this);
176
177     // Do the sizer dance
178     [GetNSBox() sizeToFit];
179     SetInitialFrameRect(pos, size);
180
181     return true;
182 }
183
184 wxRadioBox::~wxRadioBox()
185 {
186     DisassociateNSBox(GetNSBox());
187 }
188
189 WX_NSMatrix wxRadioBox::GetNSMatrix() const
190 {
191     return (NSMatrix*)[(NSBox*)m_cocoaNSView contentView];
192 }
193
194     // selection
195 void wxRadioBox::SetSelection(int n)
196 {
197     int r = GetRowForIndex(n);
198     int c = GetColumnForIndex(n);
199     [GetNSMatrix() selectCellAtRow:r column:c];
200 }
201
202 int wxRadioBox::GetSelection() const
203 {
204     NSMatrix *radioBox = GetNSMatrix();
205     NSInteger r = [radioBox selectedRow];
206     NSInteger c = [radioBox selectedColumn];
207     if(m_windowStyle & wxRA_SPECIFY_COLS)
208         return r * GetMajorDim() + c;
209     else
210         return c * GetMajorDim() + r;
211 }
212
213     // string access
214 unsigned int wxRadioBox::GetCount() const
215 {
216     NSMatrix *radioBox = GetNSMatrix();
217     NSInteger rowCount, columnCount;
218     [radioBox getNumberOfRows:&rowCount columns:&columnCount];
219
220     // FIXME: This is wrong if padding cells were made
221     return rowCount * columnCount;
222 }
223
224 wxString wxRadioBox::GetString(unsigned int n) const
225 {
226     int r = GetRowForIndex(n);
227     int c = GetColumnForIndex(n);
228     // FIXME: Cocoa stores the mnemonic-stripped title.
229     return wxStringWithNSString([[GetNSMatrix() cellAtRow:r column:c] title]);
230 }
231
232 void wxRadioBox::SetString(unsigned int n, const wxString& label)
233 {
234     int r = GetRowForIndex(n);
235     int c = GetColumnForIndex(n);
236     CocoaSetLabelForObject(label, [GetNSMatrix() cellAtRow:r column:c]);
237 }
238
239     // change the individual radio button state
240 bool wxRadioBox::Enable(unsigned int n, bool enable)
241 {
242     int r = GetRowForIndex(n);
243     int c = GetColumnForIndex(n);
244     NSCell *cell = [GetNSMatrix() cellAtRow:r column:c];
245     if(cell == nil)
246         return false;
247     bool wasEnabled = [cell isEnabled];
248     [cell setEnabled:enable];
249     return (wasEnabled && !enable) || (!wasEnabled && enable);
250 }
251
252 bool wxRadioBox::Show(unsigned int n, bool show)
253 {
254     // TODO
255     // NOTE: Cocoa has no visible state for cells so we'd need to replace the
256     // cell with a dummy one to hide it or alternatively subclass NSButtonCell
257     // and add the behaviour.
258     return false;
259 }
260
261 wxSize wxRadioBox::DoGetBestSize() const
262 {
263     // The NSBox responds to sizeToFit by sending sizeToFit to its contentView
264     // which is the NSMatrix and does the right thing.
265     return wxControl::DoGetBestSize();
266 }
267
268 void wxRadioBox::CocoaTarget_action(void)
269 {
270     wxCommandEvent event(wxEVT_RADIOBOX, GetId());
271     InitCommandEvent(event);
272     event.SetInt(GetSelection()); // i.e. SetSelection.
273     Command(event);
274 }
275
276 #endif