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