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