]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/listbox.cpp
Do not emit a wxEVT_COMMAND_TEXT_UPDATED when the tab key is lifted (otherwise each...
[wxWidgets.git] / src / mac / carbon / listbox.cpp
index fa4e047e4850043f4fe6e051c146ba09638ca706..502651c1a45e2b083e6669718d16c242590e0afb 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     1998-01-01
 // RCS-ID:      $Id$
 // Copyright:   (c) Stefan Csomor
-// Licence:     wxWidgets licence
+// Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
@@ -27,8 +27,8 @@
 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
 
 BEGIN_EVENT_TABLE(wxListBox, wxControl)
-#if !__WXMAC_OSX__
-    EVT_SIZE( wxListBox::OnSize )
+#ifndef __WXMAC_OSX__
+//    EVT_SIZE( wxListBox::OnSize )
     EVT_CHAR( wxListBox::OnChar )
 #endif
 END_EVENT_TABLE()
@@ -39,28 +39,10 @@ END_EVENT_TABLE()
 const short kTextColumnId = 1024 ;
 
 // new databrowserbased version
-
-// Listbox item
-wxListBox::wxListBox()
-{
-  m_noItems = 0;
-  m_selected = 0;
-  m_macList = NULL ;
-}
-
-bool wxListBox::Create(wxWindow *parent, wxWindowID id,
-                       const wxPoint& pos,
-                       const wxSize& size,
-                       const wxArrayString& choices,
-                       long style,
-                       const wxValidator& validator,
-                       const wxString& name)
-{
-    wxCArrayString chs(choices);
-
-    return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
-                  style, validator, name);
-}
+// because of the limited insert
+// functionality of DataBrowser, 
+// we just introduce id s corresponding
+// to the line number
 
 #if TARGET_API_MAC_OSX
 static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID, 
@@ -74,46 +56,46 @@ static pascal  void DataBrowserItemNotificationProc(ControlRef browser, DataBrow
     if ( ref )
     {
         wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ;
-        for ( size_t i = 0 ; i < list->m_idArray.GetCount() ; ++i )
-            if ( list->m_idArray[i] == (long) itemID )
+        int i = itemID - 1 ;
+        if (i >= 0 && i < list->GetCount() )
+        {
+            bool trigger = false ;
+            wxCommandEvent event(
+                wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() );
+            switch( message )
             {
-                bool trigger = false ;
-                wxCommandEvent event(
-                    wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() );
-                switch( message )
-                {
-                    case kDataBrowserItemDeselected :
-                        if ( list->HasMultipleSelection() )
-                            trigger = true ;
-                        break ;
-                    case kDataBrowserItemSelected :
-                        trigger = true ;
-                        break ;
-                    case kDataBrowserItemDoubleClicked :
-                        event.SetEventType(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) ;
-                        trigger = true ;
-                        break ;
-                    default :
-                        break ;
-                }
-                if ( trigger )
-                {
-                    event.SetEventObject( list );
-                    if ( list->HasClientObjectData() )
-                        event.SetClientObject( list->GetClientObject(i) );
-                    else if ( list->HasClientUntypedData() )
-                        event.SetClientData( list->GetClientData(i) );
-                    event.SetString( list->GetString(i) );
-                    event.SetInt(i) ;
-                    event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : TRUE );
-                    list->GetEventHandler()->ProcessEvent(event) ;
-                } 
-                break ;
+                case kDataBrowserItemDeselected :
+                    if ( list->HasMultipleSelection() )
+                        trigger = !list->MacIsSelectionSuppressed() ;
+                    break ;
+                case kDataBrowserItemSelected :
+                    trigger = !list->MacIsSelectionSuppressed() ;
+                    break ;
+                case kDataBrowserItemDoubleClicked :
+                    event.SetEventType(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) ;
+                    trigger = true ;
+                    break ;
+                default :
+                    break ;
             }
+            if ( trigger )
+            {
+                event.SetEventObject( list );
+                if ( list->HasClientObjectData() )
+                    event.SetClientObject( list->GetClientObject(i) );
+                else if ( list->HasClientUntypedData() )
+                    event.SetClientData( list->GetClientData(i) );
+                event.SetString( list->GetString(i) );
+                event.SetInt(i) ;
+                event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : TRUE );
+                wxPostEvent( list->GetEventHandler() , event ) ;
+                // direct notification is not always having the listbox GetSelection() having in synch with event
+                // list->GetEventHandler()->ProcessEvent(event) ; 
+            } 
+        }
     }
 }
 
