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