1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/listbox.mm
4 // Author: Stefan Csomor
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
15 #include "wx/listbox.h"
22 #include "wx/settings.h"
23 #include "wx/arrstr.h"
24 #include "wx/dcclient.h"
27 #include "wx/osx/private.h"
33 class wxListWidgetCocoaImpl;
35 @interface wxNSTableDataSource : NSObject wxOSX_10_6_AND_LATER(<NSTableViewDataSource>)
37 wxListWidgetCocoaImpl* impl;
40 - (id)tableView:(NSTableView *)aTableView
41 objectValueForTableColumn:(NSTableColumn *)aTableColumn
42 row:(NSInteger)rowIndex;
44 - (void)tableView:(NSTableView *)aTableView
45 setObjectValue:(id)value forTableColumn:(NSTableColumn *)aTableColumn
46 row:(NSInteger)rowIndex;
48 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView;
50 - (void)setImplementation: (wxListWidgetCocoaImpl *) theImplementation;
51 - (wxListWidgetCocoaImpl*) implementation;
55 @interface wxNSTableView : NSTableView wxOSX_10_6_AND_LATER(<NSTableViewDelegate>)
65 class wxCocoaTableColumn;
67 @interface wxNSTableColumn : NSTableColumn
69 wxCocoaTableColumn* column;
72 - (void) setColumn: (wxCocoaTableColumn*) col;
74 - (wxCocoaTableColumn*) column;
78 class WXDLLIMPEXP_CORE wxCocoaTableColumn : public wxListWidgetColumn
81 wxCocoaTableColumn( wxNSTableColumn* column, bool editable )
82 : m_column( column ), m_editable(editable)
90 wxNSTableColumn* GetNSTableColumn() const { return m_column ; }
92 bool IsEditable() const { return m_editable; }
95 wxNSTableColumn* m_column;
99 NSString* column1 = @"1";
101 class wxListWidgetCocoaImpl : public wxWidgetCocoaImpl, public wxListWidgetImpl
104 wxListWidgetCocoaImpl( wxWindowMac* peer, NSScrollView* view, wxNSTableView* tableview, wxNSTableDataSource* data );
106 ~wxListWidgetCocoaImpl();
108 virtual wxListWidgetColumn* InsertTextColumn( unsigned pos, const wxString& title, bool editable = false,
109 wxAlignment just = wxALIGN_LEFT , int defaultWidth = -1) ;
110 virtual wxListWidgetColumn* InsertCheckColumn( unsigned pos , const wxString& title, bool editable = false,
111 wxAlignment just = wxALIGN_LEFT , int defaultWidth = -1) ;
115 virtual void ListDelete( unsigned int n ) ;
116 virtual void ListInsert( unsigned int n ) ;
117 virtual void ListClear() ;
121 virtual void ListDeselectAll();
123 virtual void ListSetSelection( unsigned int n, bool select, bool multi ) ;
124 virtual int ListGetSelection() const ;
126 virtual int ListGetSelections( wxArrayInt& aSelections ) const ;
128 virtual bool ListIsSelected( unsigned int n ) const ;
132 virtual void ListScrollTo( unsigned int n ) ;
136 virtual unsigned int ListGetCount() const ;
137 virtual int DoListHitTest( const wxPoint& inpoint ) const;
139 int ListGetColumnType( int col )
143 virtual void UpdateLine( unsigned int n, wxListWidgetColumn* col = NULL ) ;
144 virtual void UpdateLineToEnd( unsigned int n);
146 virtual void controlDoubleAction(WXWidget slf, void* _cmd, void *sender);
150 wxNSTableView* m_tableView ;
152 wxNSTableDataSource* m_dataSource;
159 @implementation wxNSTableColumn
168 - (void) setColumn: (wxCocoaTableColumn*) col
173 - (wxCocoaTableColumn*) column
180 class wxNSTableViewCellValue : public wxListWidgetCellValue
183 wxNSTableViewCellValue( id &v ) : value(v)
187 virtual ~wxNSTableViewCellValue() {}
189 virtual void Set( CFStringRef v )
191 value = [[(NSString*)v retain] autorelease];
193 virtual void Set( const wxString& value )
195 Set( (CFStringRef) wxCFStringRef( value ) );
197 virtual void Set( int v )
199 value = [NSNumber numberWithInt:v];
202 virtual int GetIntValue() const
204 if ( [value isKindOfClass:[NSNumber class]] )
205 return [ (NSNumber*) value intValue ];
210 virtual wxString GetStringValue() const
212 if ( [value isKindOfClass:[NSString class]] )
213 return wxCFStringRef::AsString( (NSString*) value );
215 return wxEmptyString;
222 @implementation wxNSTableDataSource
231 - (void)setImplementation: (wxListWidgetCocoaImpl *) theImplementation
233 impl = theImplementation;
236 - (wxListWidgetCocoaImpl*) implementation
241 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
243 wxUnusedVar(aTableView);
245 return impl->ListGetCount();
249 - (id)tableView:(NSTableView *)aTableView
250 objectValueForTableColumn:(NSTableColumn *)aTableColumn
251 row:(NSInteger)rowIndex
253 wxUnusedVar(aTableView);
254 wxNSTableColumn* tablecol = (wxNSTableColumn *)aTableColumn;
255 wxListBox* lb = dynamic_cast<wxListBox*>(impl->GetWXPeer());
256 wxCocoaTableColumn* col = [tablecol column];
258 wxNSTableViewCellValue cellvalue(value);
259 lb->GetValueCallback(rowIndex, col, cellvalue);
263 - (void)tableView:(NSTableView *)aTableView
264 setObjectValue:(id)value forTableColumn:(NSTableColumn *)aTableColumn
265 row:(NSInteger)rowIndex
267 wxUnusedVar(aTableView);
268 wxNSTableColumn* tablecol = (wxNSTableColumn *)aTableColumn;
269 wxListBox* lb = dynamic_cast<wxListBox*>(impl->GetWXPeer());
270 wxCocoaTableColumn* col = [tablecol column];
271 wxNSTableViewCellValue cellvalue(value);
272 lb->SetValueCallback(rowIndex, col, cellvalue);
277 @implementation wxNSTableView
281 static BOOL initialized = NO;
285 wxOSXCocoaClassAddWXMethods( self );
289 - (void) tableViewSelectionDidChange: (NSNotification *) notification
291 wxUnusedVar(notification);
293 int row = [self selectedRow];
301 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
302 wxListBox *list = static_cast<wxListBox*> ( impl->GetWXPeer());
303 wxCHECK_RET( list != NULL , wxT("Listbox expected"));
305 wxCommandEvent event( wxEVT_LISTBOX, list->GetId() );
307 if ((row < 0) || (row > (int) list->GetCount())) // OS X can select an item below the last item
310 if ( !list->MacGetBlockEvents() )
311 list->HandleLineEvent( row, false );
316 - (void)setFont:(NSFont *)aFont
318 NSArray *tableColumns = [self tableColumns];
319 unsigned int columnIndex = [tableColumns count];
320 while (columnIndex--)
321 [[(NSTableColumn *)[tableColumns objectAtIndex:columnIndex] dataCell] setFont:aFont];
323 [self setRowHeight:[gNSLayoutManager defaultLineHeightForFont:aFont]+2];
326 - (void) setControlSize:(NSControlSize) size
328 NSArray *tableColumns = [self tableColumns];
329 unsigned int columnIndex = [tableColumns count];
330 while (columnIndex--)
331 [[(NSTableColumn *)[tableColumns objectAtIndex:columnIndex] dataCell] setControlSize:size];
340 wxListWidgetCocoaImpl::wxListWidgetCocoaImpl( wxWindowMac* peer, NSScrollView* view, wxNSTableView* tableview, wxNSTableDataSource* data ) :
341 wxWidgetCocoaImpl( peer, view ), m_tableView(tableview), m_dataSource(data)
343 InstallEventHandler( tableview );
346 wxListWidgetCocoaImpl::~wxListWidgetCocoaImpl()
348 [m_dataSource release];
351 unsigned int wxListWidgetCocoaImpl::ListGetCount() const
353 wxListBox* lb = dynamic_cast<wxListBox*> ( GetWXPeer() );
354 return lb->GetCount();
361 wxListWidgetColumn* wxListWidgetCocoaImpl::InsertTextColumn( unsigned pos, const wxString& WXUNUSED(title), bool editable,
362 wxAlignment WXUNUSED(just), int defaultWidth)
364 wxNSTableColumn* col1 = [[wxNSTableColumn alloc] init];
365 [col1 setEditable:editable];
367 unsigned formerColCount = [m_tableView numberOfColumns];
369 // there's apparently no way to insert at a specific position
370 [m_tableView addTableColumn:col1 ];
371 if ( pos < formerColCount )
372 [m_tableView moveColumn:formerColCount toColumn:pos];
374 if ( defaultWidth >= 0 )
376 [col1 setMaxWidth:defaultWidth];
377 [col1 setMinWidth:defaultWidth];
378 [col1 setWidth:defaultWidth];
382 [col1 setMaxWidth:1000];
383 [col1 setMinWidth:10];
384 // temporary hack, because I cannot get the automatic column resizing
386 [col1 setWidth:1000];
388 [col1 setResizingMask: NSTableColumnAutoresizingMask];
390 wxListBox *list = static_cast<wxListBox*> ( GetWXPeer());
392 [[col1 dataCell] setFont:list->GetFont().OSXGetNSFont()];
394 wxCocoaTableColumn* wxcol = new wxCocoaTableColumn( col1, editable );
395 [col1 setColumn:wxcol];
397 // owned by the tableview
402 wxListWidgetColumn* wxListWidgetCocoaImpl::InsertCheckColumn( unsigned pos , const wxString& WXUNUSED(title), bool editable,
403 wxAlignment WXUNUSED(just), int defaultWidth )
405 wxNSTableColumn* col1 = [[wxNSTableColumn alloc] init];
406 [col1 setEditable:editable];
408 // set your custom cell & set it up
409 NSButtonCell* checkbox = [[NSButtonCell alloc] init];
410 [checkbox setTitle:@""];
411 [checkbox setButtonType:NSSwitchButton];
412 [col1 setDataCell:checkbox] ;
414 wxListBox *list = static_cast<wxListBox*> ( GetWXPeer());
417 NSControlSize size = NSRegularControlSize;
419 switch ( list->GetWindowVariant() )
421 case wxWINDOW_VARIANT_NORMAL :
422 size = NSRegularControlSize;
425 case wxWINDOW_VARIANT_SMALL :
426 size = NSSmallControlSize;
429 case wxWINDOW_VARIANT_MINI :
430 size = NSMiniControlSize;
433 case wxWINDOW_VARIANT_LARGE :
434 size = NSRegularControlSize;
441 [[col1 dataCell] setControlSize:size];
442 // although there is no text, it may help to get the correct vertical layout
443 [[col1 dataCell] setFont:list->GetFont().OSXGetNSFont()];
448 unsigned formerColCount = [m_tableView numberOfColumns];
450 // there's apparently no way to insert at a specific position
451 [m_tableView addTableColumn:col1 ];
452 if ( pos < formerColCount )
453 [m_tableView moveColumn:formerColCount toColumn:pos];
455 if ( defaultWidth >= 0 )
457 [col1 setMaxWidth:defaultWidth];
458 [col1 setMinWidth:defaultWidth];
459 [col1 setWidth:defaultWidth];
462 [col1 setResizingMask: NSTableColumnNoResizing];
463 wxCocoaTableColumn* wxcol = new wxCocoaTableColumn( col1, editable );
464 [col1 setColumn:wxcol];
466 // owned by the tableview
473 // inserting / removing lines
476 void wxListWidgetCocoaImpl::ListInsert( unsigned int WXUNUSED(n) )
478 [m_tableView reloadData];
481 void wxListWidgetCocoaImpl::ListDelete( unsigned int WXUNUSED(n) )
483 [m_tableView reloadData];
486 void wxListWidgetCocoaImpl::ListClear()
488 [m_tableView reloadData];
493 void wxListWidgetCocoaImpl::ListDeselectAll()
495 [m_tableView deselectAll:nil];
498 void wxListWidgetCocoaImpl::ListSetSelection( unsigned int n, bool select, bool multi )
502 [m_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:n]
503 byExtendingSelection:multi];
505 [m_tableView deselectRow: n];
509 int wxListWidgetCocoaImpl::ListGetSelection() const
511 return [m_tableView selectedRow];
514 int wxListWidgetCocoaImpl::ListGetSelections( wxArrayInt& aSelections ) const
518 int count = ListGetCount();
520 for ( int i = 0; i < count; ++i)
522 if ([m_tableView isRowSelected:i])
526 return aSelections.Count();
529 bool wxListWidgetCocoaImpl::ListIsSelected( unsigned int n ) const
531 return [m_tableView isRowSelected:n];
536 void wxListWidgetCocoaImpl::ListScrollTo( unsigned int n )
538 [m_tableView scrollRowToVisible:n];
542 void wxListWidgetCocoaImpl::UpdateLine( unsigned int WXUNUSED(n), wxListWidgetColumn* WXUNUSED(col) )
545 [m_tableView reloadData];
548 void wxListWidgetCocoaImpl::UpdateLineToEnd( unsigned int WXUNUSED(n))
551 [m_tableView reloadData];
554 void wxListWidgetCocoaImpl::controlDoubleAction(WXWidget WXUNUSED(slf),void* WXUNUSED(_cmd), void *WXUNUSED(sender))
556 wxListBox *list = static_cast<wxListBox*> ( GetWXPeer());
557 wxCHECK_RET( list != NULL , wxT("Listbox expected"));
559 int sel = [m_tableView clickedRow];
560 if ((sel < 0) || (sel > (int) list->GetCount())) // OS X can select an item below the last item (why?)
563 list->HandleLineEvent( sel, true );
569 wxWidgetImplType* wxWidgetImpl::CreateListBox( wxWindowMac* wxpeer,
570 wxWindowMac* WXUNUSED(parent),
571 wxWindowID WXUNUSED(id),
575 long WXUNUSED(extraStyle))
577 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
578 NSScrollView* scrollview = [[NSScrollView alloc] initWithFrame:r];
580 // use same scroll flags logic as msw
582 [scrollview setHasVerticalScroller:YES];
584 if ( style & wxLB_HSCROLL )
585 [scrollview setHasHorizontalScroller:YES];
587 [scrollview setAutohidesScrollers: ((style & wxLB_ALWAYS_SB) ? NO : YES)];
589 // setting up the true table
591 wxNSTableView* tableview = [[wxNSTableView alloc] init];
592 [tableview setDelegate:tableview];
593 // only one multi-select mode available
594 if ( (style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE) )
595 [tableview setAllowsMultipleSelection:YES];
597 // simple listboxes have no header row
598 [tableview setHeaderView:nil];
600 if ( style & wxLB_HSCROLL )
601 [tableview setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing];
603 [tableview setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle];
605 wxNSTableDataSource* ds = [[ wxNSTableDataSource alloc] init];
606 [tableview setDataSource:ds];
607 [scrollview setDocumentView:tableview];
610 wxListWidgetCocoaImpl* c = new wxListWidgetCocoaImpl( wxpeer, scrollview, tableview, ds );
612 // temporary hook for dnd
613 // [tableview registerForDraggedTypes:[NSArray arrayWithObjects:
614 // NSStringPboardType, NSFilenamesPboardType, (NSString*) kPasteboardTypeFileURLPromise, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]];
616 [ds setImplementation:c];
620 int wxListWidgetCocoaImpl::DoListHitTest(const wxPoint& inpoint) const
622 // translate inpoint to listpoint via scrollview
623 NSPoint p = wxToNSPoint( m_osxView, inpoint );
624 p = [m_osxView convertPoint:p toView:m_tableView];
625 // hittest using new point
626 NSInteger i = [m_tableView rowAtPoint:p];
630 #endif // wxUSE_LISTBOX