-
 static pascal OSStatus ListBoxGetSetItemData(ControlRef browser, 
     DataBrowserItemID itemID, DataBrowserPropertyID property, 
     DataBrowserItemDataRef itemData, Boolean changeValue)
@@ -131,14 +113,13 @@ static pascal OSStatus ListBoxGetSetItemData(ControlRef browser,
                    if ( ref )
                    {
                        wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ;
-                       for ( size_t i = 0 ; i < list->m_idArray.GetCount() ; ++i )
-                           if ( list->m_idArray[i] == (long) itemID )
-                           {
-                               wxMacCFStringHolder cf( list->GetString(i) , list->GetFont().GetEncoding() ) ;
-                               verify_noerr( ::SetDataBrowserItemDataText( itemData , cf ) ) ;
-                               err = noErr ;
-                               break ;
-                           }
+                    int i = itemID - 1 ;
+                    if (i >= 0 && i < list->GetCount() )
+                           {
+                               wxMacCFStringHolder cf( list->GetString(i) , list->GetFont().GetEncoding() ) ;
+                               verify_noerr( ::SetDataBrowserItemDataText( itemData , cf ) ) ;
+                               err = noErr ;
+                           }
                        }
                }       
                break;
@@ -151,6 +132,31 @@ static pascal OSStatus ListBoxGetSetItemData(ControlRef browser,
        
        return err;
 }
+
+
+// Listbox item
+wxListBox::wxListBox()
+{
+  m_noItems = 0;
+  m_selected = 0;
+  m_macList = NULL ;
+  m_suppressSelection = false ;
+}
+
+bool wxListBox::Create(wxWindow *parent, wxWindowID id,
+                       const wxPoint& pos,
+                       const wxSize& size,
+                       const wxArrayString& choices,
+                       long style,
+                       const wxValidator& validator,
+                       const wxString& name)
+{
+    wxCArrayString chs(choices);
+
+    return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
+                  style, validator, name);
+}
+
 bool wxListBox::Create(wxWindow *parent, wxWindowID id,
                        const wxPoint& pos,
                        const wxSize& size,
@@ -169,14 +175,11 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
 
     m_noItems = 0 ; // this will be increased by our append command
     m_selected = 0;
-    m_nextId = 1 ;
-    
 
     Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
-    ControlRef browser ;
 
-    verify_noerr( ::CreateDataBrowserControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds, kDataBrowserListView , (ControlRef *)&m_macControl ) );
-    browser = (ControlRef) m_macControl ;
+    m_peer = new wxMacControl() ;
+    verify_noerr( ::CreateDataBrowserControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds, kDataBrowserListView , m_peer->GetControlRefAddr() ) );
 
     DataBrowserSelectionFlags  options = kDataBrowserDragSelect ;
     if ( style & wxLB_MULTIPLE )
@@ -191,7 +194,7 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
     {
         options += kDataBrowserSelectOnlyOne ;
     }
-    verify_noerr(SetDataBrowserSelectionFlags  (browser, options ) ); 
+    verify_noerr(m_peer->SetSelectionFlags( options ) ); 
 
     DataBrowserListViewColumnDesc columnDesc ;
     columnDesc.headerBtnDesc.titleOffset = 0;
@@ -219,11 +222,11 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
         kDataBrowserTableViewSelectionColumn ;
 
        
-       verify_noerr(::AddDataBrowserListViewColumn(browser, &columnDesc, kDataBrowserListViewAppendColumn) ) ;
-    verify_noerr(::AutoSizeDataBrowserListViewColumns( browser ) ) ;
-    verify_noerr(::SetDataBrowserHasScrollBars( browser , false , true ) ) ;
-    verify_noerr(::SetDataBrowserTableViewHiliteStyle( browser, kDataBrowserTableViewFillHilite  ) ) ;
-    verify_noerr(::SetDataBrowserListViewHeaderBtnHeight( browser , 0 ) ) ;
+       verify_noerr(m_peer->AddListViewColumn( &columnDesc, kDataBrowserListViewAppendColumn) ) ;
+    verify_noerr(m_peer->AutoSizeListViewColumns() ) ;
+    verify_noerr(m_peer->SetHasScrollBars(false , true ) ) ;
+    verify_noerr(m_peer->SetTableViewHiliteStyle(kDataBrowserTableViewFillHilite  ) ) ;
+    verify_noerr(m_peer->SetListViewHeaderBtnHeight( 0 ) ) ;
     DataBrowserCallbacks callbacks ;
     
     callbacks.version = kDataBrowserLatestCallbacks;
