1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/radiobox.mm
4 // Author: David Elliott
8 // Copyright: (c) 2003 David Elliott
9 // (c) 2007 Software 2000 Ltd.
10 // Licence: wxWidgets licence
11 /////////////////////////////////////////////////////////////////////////////
13 #include "wx/wxprec.h"
17 #include "wx/radiobox.h"
21 #include "wx/arrstr.h"
24 #include "wx/cocoa/string.h"
25 #include "wx/cocoa/autorelease.h"
27 #include "wx/cocoa/objc/NSView.h"
28 #import <AppKit/NSButton.h>
29 #import <AppKit/NSBox.h>
30 #import <AppKit/NSMatrix.h>
32 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
33 BEGIN_EVENT_TABLE(wxRadioBox, wxControl)
35 // WX_IMPLEMENT_COCOA_OWNER(wxRadioBox,NSTextField,NSControl,NSView)
37 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
38 const wxString& title,
41 const wxArrayString& choices,
43 long style, const wxValidator& validator,
46 wxCArrayString chs(choices);
48 return Create(parent, winid, title, pos, size, chs.GetCount(),
49 chs.GetStrings(), majorDim, style, validator, name);
52 bool wxRadioBox::Create(wxWindow *parent, wxWindowID winid,
53 const wxString& title,
56 int n, const wxString choices[],
58 long style, const wxValidator& validator,
61 // We autorelease heavily so we want our own pool
62 wxAutoNSAutoreleasePool pool;
64 if(!CreateControl(parent,winid,pos,size,style,validator,name))
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;
74 // Create a prototype cell for use with the NSMatrix build
75 NSCell *currCell = [[NSButtonCell alloc] initTextCell:@""];
76 [(NSButtonCell*)currCell setButtonType:NSRadioButton];
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)
82 [currCell setTitle: wxNSStringWithWxString(wxStripMenuCodes(choices[i], wxStrip_Mnemonics))];
83 [allCells addObject: currCell];
85 // NOTE: We can still safely message currCell as the array has retained it.
86 currCell = [currCell copy];
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)
98 [allCells addObject: currCell];
99 // NOTE: Use the same instance.. this should work and save some heap allocations.
102 currCell = [currCell copy];
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
118 numberOfRows:style&wxRA_SPECIFY_COLS?0:majorDim
119 numberOfColumns:style&wxRA_SPECIFY_COLS?majorDim:0
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
128 addMajorWithCellsSelector = @selector(addColumnWithCells:);
130 for(int i=0; i<minorDim; ++i)
133 performSelector:addMajorWithCellsSelector
134 withObject:[allCells subarrayWithRange:NSMakeRange(i*majorDim, majorDim)]];
137 //make and set up an NSBox (TODO: Just derive from wxStaticBox)
138 SetNSView([[NSBox alloc] initWithFrame:MakeDefaultNSRect(size)]);
139 [m_cocoaNSView release];
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.
145 [GetNSBox() setTitle:wxNSStringWithWxString(wxStripMenuCodes(title, wxStrip_Mnemonics))];
146 // [GetNSBox() setBorderType:NSLineBorder]; // why??
148 SetMajorDim(majorDim, style);
151 m_parent->CocoaAddChild(this);
153 // Do the sizer dance
154 [GetNSBox() sizeToFit];
155 SetInitialFrameRect(pos, size);
160 wxRadioBox::~wxRadioBox()
164 WX_NSMatrix wxRadioBox::GetNSMatrix() const
166 return (NSMatrix*)[(NSBox*)m_cocoaNSView contentView];
170 void wxRadioBox::SetSelection(int n)
172 int r = GetRowForIndex(n);
173 int c = GetColumnForIndex(n);
174 [GetNSMatrix() selectCellAtRow:r column:c];
177 int wxRadioBox::GetSelection() const
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;
185 return c * GetMajorDim() + r;
189 unsigned int wxRadioBox::GetCount() const
191 NSMatrix *radioBox = GetNSMatrix();
192 NSInteger rowCount, columnCount;
193 [radioBox getNumberOfRows:&rowCount columns:&columnCount];
195 // FIXME: This is wrong if padding cells were made
196 return rowCount * columnCount;
199 wxString wxRadioBox::GetString(unsigned int n) const
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]);
207 void wxRadioBox::SetString(unsigned int n, const wxString& label)
209 int r = GetRowForIndex(n);
210 int c = GetColumnForIndex(n);
211 [[GetNSMatrix() cellAtRow:r column:c] setTitle:wxNSStringWithWxString(wxStripMenuCodes(label, wxStrip_Mnemonics))];
214 // change the individual radio button state
215 bool wxRadioBox::Enable(unsigned int n, bool enable)
217 int r = GetRowForIndex(n);
218 int c = GetColumnForIndex(n);
219 NSCell *cell = [GetNSMatrix() cellAtRow:r column:c];
222 bool wasEnabled = [cell isEnabled];
223 [cell setEnabled:enable];
224 return (wasEnabled && !enable) || (!wasEnabled && enable);
227 bool wxRadioBox::Show(unsigned int n, bool show)
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.
236 wxSize wxRadioBox::DoGetBestSize() const
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();