listbox.mm 10 KB

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