]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/listbox.mm
don't refresh the current cell in SetCellHighlightROPenWidth() if it's invalid (...
[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
11e62fe6 7// Id: $Id$
812edc25 8// Copyright: (c) 2003 David Elliott
11e62fe6 9// Licence: wxWidgets licence
812edc25
DE
10/////////////////////////////////////////////////////////////////////////////
11
449c5673 12#include "wx/wxprec.h"
16c81607
RN
13
14#if wxUSE_LISTBOX
15
2a673eb1
WS
16#include "wx/listbox.h"
17
449c5673
DE
18#ifndef WX_PRECOMP
19 #include "wx/log.h"
20 #include "wx/app.h"
449c5673 21#endif //WX_PRECOMP
812edc25 22
bcaadf7e 23#include "wx/cocoa/string.h"
bed6fe0c 24#include "wx/cocoa/autorelease.h"
1a393573 25#include "wx/cocoa/ObjcRef.h"
97795793 26#include "wx/cocoa/private/scrollview.h"
bcaadf7e
DE
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>
97795793 33#import <AppKit/NSScrollView.h>
580cc1eb
DE
34#import <AppKit/NSCell.h>
35
580cc1eb
DE
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// ============================================================================
981af57c 70
b1294ada 71IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
812edc25
DE
72BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
73END_EVENT_TABLE()
bcaadf7e 74WX_IMPLEMENT_COCOA_OWNER(wxListBox,NSTableView,NSControl,NSView)
812edc25 75
584ad2a3
MB
76bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
77 const wxPoint& pos,
78 const wxSize& size,
79 const wxArrayString& choices,
80 long style,
81 const wxValidator& validator,
82 const wxString& name)
83{
84 wxCArrayString chs(choices);
85
86 return Create(parent, winid, pos, size, chs.GetCount(), chs.GetStrings(),
87 style, validator, name);
88}
89
812edc25
DE
90bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
91 const wxPoint& pos,
92 const wxSize& size,
93 int n, const wxString choices[],
94 long style,
95 const wxValidator& validator,
96 const wxString& name)
97{
50d2af52 98/*
11e62fe6
WS
99wxLB_SINGLE
100Single-selection list.
50d2af52 101
11e62fe6
WS
102wxLB_MULTIPLE
103Multiple-selection list: the user can toggle multiple items on and off.
50d2af52 104
11e62fe6
WS
105wxLB_EXTENDED
106Extended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.
50d2af52 107
11e62fe6
WS
108wxLB_HSCROLL
109Create horizontal scrollbar if contents are too wide (Windows only).
50d2af52 110
11e62fe6
WS
111wxLB_ALWAYS_SB
112Always show a vertical scrollbar.
50d2af52 113
11e62fe6
WS
114wxLB_NEEDED_SB
115Only create a vertical scrollbar if needed.
50d2af52 116
11e62fe6
WS
117wxLB_SORT
118The listbox contents are sorted in alphabetical order.
50d2af52 119*/
bed6fe0c 120 wxAutoNSAutoreleasePool pool;
812edc25
DE
121 if(!CreateControl(parent,winid,pos,size,style,validator,name))
122 return false;
123
bcaadf7e 124 // Provide the data
1a393573 125 m_cocoaItems = wxGCSafeRetain([NSMutableArray arrayWithCapacity:n]);
bcaadf7e
DE
126 for(int i=0; i < n; i++)
127 {
128 [m_cocoaItems addObject: wxNSStringWithWxString(choices[i])];
129 }
130 // Remove everything
c0ccf6a9 131 m_itemClientData.Clear();
bcaadf7e 132 // Initialize n elements to NULL
c0ccf6a9 133 m_itemClientData.SetCount(n,NULL);
bcaadf7e
DE
134
135 SetNSTableView([[NSTableView alloc] initWithFrame: MakeDefaultNSRect(size)]);
981af57c 136 [m_cocoaNSView release];
4a3dcf1d 137 [GetNSTableView() setHeaderView: nil];
981af57c 138
bcaadf7e 139 // Set up the data source
861b3043 140 m_cocoaDataSource = [[WX_GET_OBJC_CLASS(wxCocoaNSTableDataSource) alloc] init];
bcaadf7e
DE
141 [GetNSTableView() setDataSource:m_cocoaDataSource];
142
143 // Add the single column
144 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier:nil];
145 [GetNSTableView() addTableColumn: tableColumn];
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
97795793 157 [m_wxCocoaScrollView->GetNSScrollView() setHasVerticalScroller:YES];
fd3fe3ec
DE
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:)])
161 {
162 [m_wxCocoaScrollView->GetNSScrollView() setHasHorizontalScroller:YES];
163 [m_wxCocoaScrollView->GetNSScrollView() setAutohidesScrollers:YES];
164 }
97795793 165
50d2af52 166 // Set up extended/multiple selection flags
11e62fe6 167 if ((style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE))
50d2af52
RN
168 //diff is that mult requires shift down for multi selection
169 [GetNSTableView() setAllowsMultipleSelection:true];
170
171 [GetNSTableView() setAllowsColumnSelection:false];
580cc1eb 172 _SetWidthOfTableColumnToFitItems(tableColumn, m_cocoaItems);
812edc25
DE
173 return true;
174}
175
c86ec17b
DE
176wxSize wxListBox::DoGetBestSize() const
177{
178 wxSize size = wxControlWithItems::DoGetBestSize();
179 // Limit best size to 100x100. It can be smaller if none of the items are very
180 // wide or if there aren't many items, but anything bigger than 100x100 ought
181 // to be asked for by the programmer. The 100x100 size is based on being barely
182 // enough for a scroller to be usable.
183 if(size.GetWidth() > 100)
184 size.SetWidth(100);
185 if(size.GetHeight() > 100)
186 size.SetHeight(100);
187 return size;
188}
189
812edc25
DE
190wxListBox::~wxListBox()
191{
bcaadf7e
DE
192 [GetNSTableView() setDataSource: nil];
193 [m_cocoaDataSource release];
1a393573
DE
194 wxGCSafeRelease(m_cocoaItems);
195 m_cocoaItems = nil;
911e17c6 196 DisassociateNSTableView(GetNSTableView());
bcaadf7e
DE
197}
198
580cc1eb
DE
199bool wxListBox::_WxCocoa_GetNeedsUpdate()
200{
861b3043 201 return m_needsUpdate;
580cc1eb
DE
202}
203
204void wxListBox::_WxCocoa_SetNeedsUpdate(bool needsUpdate)
205{
861b3043 206 m_needsUpdate = needsUpdate;
580cc1eb
DE
207}
208
861b3043 209void wxListBox::OnInternalIdle()
580cc1eb 210{
861b3043 211 wxControlWithItems::OnInternalIdle();
580cc1eb
DE
212 if(_WxCocoa_GetNeedsUpdate())
213 {
214 _SetWidthOfTableColumnToFitItems([[GetNSTableView() tableColumns] objectAtIndex:0], m_cocoaItems);
215 [GetNSTableView() tile];
216 [GetNSTableView() reloadData];
217 _WxCocoa_SetNeedsUpdate(false);
218 }
219}
220
bcaadf7e
DE
221int wxListBox::CocoaDataSource_numberOfRows()
222{
223 return [m_cocoaItems count];
224}
225
226struct objc_object* wxListBox::CocoaDataSource_objectForTableColumn(
227 WX_NSTableColumn tableColumn, int rowIndex)
228{
229 return [m_cocoaItems objectAtIndex:rowIndex];
812edc25
DE
230}
231
232// pure virtuals from wxListBoxBase
233bool wxListBox::IsSelected(int n) const
234{
bcaadf7e 235 return [GetNSTableView() isRowSelected: n];
812edc25
DE
236}
237
c6179a84 238void wxListBox::DoSetSelection(int n, bool select)
812edc25 239{
bcaadf7e
DE
240 if(select)
241 [GetNSTableView() selectRow: n byExtendingSelection:NO];
242 else
243 [GetNSTableView() deselectRow: n];
812edc25
DE
244}
245
246int wxListBox::GetSelections(wxArrayInt& aSelections) const
247{
bcaadf7e
DE
248 aSelections.Clear();
249 NSEnumerator *enumerator = [GetNSTableView() selectedRowEnumerator];
250 while(NSNumber *num = [enumerator nextObject])
251 {
252 aSelections.Add([num intValue]);
253 }
254 return [GetNSTableView() numberOfSelectedRows];
812edc25
DE
255}
256
a236aa20 257int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
812edc25 258{
50d2af52
RN
259 wxAutoNSAutoreleasePool pool;
260
a236aa20
VZ
261 const unsigned int numItems = items.GetCount();
262 for ( unsigned int i = 0; i < numItems; ++i, ++pos )
bcaadf7e
DE
263 {
264 [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
265 atIndex: pos];
a236aa20
VZ
266 m_itemClientData.Insert(NULL, pos);
267 AssignNewItemClientData(pos, clientData, i, type);
bcaadf7e 268 }
11e62fe6 269
580cc1eb 270 _WxCocoa_SetNeedsUpdate(true);
a236aa20 271 return pos - 1;
812edc25
DE
272}
273
274void wxListBox::DoSetFirstItem(int n)
275{
50d2af52
RN
276 [m_cocoaItems exchangeObjectAtIndex:0 withObjectAtIndex:n];
277 void* pOld = m_itemClientData[n];
278 m_itemClientData[n] = m_itemClientData[0];
279 m_itemClientData[0] = pOld;
580cc1eb 280 _WxCocoa_SetNeedsUpdate(true);
812edc25
DE
281}
282
283
284// pure virtuals from wxItemContainer
285 // deleting items
a236aa20 286void wxListBox::DoClear()
812edc25 287{
50d2af52
RN
288 [m_cocoaItems removeAllObjects];
289 m_itemClientData.Clear();
580cc1eb 290 _WxCocoa_SetNeedsUpdate(true);
812edc25
DE
291}
292
a236aa20 293void wxListBox::DoDeleteOneItem(unsigned int n)
812edc25 294{
50d2af52
RN
295 [m_cocoaItems removeObjectAtIndex:n];
296 m_itemClientData.RemoveAt(n);
580cc1eb 297 _WxCocoa_SetNeedsUpdate(true);
812edc25
DE
298}
299
300 // accessing strings
aa61d352 301unsigned int wxListBox::GetCount() const
812edc25 302{
aa61d352 303 return (unsigned int)[m_cocoaItems count];
812edc25
DE
304}
305
aa61d352 306wxString wxListBox::GetString(unsigned int n) const
812edc25 307{
50d2af52 308 return wxStringWithNSString([m_cocoaItems objectAtIndex:n]);
812edc25
DE
309}
310
aa61d352 311void wxListBox::SetString(unsigned int n, const wxString& s)
812edc25 312{
50d2af52
RN
313 wxAutoNSAutoreleasePool pool;
314 [m_cocoaItems removeObjectAtIndex:n];
315 [m_cocoaItems insertObject: wxNSStringWithWxString(s) atIndex: n];
580cc1eb 316 _WxCocoa_SetNeedsUpdate(true);
812edc25
DE
317}
318
11e62fe6 319int wxListBox::FindString(const wxString& s, bool bCase) const
812edc25 320{
11e62fe6 321 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter
50d2af52
RN
322 wxAutoNSAutoreleasePool pool;
323 return [m_cocoaItems indexOfObject:wxNSStringWithWxString(s)];
812edc25
DE
324}
325
326 // selection
812edc25
DE
327int wxListBox::GetSelection() const
328{
50d2af52 329 return [GetNSTableView() selectedRow];
812edc25
DE
330}
331
aa61d352 332void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
812edc25 333{
50d2af52 334 m_itemClientData[n] = clientData;
812edc25
DE
335}
336
aa61d352 337void* wxListBox::DoGetItemClientData(unsigned int n) const
812edc25 338{
50d2af52 339 return m_itemClientData[n];
812edc25
DE
340}
341
a236aa20 342#endif // wxUSE_LISTBOX