@@ -239,8 +242,13 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
 #else
            NewDataBrowserItemNotificationUPP(DataBrowserItemNotificationProc) ;
 #endif
-    SetDataBrowserCallbacks(browser, &callbacks);
+    m_peer->SetCallbacks( &callbacks);
 
+#if TARGET_API_MAC_OSX
+    // there is a redraw bug in 10.2.X
+    if ( UMAGetSystemVersion() < 0x1030 )
+        m_peer->SetData( kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, (Boolean) false ) ;
+#endif
     MacPostControlCreate(pos,size) ;
 
     for ( int i = 0 ; i < n ; i++ )
@@ -255,7 +263,7 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
 
 wxListBox::~wxListBox()
 {
-    SetControlReference( (ControlRef) m_macControl , NULL ) ;
+    m_peer->SetReference( NULL ) ;
     FreeData() ;
     // avoid access during destruction
     if ( m_macList )
@@ -323,6 +331,8 @@ void wxListBox::Delete(int N)
 
 int wxListBox::DoAppend(const wxString& item)
 {
+    InvalidateBestSize();
+
     int index = m_noItems ;
     m_stringArray.Add( item ) ;
     m_dataArray.Add( NULL );
@@ -430,10 +440,13 @@ void wxListBox::Clear()
 
 void wxListBox::SetSelection(int N, bool select)
 {
-    wxCHECK_RET( N >= 0 && N < m_noItems,
+    wxCHECK_RET( N == wxNOT_FOUND || (N >= 0 && N < m_noItems) ,
         wxT("invalid index in wxListBox::SetSelection") );
-    MacSetSelection( N , select ) ;
-    GetSelections( m_selectionPreImage ) ;
+        
+    if ( N == wxNOT_FOUND )
+        MacDeselectAll() ;
+    else
+        MacSetSelection( N , select ) ;
 }
 
 bool wxListBox::IsSelected(int N) const
@@ -510,16 +523,17 @@ void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
     wxCHECK_RET( pos >= 0 && pos <= m_noItems,
         wxT("invalid index in wxListBox::InsertItems") );
     
+    InvalidateBestSize();
+
     int nItems = items.GetCount();
     
     for ( int i = 0 ; i < nItems ; i++ )
     {
         m_stringArray.Insert( items[i] , pos + i ) ;
         m_dataArray.Insert( NULL , pos + i ) ;
+        m_noItems++ ;
         MacInsert( pos + i , items[i] ) ;
     }
-    
-    m_noItems += nItems;
 }
 
 void wxListBox::SetString(int N, const wxString& s)
@@ -617,71 +631,127 @@ wxOwnerDrawn *wxListBox::CreateItem(size_t n)
 
 #endif  //USE_OWNER_DRAWN
 
+
+// Some custom controls depend on this
+/* static */ wxVisualAttributes
+wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+    wxVisualAttributes attr;
+    attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+    attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
+    attr.font  = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+    return attr;
+}
+
 // ============================================================================
 // list box control implementation
 // ============================================================================
 
-void wxListBox::MacDelete( int N )
+void wxListBox::MacDelete( int n )
 {
-    UInt32 id = m_idArray[N] ;
-    verify_noerr(::RemoveDataBrowserItems((ControlRef) m_macControl , kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) ) ;
-    m_idArray.RemoveAt( N ) ;
+    wxArrayInt selectionBefore ;
+    MacGetSelections( selectionBefore ) ;
+
+    UInt32 id = m_noItems+1 ;
+    verify_noerr( m_peer->RemoveItems( kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) ) ;
+    for ( size_t i = 0 ; i < selectionBefore.GetCount() ; ++i )
+    {
+        int current = selectionBefore[i] ;
+        if ( current == n )
+        {
+            // selection was deleted
+            MacSetSelection( current , false ) ;
+        }
+        else if ( current > n )
+        {
+            // something behind the deleted item was selected -> move up
+            MacSetSelection( current - 1 , true ) ;            
+            MacSetSelection( current , false ) ;
+        }
+    }
+    // refresh all
+    verify_noerr( m_peer->UpdateItems( kDataBrowserNoItem , 1 , (UInt32*) kDataBrowserNoItem , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) ) ;
 }
 
 void wxListBox::MacInsert( int n , const wxString& text)
 {
-    verify_noerr(::AddDataBrowserItems( (ControlRef) m_macControl , kDataBrowserNoItem , 1 , (UInt32*) &m_nextId , kDataBrowserItemNoProperty ) ) ;
-    m_idArray.Insert( m_nextId , n ) ;
-    ++m_nextId ;
+    wxArrayInt selectionBefore ;
+    MacGetSelections( selectionBefore ) ;
+
+    UInt32 id = m_noItems ; // this has already been increased
+    verify_noerr( m_peer->AddItems( kDataBrowserNoItem , 1 ,  (UInt32*) &id , kDataBrowserItemNoProperty ) ) ;
+
+    for ( int i = selectionBefore.GetCount()-1 ; i >= 0 ; --i )
+    {
+        int current = selectionBefore[i] ;
+        if ( current >= n )
+        {
+            MacSetSelection( current + 1 , true ) ;            
+            MacSetSelection( current , false ) ;
+        }
+    }
+
+    // refresh all
+    verify_noerr( m_peer->UpdateItems( kDataBrowserNoItem , 1 , (UInt32*) kDataBrowserNoItem , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) ) ;
 }
 
 void wxListBox::MacAppend( const wxString& text)
 {
-    verify_noerr(::AddDataBrowserItems( (ControlRef) m_macControl , kDataBrowserNoItem , 1 , (UInt32*) &m_nextId , kDataBrowserItemNoProperty ) ) ;
-    m_idArray.Add( m_nextId ) ;
-    ++m_nextId ;
+    UInt32 id = m_noItems ; // this has already been increased
+    verify_noerr( m_peer->AddItems( kDataBrowserNoItem , 1 ,  (UInt32*) &id , kDataBrowserItemNoProperty ) ) ;
+    // no need to deal with selections nor refreshed, as we have appended
 }
 
 void wxListBox::MacClear()
 {
-    verify_noerr(::RemoveDataBrowserItems((ControlRef) m_macControl , kDataBrowserNoItem , 0 , NULL , kDataBrowserItemNoProperty ) ) ;
-    m_idArray.Empty() ;
+    verify_noerr( m_peer->RemoveItems( kDataBrowserNoItem , 0 , NULL , kDataBrowserItemNoProperty ) ) ;
+}
+
+void wxListBox::MacDeselectAll() 
+{
+    bool former = MacSuppressSelection( true ) ;
+    verify_noerr(m_peer->SetSelectedItems( 0 , NULL , kDataBrowserItemsRemove ) ) ;
+    MacSuppressSelection( former ) ;
 }
 
 void wxListBox::MacSetSelection( int n , bool select )
 {
-    UInt32 id = m_idArray[n] ;
-    if ( !(GetWindowStyle() & (wxLB_MULTIPLE|wxLB_EXTENDED) ) )
-    {
-        int n = MacGetSelection() ;
-        if ( n >= 0 )
-        {
-            UInt32 idOld = m_idArray[n] ;
-            SetDataBrowserSelectedItems((ControlRef) m_macControl , 1 , & idOld , kDataBrowserItemsRemove ) ;
-        }
-    }
-    if ( ::IsDataBrowserItemSelected( (ControlRef) m_macControl , id ) != select )
+    bool former = MacSuppressSelection( true ) ;
+    UInt32 id = n + 1 ;
+
+    if ( m_peer->IsItemSelected( id ) != select )
     {
-        verify_noerr(::SetDataBrowserSelectedItems((ControlRef) m_macControl , 1 , & id , kDataBrowserItemsToggle ) ) ;
+        if ( select )
+            verify_noerr(m_peer->SetSelectedItems( 1 , & id , HasMultipleSelection() ? kDataBrowserItemsAdd : kDataBrowserItemsAssign ) ) ;
+        else
+            verify_noerr(m_peer->SetSelectedItems( 1 , & id , kDataBrowserItemsRemove ) ) ;
     }
     MacScrollTo( n ) ;
+    MacSuppressSelection( former ) ;
+}
+
+bool  wxListBox::MacSuppressSelection( bool suppress ) 
+{
+       bool former = m_suppressSelection ;
+       m_suppressSelection = suppress ;
+       return former ;
 }
 
 bool wxListBox::MacIsSelected( int n ) const
 {
-    return ::IsDataBrowserItemSelected( (ControlRef) m_macControl , m_idArray[n] ) ;
+    return m_peer->IsItemSelected( n + 1 ) ;
 }
 
 int wxListBox::MacGetSelection() const
 {
-    for ( size_t i = 0 ; i < m_idArray.GetCount() ; ++i )
+    for ( int i = 0 ; i < GetCount() ; ++i )
     {
-        if ( ::IsDataBrowserItemSelected((ControlRef) m_macControl , m_idArray[i] ) )
+        if ( m_peer->IsItemSelected( i + 1 ) )
         {
             return i ;
         }
     }
-        return -1 ;
+    return -1 ;
 }
 
 int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const
@@ -689,12 +759,18 @@ int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const
     int no_sel = 0 ;
     
     aSelections.Empty();
-    for ( size_t i = 0 ; i < m_idArray.GetCount() ; ++i )
+    
+    UInt32 first , last ;
+    m_peer->GetSelectionAnchor( &first , &last ) ;
+    if ( first != kDataBrowserNoItem )
     {
-        if ( ::IsDataBrowserItemSelected((ControlRef) m_macControl , m_idArray[i] ) )
+        for ( size_t i = first ; i <= last ; ++i )
         {
-            aSelections.Add( i ) ;
-            no_sel++ ;
+            if ( m_peer->IsItemSelected( i ) )
+            {
+                aSelections.Add( i - 1 ) ;
+                no_sel++ ;
+            }
         }
     }
     return no_sel ;
@@ -703,82 +779,14 @@ int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const
 void wxListBox::MacSet( int n , const wxString& text )
 {
     // as we don't store the strings we only have to issue a redraw
-    UInt32 id = m_idArray[n] ;
-    verify_noerr( ::UpdateDataBrowserItems( (ControlRef) m_macControl , kDataBrowserNoItem , 1 , &id , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) ) ;
+    UInt32 id = n + 1 ;
+    verify_noerr( m_peer->UpdateItems( kDataBrowserNoItem , 1 , &id , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) ) ;
 }
 
 void wxListBox::MacScrollTo( int n )
 {
-    UInt32 id = m_idArray[n] ;
-    verify_noerr( ::RevealDataBrowserItem((ControlRef) m_macControl , id , kTextColumnId , kDataBrowserRevealWithoutSelecting ) ) ;
-}
-
-#if !TARGET_API_MAC_OSX
-void wxListBox::OnSize( wxSizeEvent &event)
-{
-}
-#endif
-
-void wxListBox::MacSetRedraw( bool doDraw )
-{
-    // nothing to do in compositing mode
-}
-
-void wxListBox::MacDoClick()
-{/*
-    wxArrayInt aSelections;
-    int n ;
-    size_t count = GetSelections(aSelections);
-    
-    if ( count == m_selectionPreImage.GetCount() )
-    {
-        bool hasChanged = false ;
-        for ( size_t i = 0 ; i < count ; ++i )
-        {
-            if ( aSelections[i] != m_selectionPreImage[i] )
-            {
-                hasChanged = true ;
-                break ;
-            }
-        }
-        if ( !hasChanged )
-        {
-            return ;
-        }
-    }
-    
-    m_selectionPreImage = aSelections;
-    
-    wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId);
-    event.SetEventObject( this );
-    
-    if ( count > 0 )
-    {
-        n = aSelections[0];
-        if ( HasClientObjectData() )
-            event.SetClientObject( GetClientObject(n) );
-        else if ( HasClientUntypedData() )
-            event.SetClientData( GetClientData(n) );
-        event.SetString( GetString(n) );
-    }
-    else
-    {
-        n = -1;
-    }
-    
-    event.m_commandInt = n;
-    
-    GetEventHandler()->ProcessEvent(event);
-*/
-}
-
-void wxListBox::MacDoDoubleClick()
-{
-/*
-    wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, m_windowId);
-    event.SetEventObject( this );
-    GetEventHandler()->ProcessEvent(event) ;
-*/
+    UInt32 id = n + 1 ;
+    verify_noerr(  m_peer->RevealItem( id , kTextColumnId , kDataBrowserRevealWithoutSelecting ) ) ;
 }
 
 #if !TARGET_API_MAC_OSX
@@ -856,7 +864,7 @@ void wxListBox::OnChar(wxKeyEvent& event)
             n = -1;
         }
         
-        event.m_commandInt = n;
+        event.SetInt(n);
         
         GetEventHandler()->ProcessEvent(event);
     }
@@ -883,7 +891,7 @@ void wxListBox::OnChar(wxKeyEvent& event)
                     event.SetClientData( GetClientData(line) );
                 event.SetString( GetString(line) );
                 
-                event.m_commandInt = line ;
+                event.SetInt(line);
                 
                 GetEventHandler()->ProcessEvent(event);
             }