X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2126732187091fcdb61329b9ba2821627469f44a..60372b0d54379701d62edf5595a7dc25c48330e1:/src/osx/cocoa/listbox.mm diff --git a/src/osx/cocoa/listbox.mm b/src/osx/cocoa/listbox.mm index 94d57afad6..4b10d40656 100644 --- a/src/osx/cocoa/listbox.mm +++ b/src/osx/cocoa/listbox.mm @@ -4,7 +4,7 @@ // Author: Stefan Csomor // Modified by: // Created: 1998-01-01 -// RCS-ID: $Id: listbox.cpp 54820 2008-07-29 20:04:11Z SC $ +// RCS-ID: $Id$ // Copyright: (c) Stefan Csomor // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// @@ -14,6 +14,7 @@ #if wxUSE_LISTBOX #include "wx/listbox.h" +#include "wx/dnd.h" #ifndef WX_PRECOMP #include "wx/log.h" @@ -32,19 +33,19 @@ class wxListWidgetCocoaImpl; -@interface wxNSTableDataSource : NSObject +@interface wxNSTableDataSource : NSObject wxOSX_10_6_AND_LATER() { wxListWidgetCocoaImpl* impl; } -- (id)tableView:(NSTableView *)aTableView - objectValueForTableColumn:(NSTableColumn *)aTableColumn +- (id)tableView:(NSTableView *)aTableView + objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex; -- (id)tableView:(NSTableView *)aTableView - setObjectValue:(NSTableColumn *)aTableColumn +- (void)tableView:(NSTableView *)aTableView + setObjectValue:(id)value forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex; - + - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView; - (void)setImplementation: (wxListWidgetCocoaImpl *) theImplementation; @@ -52,16 +53,10 @@ class wxListWidgetCocoaImpl; @end -@interface wxNSTableView : NSTableView +@interface wxNSTableView : NSTableView wxOSX_10_6_AND_LATER() { - wxListWidgetCocoaImpl* impl; } -- (void)setImplementation: (wxListWidgetCocoaImpl *) theImplementation; -- (wxListWidgetCocoaImpl*) implementation; -- (void)clickedAction: (id) sender; -- (void)doubleClickedAction: (id) sender; - @end // @@ -84,19 +79,19 @@ class wxCocoaTableColumn; class WXDLLIMPEXP_CORE wxCocoaTableColumn : public wxListWidgetColumn { public : - wxCocoaTableColumn( wxNSTableColumn* column, bool editable ) + wxCocoaTableColumn( wxNSTableColumn* column, bool editable ) : m_column( column ), m_editable(editable) { } - + ~wxCocoaTableColumn() { } - + wxNSTableColumn* GetNSTableColumn() const { return m_column ; } - + bool IsEditable() const { return m_editable; } - + protected : wxNSTableColumn* m_column; bool m_editable; @@ -108,31 +103,31 @@ class wxListWidgetCocoaImpl : public wxWidgetCocoaImpl, public wxListWidgetImpl { public : wxListWidgetCocoaImpl( wxWindowMac* peer, NSScrollView* view, wxNSTableView* tableview, wxNSTableDataSource* data ); - + ~wxListWidgetCocoaImpl(); - - virtual wxListWidgetColumn* InsertTextColumn( unsigned pos, const wxString& title, bool editable = false, + + virtual wxListWidgetColumn* InsertTextColumn( unsigned pos, const wxString& title, bool editable = false, wxAlignment just = wxALIGN_LEFT , int defaultWidth = -1) ; - virtual wxListWidgetColumn* InsertCheckColumn( unsigned pos , const wxString& title, bool editable = false, + virtual wxListWidgetColumn* InsertCheckColumn( unsigned pos , const wxString& title, bool editable = false, wxAlignment just = wxALIGN_LEFT , int defaultWidth = -1) ; - + // add and remove - - virtual void ListDelete( unsigned int n ) ; + + virtual void ListDelete( unsigned int n ) ; virtual void ListInsert( unsigned int n ) ; virtual void ListClear() ; // selecting virtual void ListDeselectAll(); - + virtual void ListSetSelection( unsigned int n, bool select, bool multi ) ; virtual int ListGetSelection() const ; - + virtual int ListGetSelections( wxArrayInt& aSelections ) const ; - + virtual bool ListIsSelected( unsigned int n ) const ; - + // display virtual void ListScrollTo( unsigned int n ) ; @@ -140,16 +135,21 @@ public : // accessing content virtual unsigned int ListGetCount() const ; - + virtual int DoListHitTest( const wxPoint& inpoint ) const; + int ListGetColumnType( int col ) { return col; } virtual void UpdateLine( unsigned int n, wxListWidgetColumn* col = NULL ) ; virtual void UpdateLineToEnd( unsigned int n); + + virtual void controlDoubleAction(WXWidget slf, void* _cmd, void *sender); + + protected : wxNSTableView* m_tableView ; - + wxNSTableDataSource* m_dataSource; } ; @@ -161,7 +161,7 @@ protected : - (id) init { - [super init]; + self = [super init]; column = nil; return self; } @@ -184,38 +184,38 @@ public : wxNSTableViewCellValue( id &v ) : value(v) { } - + virtual ~wxNSTableViewCellValue() {} virtual void Set( CFStringRef v ) { value = [[(NSString*)v retain] autorelease]; } - virtual void Set( const wxString& value ) + virtual void Set( const wxString& value ) { Set( (CFStringRef) wxCFStringRef( value ) ); } - virtual void Set( int v ) + virtual void Set( int v ) { value = [NSNumber numberWithInt:v]; } - - virtual int GetIntValue() const + + virtual int GetIntValue() const { if ( [value isKindOfClass:[NSNumber class]] ) return [ (NSNumber*) value intValue ]; - + return 0; } - - virtual wxString GetStringValue() const + + virtual wxString GetStringValue() const { if ( [value isKindOfClass:[NSString class]] ) - return wxCFStringRef( (CFStringRef) [value retain] ).AsString(); - + return wxCFStringRef::AsString( (NSString*) value ); + return wxEmptyString; } - + protected: id& value; } ; @@ -224,7 +224,7 @@ protected: - (id) init { - [super init]; + self = [super init]; impl = nil; return self; } @@ -241,15 +241,17 @@ protected: - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { + wxUnusedVar(aTableView); if ( impl ) return impl->ListGetCount(); return 0; } -- (id)tableView:(NSTableView *)aTableView - objectValueForTableColumn:(NSTableColumn *)aTableColumn +- (id)tableView:(NSTableView *)aTableView + objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { + wxUnusedVar(aTableView); wxNSTableColumn* tablecol = (wxNSTableColumn *)aTableColumn; wxListBox* lb = dynamic_cast(impl->GetWXPeer()); wxCocoaTableColumn* col = [tablecol column]; @@ -259,10 +261,11 @@ protected: return value; } -- (void)tableView:(NSTableView *)aTableView - setObjectValue:(id)value forTableColumn:(NSTableColumn *)aTableColumn +- (void)tableView:(NSTableView *)aTableView + setObjectValue:(id)value forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { + wxUnusedVar(aTableView); wxNSTableColumn* tablecol = (wxNSTableColumn *)aTableColumn; wxListBox* lb = dynamic_cast(impl->GetWXPeer()); wxCocoaTableColumn* col = [tablecol column]; @@ -274,57 +277,42 @@ protected: @implementation wxNSTableView -- (void)setImplementation: (wxListWidgetCocoaImpl *) theImplementation ++ (void)initialize { - impl = theImplementation; -} - -- (wxListWidgetCocoaImpl*) implementation -{ - return impl; -} - -- (id) init -{ - [super init]; - impl = NULL; - [self setTarget: self]; - [self setAction: @selector(clickedAction:)]; - [self setDoubleAction: @selector(doubleClickedAction:)]; - return self; -} - -- (void) clickedAction: (id) sender -{ - if ( impl ) + static BOOL initialized = NO; + if (!initialized) { - wxListBox *list = static_cast ( impl->GetWXPeer()); - wxCHECK_RET( list != NULL , wxT("Listbox expected")); - - wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() ); - - int sel = [self clickedRow]; - if ((sel < 0) || (sel > (int) list->GetCount())) // OS X can select an item below the last item (why?) - return; - - list->HandleLineEvent( sel, false ); + initialized = YES; + wxOSXCocoaClassAddWXMethods( self ); } } -- (void) doubleClickedAction: (id) sender +- (void) tableViewSelectionDidChange: (NSNotification *) notification { - if ( impl ) + wxUnusedVar(notification); + + int row = [self selectedRow]; + + if (row == -1) { + // no row selected + } + else + { + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); wxListBox *list = static_cast ( impl->GetWXPeer()); wxCHECK_RET( list != NULL , wxT("Listbox expected")); - - int sel = [self clickedRow]; - if ((sel < 0) || (sel > (int) list->GetCount())) // OS X can select an item below the last item (why?) - return; - - list->HandleLineEvent( sel, true ); + + wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() ); + + if ((row < 0) || (row > (int) list->GetCount())) // OS X can select an item below the last item + return; + + if ( !list->MacGetBlockEvents() ) + list->HandleLineEvent( row, false ); } -} + +} @end @@ -335,6 +323,7 @@ protected: wxListWidgetCocoaImpl::wxListWidgetCocoaImpl( wxWindowMac* peer, NSScrollView* view, wxNSTableView* tableview, wxNSTableDataSource* data ) : wxWidgetCocoaImpl( peer, view ), m_tableView(tableview), m_dataSource(data) { + InstallEventHandler( tableview ); } wxListWidgetCocoaImpl::~wxListWidgetCocoaImpl() @@ -342,7 +331,7 @@ wxListWidgetCocoaImpl::~wxListWidgetCocoaImpl() [m_dataSource release]; } -unsigned int wxListWidgetCocoaImpl::ListGetCount() const +unsigned int wxListWidgetCocoaImpl::ListGetCount() const { wxListBox* lb = dynamic_cast ( GetWXPeer() ); return lb->GetCount(); @@ -352,25 +341,34 @@ unsigned int wxListWidgetCocoaImpl::ListGetCount() const // columns // -wxListWidgetColumn* wxListWidgetCocoaImpl::InsertTextColumn( unsigned pos, const wxString& title, bool editable, - wxAlignment just, int defaultWidth) +wxListWidgetColumn* wxListWidgetCocoaImpl::InsertTextColumn( unsigned pos, const wxString& WXUNUSED(title), bool editable, + wxAlignment WXUNUSED(just), int defaultWidth) { wxNSTableColumn* col1 = [[wxNSTableColumn alloc] init]; [col1 setEditable:editable]; - + unsigned formerColCount = [m_tableView numberOfColumns]; - + // there's apparently no way to insert at a specific position [m_tableView addTableColumn:col1 ]; if ( pos < formerColCount ) [m_tableView moveColumn:formerColCount toColumn:pos]; - + if ( defaultWidth >= 0 ) { [col1 setMaxWidth:defaultWidth]; [col1 setMinWidth:defaultWidth]; + [col1 setWidth:defaultWidth]; } - + else + { + [col1 setMaxWidth:1000]; + [col1 setMinWidth:10]; + // temporary hack, because I cannot get the automatic column resizing + // to work properly + [col1 setWidth:1000]; + } + [col1 setResizingMask: NSTableColumnAutoresizingMask]; wxCocoaTableColumn* wxcol = new wxCocoaTableColumn( col1, editable ); [col1 setColumn:wxcol]; @@ -379,32 +377,34 @@ wxListWidgetColumn* wxListWidgetCocoaImpl::InsertTextColumn( unsigned pos, const return wxcol; } -wxListWidgetColumn* wxListWidgetCocoaImpl::InsertCheckColumn( unsigned pos , const wxString& title, bool editable, - wxAlignment just, int defaultWidth ) +wxListWidgetColumn* wxListWidgetCocoaImpl::InsertCheckColumn( unsigned pos , const wxString& WXUNUSED(title), bool editable, + wxAlignment WXUNUSED(just), int defaultWidth ) { wxNSTableColumn* col1 = [[wxNSTableColumn alloc] init]; [col1 setEditable:editable]; - + // set your custom cell & set it up NSButtonCell* checkbox = [[NSButtonCell alloc] init]; [checkbox setTitle:@""]; [checkbox setButtonType:NSSwitchButton]; [col1 setDataCell:checkbox] ; [checkbox release]; - + unsigned formerColCount = [m_tableView numberOfColumns]; - + // there's apparently no way to insert at a specific position [m_tableView addTableColumn:col1 ]; if ( pos < formerColCount ) [m_tableView moveColumn:formerColCount toColumn:pos]; - + if ( defaultWidth >= 0 ) { [col1 setMaxWidth:defaultWidth]; [col1 setMinWidth:defaultWidth]; + [col1 setWidth:defaultWidth]; } - + + [col1 setResizingMask: NSTableColumnNoResizing]; wxCocoaTableColumn* wxcol = new wxCocoaTableColumn( col1, editable ); [col1 setColumn:wxcol]; @@ -418,36 +418,17 @@ wxListWidgetColumn* wxListWidgetCocoaImpl::InsertCheckColumn( unsigned pos , con // inserting / removing lines // -void wxListWidgetCocoaImpl::ListInsert( unsigned int n ) +void wxListWidgetCocoaImpl::ListInsert( unsigned int WXUNUSED(n) ) { -#if 0 - { - wxListBoxCocoaLine* line = new wxListBoxCocoaLine(); - line->SetLabel(items[i]); - if ( m_items.size() <= n+i ) - m_items.push_back( line ); - else - m_items.insert(m_items.begin()+n, line); -/* - NSMutableDictionary* line = [[NSMutableDictionary alloc] init]; - [line setObject:wxCFStringRef(items[i]).AsNSString() forKey:column1]; - NSMutableArray* array = [m_dataSource items]; - if ( [array count] <= n+i ) - [array addObject:line]; - else - [array insertObject:line atIndex:n]; -*/ - } -#endif [m_tableView reloadData]; } -void wxListWidgetCocoaImpl::ListDelete( unsigned int n ) +void wxListWidgetCocoaImpl::ListDelete( unsigned int WXUNUSED(n) ) { [m_tableView reloadData]; } -void wxListWidgetCocoaImpl::ListClear() +void wxListWidgetCocoaImpl::ListClear() { [m_tableView reloadData]; } @@ -459,22 +440,23 @@ void wxListWidgetCocoaImpl::ListDeselectAll() [m_tableView deselectAll:nil]; } -void wxListWidgetCocoaImpl::ListSetSelection( unsigned int n, bool select, bool multi ) +void wxListWidgetCocoaImpl::ListSetSelection( unsigned int n, bool select, bool multi ) { // TODO if ( select ) - [m_tableView selectRow: n byExtendingSelection:multi]; + [m_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:n] + byExtendingSelection:multi]; else [m_tableView deselectRow: n]; } -int wxListWidgetCocoaImpl::ListGetSelection() const +int wxListWidgetCocoaImpl::ListGetSelection() const { return [m_tableView selectedRow]; } -int wxListWidgetCocoaImpl::ListGetSelections( wxArrayInt& aSelections ) const +int wxListWidgetCocoaImpl::ListGetSelections( wxArrayInt& aSelections ) const { aSelections.Empty(); @@ -482,186 +464,112 @@ int wxListWidgetCocoaImpl::ListGetSelections( wxArrayInt& aSelections ) const for ( int i = 0; i < count; ++i) { - if ([m_tableView isRowSelected:count]) + if ([m_tableView isRowSelected:i]) aSelections.Add(i); } return aSelections.Count(); } -bool wxListWidgetCocoaImpl::ListIsSelected( unsigned int n ) const +bool wxListWidgetCocoaImpl::ListIsSelected( unsigned int n ) const { return [m_tableView isRowSelected:n]; } // display -void wxListWidgetCocoaImpl::ListScrollTo( unsigned int n ) +void wxListWidgetCocoaImpl::ListScrollTo( unsigned int n ) { [m_tableView scrollRowToVisible:n]; } - -void wxListWidgetCocoaImpl::UpdateLine( unsigned int n, wxListWidgetColumn* col ) + +void wxListWidgetCocoaImpl::UpdateLine( unsigned int WXUNUSED(n), wxListWidgetColumn* WXUNUSED(col) ) { // TODO optimize [m_tableView reloadData]; } -void wxListWidgetCocoaImpl::UpdateLineToEnd( unsigned int n) +void wxListWidgetCocoaImpl::UpdateLineToEnd( unsigned int WXUNUSED(n)) { // TODO optimize [m_tableView reloadData]; } +void wxListWidgetCocoaImpl::controlDoubleAction(WXWidget WXUNUSED(slf),void* WXUNUSED(_cmd), void *WXUNUSED(sender)) +{ + wxListBox *list = static_cast ( GetWXPeer()); + wxCHECK_RET( list != NULL , wxT("Listbox expected")); + + int sel = [m_tableView clickedRow]; + if ((sel < 0) || (sel > (int) list->GetCount())) // OS X can select an item below the last item (why?) + return; + + list->HandleLineEvent( sel, true ); +} // accessing content -wxWidgetImplType* wxWidgetImpl::CreateListBox( wxWindowMac* wxpeer, - wxWindowMac* parent, - wxWindowID id, - const wxPoint& pos, +wxWidgetImplType* wxWidgetImpl::CreateListBox( wxWindowMac* wxpeer, + wxWindowMac* WXUNUSED(parent), + wxWindowID WXUNUSED(id), + const wxPoint& pos, const wxSize& size, - long style, - long extraStyle) + long style, + long WXUNUSED(extraStyle)) { NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; NSScrollView* scrollview = [[NSScrollView alloc] initWithFrame:r]; - + // use same scroll flags logic as msw - + [scrollview setHasVerticalScroller:YES]; - + if ( style & wxLB_HSCROLL ) [scrollview setHasHorizontalScroller:YES]; - + [scrollview setAutohidesScrollers: ((style & wxLB_ALWAYS_SB) ? NO : YES)]; - + // setting up the true table - + wxNSTableView* tableview = [[wxNSTableView alloc] init]; - [scrollview setDocumentView:tableview]; - [tableview release]; - + [tableview setDelegate:tableview]; // only one multi-select mode available if ( (style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE) ) [tableview setAllowsMultipleSelection:YES]; - + // simple listboxes have no header row [tableview setHeaderView:nil]; - - [tableview setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle]; + + if ( style & wxLB_HSCROLL ) + [tableview setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing]; + else + [tableview setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle]; + wxNSTableDataSource* ds = [[ wxNSTableDataSource alloc] init]; [tableview setDataSource:ds]; + [scrollview setDocumentView:tableview]; + [tableview release]; + wxListWidgetCocoaImpl* c = new wxListWidgetCocoaImpl( wxpeer, scrollview, tableview, ds ); - [tableview setImplementation:c]; + + // temporary hook for dnd + [tableview registerForDraggedTypes:[NSArray arrayWithObjects: + NSStringPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]]; + [ds setImplementation:c]; return c; } -int wxListBox::DoListHitTest(const wxPoint& inpoint) const -{ -#if wxOSX_USE_CARBON - OSStatus err; - - // There are few reasons why this is complicated: - // 1) There is no native HitTest function for Mac - // 2) GetDataBrowserItemPartBounds only works on visible items - // 3) We can't do it through GetDataBrowserTableView[Item]RowHeight - // because what it returns is basically inaccurate in the context - // of the coordinates we want here, but we use this as a guess - // for where the first visible item lies - - wxPoint point = inpoint; - - // get column property ID (req. for call to itempartbounds) - DataBrowserTableViewColumnID colId = 0; - err = GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId); - wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewColumnProperty")); - - // OK, first we need to find the first visible item we have - - // this will be the "low" for our binary search. There is no real - // easy way around this, as we will need to do a SLOW linear search - // until we find a visible item, but we can do a cheap calculation - // via the row height to speed things up a bit - UInt32 scrollx, scrolly; - err = GetDataBrowserScrollPosition(m_peer->GetControlRef(), &scrollx, &scrolly); - wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserScrollPosition")); - - UInt16 height; - err = GetDataBrowserTableViewRowHeight(m_peer->GetControlRef(), &height); - wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewRowHeight")); - - // these indices are 0-based, as usual, so we need to add 1 to them when - // passing them to data browser functions which use 1-based indices - int low = scrolly / height, - high = GetCount() - 1; - - // search for the first visible item (note that the scroll guess above - // is the low bounds of where the item might lie so we only use that as a - // starting point - we should reach it within 1 or 2 iterations of the loop) - while ( low <= high ) - { - Rect bounds; - err = GetDataBrowserItemPartBounds( - m_peer->GetControlRef(), low + 1, colId, - kDataBrowserPropertyEnclosingPart, - &bounds); // note +1 to translate to Mac ID - if ( err == noErr ) - break; - - // errDataBrowserItemNotFound is expected as it simply means that the - // item is not currently visible -- but other errors are not - wxCHECK_MSG( err == errDataBrowserItemNotFound, wxNOT_FOUND, - wxT("Unexpected error from GetDataBrowserItemPartBounds") ); - - low++; - } - - // NOW do a binary search for where the item lies, searching low again if - // we hit an item that isn't visible - while ( low <= high ) - { - int mid = (low + high) / 2; - - Rect bounds; - err = GetDataBrowserItemPartBounds( - m_peer->GetControlRef(), mid + 1, colId, - kDataBrowserPropertyEnclosingPart, - &bounds); //note +1 to trans to mac id - wxCHECK_MSG( err == noErr || err == errDataBrowserItemNotFound, - wxNOT_FOUND, - wxT("Unexpected error from GetDataBrowserItemPartBounds") ); - - if ( err == errDataBrowserItemNotFound ) - { - // item not visible, attempt to find a visible one - // search lower - high = mid - 1; - } - else // visible item, do actual hitttest - { - // if point is within the bounds, return this item (since we assume - // all x coords of items are equal we only test the x coord in - // equality) - if ((point.x >= bounds.left && point.x <= bounds.right) && - (point.y >= bounds.top && point.y <= bounds.bottom) ) - { - // found! - return mid; - } - - if ( point.y < bounds.top ) - // index(bounds) greater then key(point) - high = mid - 1; - else - // index(bounds) less then key(point) - low = mid + 1; - } - } -#endif - return wxNOT_FOUND; +int wxListWidgetCocoaImpl::DoListHitTest(const wxPoint& inpoint) const +{ + // translate inpoint to listpoint via scrollview + NSPoint p = wxToNSPoint( m_osxView, inpoint ); + p = [m_osxView convertPoint:p toView:m_tableView]; + // hittest using new point + NSInteger i = [m_tableView rowAtPoint:p]; + return i; } #endif // wxUSE_LISTBOX