1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/listbox.mm
4 // Author: David Elliott
8 // Copyright: (c) 2003 David Elliott
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
16 #include "wx/listbox.h"
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"
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>
37 // ============================================================================
39 // ============================================================================
41 static CGFloat _TableColumnMaxWidthForItems(NSTableColumn *tableColumn, NSArray *items)
43 wxAutoNSAutoreleasePool pool;
45 NSCell *dataCell = [[[tableColumn dataCell] copy] autorelease];
47 NSEnumerator *itemEnum = [items objectEnumerator];
49 while( (item = [itemEnum nextObject]) != nil )
51 [dataCell setStringValue: item];
52 NSSize itemSize = [dataCell cellSize];
53 CGFloat itemWidth = itemSize.width;
60 static void _SetWidthOfTableColumnToFitItems(NSTableColumn *tableColumn, NSArray *items)
62 CGFloat width = _TableColumnMaxWidthForItems(tableColumn, items);
63 [tableColumn setWidth:width];
64 [tableColumn setMinWidth:width];
67 // ============================================================================
69 // ============================================================================
71 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
72 BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
74 WX_IMPLEMENT_COCOA_OWNER(wxListBox,NSTableView,NSControl,NSView)
76 bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
79 const wxArrayString& choices,
81 const wxValidator& validator,
84 wxCArrayString chs(choices);
86 return Create(parent, winid, pos, size, chs.GetCount(), chs.GetStrings(),
87 style, validator, name);
90 bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
93 int n, const wxString choices[],
95 const wxValidator& validator,
100 Single-selection list.
103 Multiple-selection list: the user can toggle multiple items on and off.
106 Extended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.
109 Create horizontal scrollbar if contents are too wide (Windows only).
112 Always show a vertical scrollbar.
115 Only create a vertical scrollbar if needed.
118 The listbox contents are sorted in alphabetical order.
120 wxAutoNSAutoreleasePool pool;
121 if(!CreateControl(parent,winid,pos,size,style,validator,name))
125 m_cocoaItems = wxGCSafeRetain([NSMutableArray arrayWithCapacity:n]);
126 for(int i=0; i < n; i++)
128 [m_cocoaItems addObject: wxNSStringWithWxString(choices[i])];
131 m_itemClientData.Clear();
132 // Initialize n elements to NULL
133 m_itemClientData.SetCount(n,NULL);
135 SetNSTableView([[NSTableView alloc] initWithFrame: MakeDefaultNSRect(size)]);
136 [m_cocoaNSView release];
137 [GetNSTableView() setHeaderView: nil];
139 // Set up the data source
140 m_cocoaDataSource = [[WX_GET_OBJC_CLASS(wxCocoaNSTableDataSource) alloc] init];
141 [GetNSTableView() setDataSource:m_cocoaDataSource];
143 // Add the single column
144 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier:nil];
145 [GetNSTableView() addTableColumn: tableColumn];
146 [tableColumn release];
148 [GetNSTableView() sizeToFit];
151 m_parent->CocoaAddChild(this);
152 // NSTableView does WEIRD things with sizes. Wrapping it in an
153 // NSScrollView seems to be the only reasonable solution.
154 CocoaCreateNSScrollView();
155 SetInitialFrameRect(pos,size);
157 [m_wxCocoaScrollView->GetNSScrollView() setHasVerticalScroller:YES];
158 // Pre-10.3: Always show vertical scroller, never show horizontal scroller
159 // Post-10.3: Show scrollers dynamically (turn them both on, set auto-hide)
160 if([m_wxCocoaScrollView->GetNSScrollView() respondsToSelector:@selector(setAutohidesScrollers:)])
162 [m_wxCocoaScrollView->GetNSScrollView() setHasHorizontalScroller:YES];
163 [m_wxCocoaScrollView->GetNSScrollView() setAutohidesScrollers:YES];
166 // Set up extended/multiple selection flags
167 if ((style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE))
168 //diff is that mult requires shift down for multi selection
169 [GetNSTableView() setAllowsMultipleSelection:true];
171 [GetNSTableView() setAllowsColumnSelection:false];
172 _SetWidthOfTableColumnToFitItems(tableColumn, m_cocoaItems);
176 wxListBox::~wxListBox()
178 [GetNSTableView() setDataSource: nil];
179 [m_cocoaDataSource release];
180 wxGCSafeRelease(m_cocoaItems);
182 DisassociateNSTableView(GetNSTableView());
185 bool wxListBox::_WxCocoa_GetNeedsUpdate()
187 return m_needsUpdate;
190 void wxListBox::_WxCocoa_SetNeedsUpdate(bool needsUpdate)
192 m_needsUpdate = needsUpdate;
195 void wxListBox::OnInternalIdle()
197 wxControlWithItems::OnInternalIdle();
198 if(_WxCocoa_GetNeedsUpdate())
200 _SetWidthOfTableColumnToFitItems([[GetNSTableView() tableColumns] objectAtIndex:0], m_cocoaItems);
201 [GetNSTableView() tile];
202 [GetNSTableView() reloadData];
203 _WxCocoa_SetNeedsUpdate(false);
207 int wxListBox::CocoaDataSource_numberOfRows()
209 return [m_cocoaItems count];
212 struct objc_object* wxListBox::CocoaDataSource_objectForTableColumn(
213 WX_NSTableColumn tableColumn, int rowIndex)
215 return [m_cocoaItems objectAtIndex:rowIndex];
218 // pure virtuals from wxListBoxBase
219 bool wxListBox::IsSelected(int n) const
221 return [GetNSTableView() isRowSelected: n];
224 void wxListBox::DoSetSelection(int n, bool select)
227 [GetNSTableView() selectRow: n byExtendingSelection:NO];
229 [GetNSTableView() deselectRow: n];
232 int wxListBox::GetSelections(wxArrayInt& aSelections) const
235 NSEnumerator *enumerator = [GetNSTableView() selectedRowEnumerator];
236 while(NSNumber *num = [enumerator nextObject])
238 aSelections.Add([num intValue]);
240 return [GetNSTableView() numberOfSelectedRows];
243 int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
245 wxAutoNSAutoreleasePool pool;
247 const unsigned int numItems = items.GetCount();
248 for ( unsigned int i = 0; i < numItems; ++i, ++pos )
250 [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
252 m_itemClientData.Insert(NULL, pos);
253 AssignNewItemClientData(pos, clientData, i, type);
256 _WxCocoa_SetNeedsUpdate(true);
260 void wxListBox::DoSetFirstItem(int n)
262 [m_cocoaItems exchangeObjectAtIndex:0 withObjectAtIndex:n];
263 void* pOld = m_itemClientData[n];
264 m_itemClientData[n] = m_itemClientData[0];
265 m_itemClientData[0] = pOld;
266 _WxCocoa_SetNeedsUpdate(true);
270 // pure virtuals from wxItemContainer
272 void wxListBox::DoClear()
274 [m_cocoaItems removeAllObjects];
275 m_itemClientData.Clear();
276 _WxCocoa_SetNeedsUpdate(true);
279 void wxListBox::DoDeleteOneItem(unsigned int n)
281 [m_cocoaItems removeObjectAtIndex:n];
282 m_itemClientData.RemoveAt(n);
283 _WxCocoa_SetNeedsUpdate(true);
287 unsigned int wxListBox::GetCount() const
289 return (unsigned int)[m_cocoaItems count];
292 wxString wxListBox::GetString(unsigned int n) const
294 return wxStringWithNSString([m_cocoaItems objectAtIndex:n]);
297 void wxListBox::SetString(unsigned int n, const wxString& s)
299 wxAutoNSAutoreleasePool pool;
300 [m_cocoaItems removeObjectAtIndex:n];
301 [m_cocoaItems insertObject: wxNSStringWithWxString(s) atIndex: n];
302 _WxCocoa_SetNeedsUpdate(true);
305 int wxListBox::FindString(const wxString& s, bool bCase) const
307 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter
308 wxAutoNSAutoreleasePool pool;
309 return [m_cocoaItems indexOfObject:wxNSStringWithWxString(s)];
313 int wxListBox::GetSelection() const
315 return [GetNSTableView() selectedRow];
318 void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
320 m_itemClientData[n] = clientData;
323 void* wxListBox::DoGetItemClientData(unsigned int n) const
325 return m_itemClientData[n];
328 #endif // wxUSE_LISTBOX