]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/listbox.mm
50b5c7947292d66957773b42a53d7cf047b25620
[wxWidgets.git] / src / cocoa / listbox.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/listbox.mm
3 // Purpose: wxListBox
4 // Author: David Elliott
5 // Modified by:
6 // Created: 2003/03/18
7 // Id: $Id$
8 // Copyright: (c) 2003 David Elliott
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_LISTBOX
15
16 #include "wx/listbox.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/log.h"
20 #include "wx/app.h"
21 #endif //WX_PRECOMP
22
23 #include "wx/cocoa/string.h"
24 #include "wx/cocoa/autorelease.h"
25 #include "wx/cocoa/ObjcRef.h"
26 #include "wx/cocoa/private/scrollview.h"
27 #include "wx/cocoa/NSTableDataSource.h"
28
29 #import <Foundation/NSArray.h>
30 #import <Foundation/NSEnumerator.h>
31 #import <AppKit/NSTableView.h>
32 #import <AppKit/NSTableColumn.h>
33 #import <AppKit/NSScrollView.h>
34 #import <AppKit/NSCell.h>
35
36 // ============================================================================
37 // @class wxCocoaListBoxNSTableDataSource
38 // ============================================================================
39 // 2.8 hack: We can't add an i-var to wxListBox so we add one here
40 @interface wxCocoaListBoxNSTableDataSource : wxCocoaNSTableDataSource
41 {
42 BOOL m_needsUpdate;
43 }
44
45 @end
46 WX_DECLARE_GET_OBJC_CLASS(wxCocoaListBoxNSTableDataSource,wxCocoaNSTableDataSource)
47
48 @implementation wxCocoaListBoxNSTableDataSource
49 // No methods
50 @end
51 WX_IMPLEMENT_GET_OBJC_CLASS_WITH_UNIQUIFIED_SUPERCLASS(wxCocoaListBoxNSTableDataSource,wxCocoaNSTableDataSource)
52
53
54 // ============================================================================
55 // helper functions
56 // ============================================================================
57
58 static CGFloat _TableColumnMaxWidthForItems(NSTableColumn *tableColumn, NSArray *items)
59 {
60 wxAutoNSAutoreleasePool pool;
61
62 NSCell *dataCell = [[[tableColumn dataCell] copy] autorelease];
63 CGFloat width = 0.0f;
64 NSEnumerator *itemEnum = [items objectEnumerator];
65 NSString *item;
66 while( (item = [itemEnum nextObject]) != nil )
67 {
68 [dataCell setStringValue: item];
69 NSSize itemSize = [dataCell cellSize];
70 CGFloat itemWidth = itemSize.width;
71 if(itemWidth > width)
72 width = itemWidth;
73 }
74 return width;
75 }
76
77 static void _SetWidthOfTableColumnToFitItems(NSTableColumn *tableColumn, NSArray *items)
78 {
79 CGFloat width = _TableColumnMaxWidthForItems(tableColumn, items);
80 [tableColumn setWidth:width];
81 [tableColumn setMinWidth:width];
82 }
83
84 // ============================================================================
85 // class wxListBox
86 // ============================================================================
87
88 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
89 BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
90 EVT_IDLE(wxListBox::_WxCocoa_OnIdle)
91 END_EVENT_TABLE()
92 WX_IMPLEMENT_COCOA_OWNER(wxListBox,NSTableView,NSControl,NSView)
93
94 bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
95 const wxPoint& pos,
96 const wxSize& size,
97 const wxArrayString& choices,
98 long style,
99 const wxValidator& validator,
100 const wxString& name)
101 {
102 wxCArrayString chs(choices);
103
104 return Create(parent, winid, pos, size, chs.GetCount(), chs.GetStrings(),
105 style, validator, name);
106 }
107
108 bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
109 const wxPoint& pos,
110 const wxSize& size,
111 int n, const wxString choices[],
112 long style,
113 const wxValidator& validator,
114 const wxString& name)
115 {
116 /*
117 wxLB_SINGLE
118 Single-selection list.
119
120 wxLB_MULTIPLE
121 Multiple-selection list: the user can toggle multiple items on and off.
122
123 wxLB_EXTENDED
124 Extended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.
125
126 wxLB_HSCROLL
127 Create horizontal scrollbar if contents are too wide (Windows only).
128
129 wxLB_ALWAYS_SB
130 Always show a vertical scrollbar.
131
132 wxLB_NEEDED_SB
133 Only create a vertical scrollbar if needed.
134
135 wxLB_SORT
136 The listbox contents are sorted in alphabetical order.
137 */
138 wxAutoNSAutoreleasePool pool;
139 if(!CreateControl(parent,winid,pos,size,style,validator,name))
140 return false;
141
142 // Provide the data
143 m_cocoaItems = wxGCSafeRetain([NSMutableArray arrayWithCapacity:n]);
144 for(int i=0; i < n; i++)
145 {
146 [m_cocoaItems addObject: wxNSStringWithWxString(choices[i])];
147 }
148 // Remove everything
149 m_itemClientData.Clear();
150 // Initialize n elements to NULL
151 m_itemClientData.SetCount(n,NULL);
152
153 SetNSTableView([[NSTableView alloc] initWithFrame: MakeDefaultNSRect(size)]);
154 [m_cocoaNSView release];
155 [GetNSTableView() setHeaderView: nil];
156
157 // Set up the data source
158 m_cocoaDataSource = [[WX_GET_OBJC_CLASS(wxCocoaListBoxNSTableDataSource) alloc] init];
159 [GetNSTableView() setDataSource:m_cocoaDataSource];
160
161 // Add the single column
162 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier:nil];
163 [GetNSTableView() addTableColumn: tableColumn];
164 [tableColumn release];
165
166 [GetNSTableView() sizeToFit];
167 // Finish
168 if(m_parent)
169 m_parent->CocoaAddChild(this);
170 // NSTableView does WEIRD things with sizes. Wrapping it in an
171 // NSScrollView seems to be the only reasonable solution.
172 CocoaCreateNSScrollView();
173 SetInitialFrameRect(pos,size);
174
175 [m_wxCocoaScrollView->GetNSScrollView() setHasVerticalScroller:YES];
176 // Pre-10.3: Always show vertical scroller, never show horizontal scroller
177 // Post-10.3: Show scrollers dynamically (turn them both on, set auto-hide)
178 if([m_wxCocoaScrollView->GetNSScrollView() respondsToSelector:@selector(setAutohidesScrollers:)])
179 {
180 [m_wxCocoaScrollView->GetNSScrollView() setHasHorizontalScroller:YES];
181 [m_wxCocoaScrollView->GetNSScrollView() setAutohidesScrollers:YES];
182 }
183
184 // Set up extended/multiple selection flags
185 if ((style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE))
186 //diff is that mult requires shift down for multi selection
187 [GetNSTableView() setAllowsMultipleSelection:true];
188
189 [GetNSTableView() setAllowsColumnSelection:false];
190 _SetWidthOfTableColumnToFitItems(tableColumn, m_cocoaItems);
191 return true;
192 }
193
194 wxListBox::~wxListBox()
195 {
196 [GetNSTableView() setDataSource: nil];
197 [m_cocoaDataSource release];
198 wxGCSafeRelease(m_cocoaItems);
199 m_cocoaItems = nil;
200 DisassociateNSTableView(GetNSTableView());
201 }
202
203 bool wxListBox::_WxCocoa_GetNeedsUpdate()
204 {
205 return static_cast<wxCocoaListBoxNSTableDataSource*>(m_cocoaDataSource)->m_needsUpdate;
206 }
207
208 void wxListBox::_WxCocoa_SetNeedsUpdate(bool needsUpdate)
209 {
210 static_cast<wxCocoaListBoxNSTableDataSource*>(m_cocoaDataSource)->m_needsUpdate = needsUpdate;
211 }
212
213 void wxListBox::_WxCocoa_OnIdle(wxIdleEvent &event)
214 {
215 event.Skip();
216 if(_WxCocoa_GetNeedsUpdate())
217 {
218 _SetWidthOfTableColumnToFitItems([[GetNSTableView() tableColumns] objectAtIndex:0], m_cocoaItems);
219 [GetNSTableView() tile];
220 [GetNSTableView() reloadData];
221 _WxCocoa_SetNeedsUpdate(false);
222 }
223 }
224
225 int wxListBox::CocoaDataSource_numberOfRows()
226 {
227 return [m_cocoaItems count];
228 }
229
230 struct objc_object* wxListBox::CocoaDataSource_objectForTableColumn(
231 WX_NSTableColumn tableColumn, int rowIndex)
232 {
233 return [m_cocoaItems objectAtIndex:rowIndex];
234 }
235
236 // pure virtuals from wxListBoxBase
237 bool wxListBox::IsSelected(int n) const
238 {
239 return [GetNSTableView() isRowSelected: n];
240 }
241
242 void wxListBox::DoSetSelection(int n, bool select)
243 {
244 if(select)
245 [GetNSTableView() selectRow: n byExtendingSelection:NO];
246 else
247 [GetNSTableView() deselectRow: n];
248 }
249
250 int wxListBox::GetSelections(wxArrayInt& aSelections) const
251 {
252 aSelections.Clear();
253 NSEnumerator *enumerator = [GetNSTableView() selectedRowEnumerator];
254 while(NSNumber *num = [enumerator nextObject])
255 {
256 aSelections.Add([num intValue]);
257 }
258 return [GetNSTableView() numberOfSelectedRows];
259 }
260
261 int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
262 {
263 wxAutoNSAutoreleasePool pool;
264
265 const unsigned int numItems = items.GetCount();
266 for ( unsigned int i = 0; i < numItems; ++i, ++pos )
267 {
268 [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
269 atIndex: pos];
270 m_itemClientData.Insert(NULL, pos);
271 AssignNewItemClientData(pos, clientData, i, type);
272 }
273
274 _WxCocoa_SetNeedsUpdate(true);
275 return pos - 1;
276 }
277
278 void wxListBox::DoSetFirstItem(int n)
279 {
280 [m_cocoaItems exchangeObjectAtIndex:0 withObjectAtIndex:n];
281 void* pOld = m_itemClientData[n];
282 m_itemClientData[n] = m_itemClientData[0];
283 m_itemClientData[0] = pOld;
284 _WxCocoa_SetNeedsUpdate(true);
285 }
286
287
288 // pure virtuals from wxItemContainer
289 // deleting items
290 void wxListBox::DoClear()
291 {
292 [m_cocoaItems removeAllObjects];
293 m_itemClientData.Clear();
294 _WxCocoa_SetNeedsUpdate(true);
295 }
296
297 void wxListBox::DoDeleteOneItem(unsigned int n)
298 {
299 [m_cocoaItems removeObjectAtIndex:n];
300 m_itemClientData.RemoveAt(n);
301 _WxCocoa_SetNeedsUpdate(true);
302 }
303
304 // accessing strings
305 unsigned int wxListBox::GetCount() const
306 {
307 return (unsigned int)[m_cocoaItems count];
308 }
309
310 wxString wxListBox::GetString(unsigned int n) const
311 {
312 return wxStringWithNSString([m_cocoaItems objectAtIndex:n]);
313 }
314
315 void wxListBox::SetString(unsigned int n, const wxString& s)
316 {
317 wxAutoNSAutoreleasePool pool;
318 [m_cocoaItems removeObjectAtIndex:n];
319 [m_cocoaItems insertObject: wxNSStringWithWxString(s) atIndex: n];
320 _WxCocoa_SetNeedsUpdate(true);
321 }
322
323 int wxListBox::FindString(const wxString& s, bool bCase) const
324 {
325 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter
326 wxAutoNSAutoreleasePool pool;
327 return [m_cocoaItems indexOfObject:wxNSStringWithWxString(s)];
328 }
329
330 // selection
331 int wxListBox::GetSelection() const
332 {
333 return [GetNSTableView() selectedRow];
334 }
335
336 void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
337 {
338 m_itemClientData[n] = clientData;
339 }
340
341 void* wxListBox::DoGetItemClientData(unsigned int n) const
342 {
343 return m_itemClientData[n];
344 }
345
346 #endif // wxUSE_LISTBOX