]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/cocoa/listbox.mm
new file added
[wxWidgets.git] / src / cocoa / listbox.mm
... / ...
CommitLineData
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: wxWindows 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// ============================================================================
38// helper functions
39// ============================================================================
40
41static CGFloat _TableColumnMaxWidthForItems(NSTableColumn *tableColumn, NSArray *items)
42{
43 wxAutoNSAutoreleasePool pool;
44
45 NSCell *dataCell = [[[tableColumn dataCell] copy] autorelease];
46 CGFloat width = 0.0f;
47 NSEnumerator *itemEnum = [items objectEnumerator];
48 NSString *item;
49 while( (item = [itemEnum nextObject]) != nil )
50 {
51 [dataCell setStringValue: item];
52 NSSize itemSize = [dataCell cellSize];
53 CGFloat itemWidth = itemSize.width;
54 if(itemWidth > width)
55 width = itemWidth;
56 }
57 return width;
58}
59
60static void _SetWidthOfTableColumnToFitItems(NSTableColumn *tableColumn, NSArray *items)
61{
62 CGFloat width = _TableColumnMaxWidthForItems(tableColumn, items);
63 [tableColumn setWidth:width];
64 [tableColumn setMinWidth:width];
65}
66
67// ============================================================================
68// class wxListBox
69// ============================================================================
70
71BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
72END_EVENT_TABLE()
73WX_IMPLEMENT_COCOA_OWNER(wxListBox,NSTableView,NSControl,NSView)
74
75bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
76 const wxPoint& pos,
77 const wxSize& size,
78 const wxArrayString& choices,
79 long style,
80 const wxValidator& validator,
81 const wxString& name)
82{
83 wxCArrayString chs(choices);
84
85 return Create(parent, winid, pos, size, chs.GetCount(), chs.GetStrings(),
86 style, validator, name);
87}
88
89bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
90 const wxPoint& pos,
91 const wxSize& size,
92 int n, const wxString choices[],
93 long style,
94 const wxValidator& validator,
95 const wxString& name)
96{
97/*
98wxLB_SINGLE
99Single-selection list.
100
101wxLB_MULTIPLE
102Multiple-selection list: the user can toggle multiple items on and off.
103
104wxLB_EXTENDED
105Extended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.
106
107wxLB_HSCROLL
108Create horizontal scrollbar if contents are too wide (Windows only).
109
110wxLB_ALWAYS_SB
111Always show a vertical scrollbar.
112
113wxLB_NEEDED_SB
114Only create a vertical scrollbar if needed.
115
116wxLB_SORT
117The listbox contents are sorted in alphabetical order.
118*/
119 wxAutoNSAutoreleasePool pool;
120 if(!CreateControl(parent,winid,pos,size,style,validator,name))
121 return false;
122
123 // Provide the data
124 m_cocoaItems = wxGCSafeRetain([NSMutableArray arrayWithCapacity:n]);
125 for(int i=0; i < n; i++)
126 {
127 [m_cocoaItems addObject: wxNSStringWithWxString(choices[i])];
128 }
129 // Remove everything
130 m_itemClientData.Clear();
131 // Initialize n elements to NULL
132 m_itemClientData.SetCount(n,NULL);
133
134 SetNSTableView([[NSTableView alloc] initWithFrame: MakeDefaultNSRect(size)]);
135 [m_cocoaNSView release];
136 [GetNSTableView() setHeaderView: nil];
137
138 // Set up the data source
139 m_cocoaDataSource = [[WX_GET_OBJC_CLASS(wxCocoaNSTableDataSource) alloc] init];
140 [GetNSTableView() setDataSource:m_cocoaDataSource];
141
142 // Add the single column
143 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier:nil];
144 [GetNSTableView() addTableColumn: tableColumn];
145 // By default, entries should not be editable
146 [tableColumn setEditable:NO];
147 [tableColumn release];
148
149 [GetNSTableView() sizeToFit];
150 // Finish
151 if(m_parent)
152 m_parent->CocoaAddChild(this);
153 // NSTableView does WEIRD things with sizes. Wrapping it in an
154 // NSScrollView seems to be the only reasonable solution.
155 CocoaCreateNSScrollView();
156 SetInitialFrameRect(pos,size);
157
158 if ((style & wxLB_NEEDED_SB) || (style & wxLB_ALWAYS_SB))
159 {
160 [m_wxCocoaScrollView->GetNSScrollView() setHasVerticalScroller: YES];
161 }
162
163 if (style & wxLB_HSCROLL)
164 {
165 [m_wxCocoaScrollView->GetNSScrollView() setHasHorizontalScroller: YES];
166 }
167
168 // We can't set auto-hiding individually for horizontal/vertical scrollers,
169 // so we have settled on always allowing hiding for both unless the vertical
170 // setting is "always show".
171 if (((style & wxLB_NEEDED_SB) || (style & wxLB_HSCROLL)) && !(style & wxLB_ALWAYS_SB))
172 {
173 if ([m_wxCocoaScrollView->GetNSScrollView() respondsToSelector:@selector(setAutohidesScrollers:)])
174 {
175 [m_wxCocoaScrollView->GetNSScrollView() setAutohidesScrollers: YES];
176 }
177 }
178
179 // Set up extended/multiple selection flags
180 if ((style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE))
181 //diff is that mult requires shift down for multi selection
182 [GetNSTableView() setAllowsMultipleSelection:true];
183
184 [GetNSTableView() setAllowsColumnSelection:false];
185 _SetWidthOfTableColumnToFitItems(tableColumn, m_cocoaItems);
186 return true;
187}
188
189wxSize wxListBox::DoGetBestSize() const
190{
191 wxSize size = wxControlWithItems::DoGetBestSize();
192 // Limit best size to 100x100. It can be smaller if none of the items are very
193 // wide or if there aren't many items, but anything bigger than 100x100 ought
194 // to be asked for by the programmer. The 100x100 size is based on being barely
195 // enough for a scroller to be usable.
196 if(size.GetWidth() > 100)
197 size.SetWidth(100);
198 if(size.GetHeight() > 100)
199 size.SetHeight(100);
200 return size;
201}
202
203wxListBox::~wxListBox()
204{
205 [GetNSTableView() setDataSource: nil];
206 [m_cocoaDataSource release];
207 wxGCSafeRelease(m_cocoaItems);
208 m_cocoaItems = nil;
209 DisassociateNSTableView(GetNSTableView());
210}
211
212bool wxListBox::_WxCocoa_GetNeedsUpdate()
213{
214 return m_needsUpdate;
215}
216
217void wxListBox::_WxCocoa_SetNeedsUpdate(bool needsUpdate)
218{
219 m_needsUpdate = needsUpdate;
220}
221
222void wxListBox::OnInternalIdle()
223{
224 wxControlWithItems::OnInternalIdle();
225 if(_WxCocoa_GetNeedsUpdate())
226 {
227 _SetWidthOfTableColumnToFitItems([[GetNSTableView() tableColumns] objectAtIndex:0], m_cocoaItems);
228 [GetNSTableView() tile];
229 [GetNSTableView() reloadData];
230 _WxCocoa_SetNeedsUpdate(false);
231 }
232}
233
234int wxListBox::CocoaDataSource_numberOfRows()
235{
236 return [m_cocoaItems count];
237}
238
239struct objc_object* wxListBox::CocoaDataSource_objectForTableColumn(
240 WX_NSTableColumn tableColumn, int rowIndex)
241{
242 return [m_cocoaItems objectAtIndex:rowIndex];
243}
244
245// pure virtuals from wxListBoxBase
246bool wxListBox::IsSelected(int n) const
247{
248 return [GetNSTableView() isRowSelected: n];
249}
250
251void wxListBox::DoSetSelection(int n, bool select)
252{
253 if(select)
254 [GetNSTableView() selectRow: n byExtendingSelection:NO];
255 else
256 [GetNSTableView() deselectRow: n];
257}
258
259int wxListBox::GetSelections(wxArrayInt& aSelections) const
260{
261 aSelections.Clear();
262 NSEnumerator *enumerator = [GetNSTableView() selectedRowEnumerator];
263 while(NSNumber *num = [enumerator nextObject])
264 {
265 aSelections.Add([num intValue]);
266 }
267 return [GetNSTableView() numberOfSelectedRows];
268}
269
270int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
271{
272 wxAutoNSAutoreleasePool pool;
273
274 const unsigned int numItems = items.GetCount();
275 for ( unsigned int i = 0; i < numItems; ++i, ++pos )
276 {
277 [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
278 atIndex: pos];
279 m_itemClientData.Insert(NULL, pos);
280 AssignNewItemClientData(pos, clientData, i, type);
281 }
282
283 _WxCocoa_SetNeedsUpdate(true);
284 return pos - 1;
285}
286
287void wxListBox::DoSetFirstItem(int n)
288{
289 [m_cocoaItems exchangeObjectAtIndex:0 withObjectAtIndex:n];
290 void* pOld = m_itemClientData[n];
291 m_itemClientData[n] = m_itemClientData[0];
292 m_itemClientData[0] = pOld;
293 _WxCocoa_SetNeedsUpdate(true);
294}
295
296
297// pure virtuals from wxItemContainer
298 // deleting items
299void wxListBox::DoClear()
300{
301 [m_cocoaItems removeAllObjects];
302 m_itemClientData.Clear();
303 _WxCocoa_SetNeedsUpdate(true);
304}
305
306void wxListBox::DoDeleteOneItem(unsigned int n)
307{
308 [m_cocoaItems removeObjectAtIndex:n];
309 m_itemClientData.RemoveAt(n);
310 _WxCocoa_SetNeedsUpdate(true);
311}
312
313 // accessing strings
314unsigned int wxListBox::GetCount() const
315{
316 return (unsigned int)[m_cocoaItems count];
317}
318
319wxString wxListBox::GetString(unsigned int n) const
320{
321 return wxStringWithNSString([m_cocoaItems objectAtIndex:n]);
322}
323
324void wxListBox::SetString(unsigned int n, const wxString& s)
325{
326 wxAutoNSAutoreleasePool pool;
327 [m_cocoaItems removeObjectAtIndex:n];
328 [m_cocoaItems insertObject: wxNSStringWithWxString(s) atIndex: n];
329 _WxCocoa_SetNeedsUpdate(true);
330}
331
332int wxListBox::FindString(const wxString& s, bool bCase) const
333{
334 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter
335 wxAutoNSAutoreleasePool pool;
336 return [m_cocoaItems indexOfObject:wxNSStringWithWxString(s)];
337}
338
339 // selection
340int wxListBox::GetSelection() const
341{
342 return [GetNSTableView() selectedRow];
343}
344
345void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
346{
347 m_itemClientData[n] = clientData;
348}
349
350void* wxListBox::DoGetItemClientData(unsigned int n) const
351{
352 return m_itemClientData[n];
353}
354
355#endif // wxUSE_LISTBOX