X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c00fed0ef4d70c9b45d9b8405f636d30eadb7ea6..5aa67d6619d7758bd66375ef75b698ae49f3418b:/src/mac/carbon/listbox.cpp?ds=sidebyside diff --git a/src/mac/carbon/listbox.cpp b/src/mac/carbon/listbox.cpp index 1dc7a3c2e4..93701b90f8 100644 --- a/src/mac/carbon/listbox.cpp +++ b/src/mac/carbon/listbox.cpp @@ -60,7 +60,7 @@ static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrows { wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ; int i = itemID - 1 ; - if (i >= 0 && i < list->GetCount() ) + if (i >= 0 && i < (int)list->GetCount() ) { bool trigger = false ; wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() ); @@ -119,7 +119,7 @@ static pascal OSStatus ListBoxGetSetItemData(ControlRef browser, { wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ; int i = itemID - 1 ; - if (i >= 0 && i < list->GetCount() ) + if (i >= 0 && i < (int)list->GetCount() ) { wxMacCFStringHolder cf( list->GetString( i ) , list->GetFont().GetEncoding() ) ; verify_noerr( ::SetDataBrowserItemDataText( itemData , cf ) ) ; @@ -326,7 +326,7 @@ void wxListBox::FreeData() { if ( HasClientObjectData() ) { - for ( size_t n = 0; n < (size_t)m_noItems; n++ ) + for ( size_t n = 0; n < m_noItems; n++ ) { delete GetClientObject( n ); } @@ -347,7 +347,7 @@ void wxListBox::DoSetFirstItem(int n) void wxListBox::Delete(int n) { - wxCHECK_RET( n >= 0 && n < m_noItems, + wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::Delete") ); if ( HasClientObjectData() ) @@ -364,7 +364,7 @@ int wxListBox::DoAppend(const wxString& item) { InvalidateBestSize(); - int index = m_noItems ; + size_t index = m_noItems ; m_stringArray.Add( item ) ; m_dataArray.Add( NULL ); m_noItems++; @@ -377,9 +377,9 @@ int wxListBox::DoAppend(const wxString& item) void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) { Clear() ; - int n = choices.GetCount(); + size_t n = choices.GetCount(); - for ( int i = 0 ; i < n ; ++i ) + for ( size_t i = 0 ; i < n ; ++i ) { if ( clientData ) Append( choices[i] , clientData[i] ) ; @@ -392,28 +392,28 @@ int wxListBox::FindString(const wxString& s, bool bCase) const { if ( s.Right(1) == wxT("*") ) { - wxString search = s.Left( s.Length() - 1 ) ; - int len = search.Length() ; + wxString search = s.Left( s.length() - 1 ) ; + int len = search.length() ; Str255 s1 , s2 ; wxMacStringToPascal( search , s2 ) ; - for ( int i = 0 ; i < m_noItems ; ++ i ) + for ( size_t i = 0 ; i < m_noItems ; ++ i ) { wxMacStringToPascal( m_stringArray[i].Left( len ) , s1 ) ; if ( EqualString( s1 , s2 , bCase , false ) ) - return i ; + return (int)i; } - if ( s.Left(1) == wxT("*") && s.Length() > 1 ) + if ( s.Left(1) == wxT("*") && s.length() > 1 ) { wxString st = s ; st.MakeLower() ; - for ( int i = 0 ; i < m_noItems ; ++i ) + for ( size_t i = 0 ; i < m_noItems ; ++i ) { if ( GetString( i ).Lower().Matches(st) ) - return i ; + return (int)i ; } } } @@ -423,12 +423,12 @@ int wxListBox::FindString(const wxString& s, bool bCase) const wxMacStringToPascal( s , s2 ) ; - for ( int i = 0 ; i < m_noItems ; ++ i ) + for ( size_t i = 0 ; i < m_noItems ; ++ i ) { wxMacStringToPascal( m_stringArray[i] , s1 ) ; if ( EqualString( s1 , s2 , bCase , false ) ) - return i ; + return (int)i ; } } @@ -446,7 +446,7 @@ void wxListBox::Clear() void wxListBox::DoSetSelection(int n, bool select) { - wxCHECK_RET( n == wxNOT_FOUND || (n >= 0 && n < m_noItems) , + wxCHECK_RET( n == wxNOT_FOUND || IsValid(n) , wxT("invalid index in wxListBox::SetSelection") ); if ( n == wxNOT_FOUND ) @@ -457,7 +457,7 @@ void wxListBox::DoSetSelection(int n, bool select) bool wxListBox::IsSelected(int n) const { - wxCHECK_MSG( n >= 0 && n < m_noItems, false, + wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxListBox::Selected") ); return MacIsSelected( n ) ; @@ -465,8 +465,9 @@ bool wxListBox::IsSelected(int n) const void *wxListBox::DoGetItemClientData(int n) const { - wxCHECK_MSG( n >= 0 && n < m_noItems, NULL, - wxT("invalid index in wxListBox::GetClientData")); + wxCHECK_MSG( IsValid(n), NULL, wxT("invalid index in wxListBox::GetClientData")); + + wxASSERT_MSG( m_dataArray.GetCount() >= (size_t) n , wxT("invalid client_data array") ) ; return (void *)m_dataArray[n]; } @@ -478,8 +479,7 @@ wxClientData *wxListBox::DoGetItemClientObject(int n) const void wxListBox::DoSetItemClientData(int n, void *clientData) { - wxCHECK_RET( n >= 0 && n < m_noItems, - wxT("invalid index in wxListBox::SetClientData") ); + wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetClientData") ); wxASSERT_MSG( m_dataArray.GetCount() >= (size_t) n , wxT("invalid client_data array") ) ; @@ -509,7 +509,7 @@ int wxListBox::GetSelection() const // Find string for position wxString wxListBox::GetString(int n) const { - wxCHECK_MSG( n >= 0 && n < m_noItems, wxEmptyString, + wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("invalid index in wxListBox::GetString") ); return m_stringArray[n] ; @@ -517,14 +517,14 @@ wxString wxListBox::GetString(int n) const void wxListBox::DoInsertItems(const wxArrayString& items, int pos) { - wxCHECK_RET( pos >= 0 && pos <= m_noItems, + wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") ); InvalidateBestSize(); - int nItems = items.GetCount(); + size_t nItems = items.GetCount(); - for ( int i = 0 ; i < nItems ; i++ ) + for ( size_t i = 0 ; i < nItems ; i++ ) { m_stringArray.Insert( items[i] , pos + i ) ; m_dataArray.Insert( NULL , pos + i ) ; @@ -563,7 +563,7 @@ wxSize wxListBox::DoGetBestSize() const } // Find the widest line - for (int i = 0; i < GetCount(); i++) + for (size_t i = 0; i < GetCount(); i++) { wxString str( GetString( i ) ); @@ -581,7 +581,7 @@ wxSize wxListBox::DoGetBestSize() const &baseline ); wLine = bounds.h ; #else - wLine = ::TextWidth( str.c_str() , 0 , str.Length() ) ; + wLine = ::TextWidth( str.c_str() , 0 , str.length() ) ; #endif lbWidth = wxMax( lbWidth, wLine ); @@ -603,7 +603,7 @@ wxSize wxListBox::DoGetBestSize() const return wxSize( lbWidth, lbHeight ); } -int wxListBox::GetCount() const +size_t wxListBox::GetCount() const { return m_noItems; } @@ -737,7 +737,7 @@ bool wxListBox::MacIsSelected( int n ) const int wxListBox::MacGetSelection() const { - for ( int i = 0 ; i < GetCount() ; ++i ) + for ( size_t i = 0 ; i < GetCount() ; ++i ) { if ( m_peer->IsItemSelected( i + 1 ) ) return i ; @@ -782,79 +782,106 @@ void wxListBox::MacScrollTo( int n ) verify_noerr( m_peer->RevealItem( id , kTextColumnId , kDataBrowserRevealWithoutSelecting ) ) ; } -int wxListBox::DoListHitTest(const wxPoint& point) const +int wxListBox::DoListHitTest(const wxPoint& inpoint) const { - //Yuck - there is no easy way to get a databrowseritem from a point - //so we need to iterate through our items to see which one this falls under - int count = GetCount(); - DataBrowserTableViewColumnID colId = 0; + OSErr err; - //Get column property id (req. for call to itempartbounds) - GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId); - - for(int i = 1; i <= count; ++i) - { - Rect bounds; - GetDataBrowserItemPartBounds(m_peer->GetControlRef(), i, colId, - kDataBrowserPropertyEnclosingPart, - &bounds); - - //translate to client coords - MacRootWindowToWindow(&bounds.left, &bounds.top); - MacRootWindowToWindow(&bounds.right, &bounds.bottom); - -#if 0 //debugging :) - wxPrintf(wxT("L:%i R:%i T:%i B:%i HT:%i,%i\n"), - bounds.left, bounds.right, - bounds.top, bounds.bottom, - point.x, point.y); - fflush(stdout); -#endif - //if point is within the bounds, return this item - if( (point.x >= bounds.left && point.x <= bounds.right) && - (point.y >= bounds.top && point.y <= bounds.bottom) ) - { - return i - 1; //found - } - } - - return wxNOT_FOUND; -} + // 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 -int wxListBox::MacHitTest(const wxPoint& point) -{ - //Yuck - there is no easy way to get a databrowseritem from a point - //so we need to iterate through our items to see which one this falls under + wxPoint point = inpoint; + // interestingly enough 10.2 (and below?) have GetDataBrowserItemPartBounds + // giving root window coordinates but 10.3 and above give client coordinates + // so we only compare using root window coordinates on 10.3 and up + if ( UMAGetSystemVersion() < 0x1030 ) + MacClientToRootWindow(&point.x, &point.y); - // TODO: binary search would be faster - int count = GetCount(); + // 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 trans 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++; + } - //Get column property id (req. for call to itempartbounds) - GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId); - - for(int i = 1; i <= count; ++i) + // 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; - GetDataBrowserItemPartBounds(m_peer->GetControlRef(), i, colId, - kDataBrowserPropertyEnclosingPart, - &bounds); - - //translate to client coords - // - // TODO: it would probably be more efficient to translate point to - // screen coordinates once outside of the loop - MacRootWindowToWindow(&bounds.left, &bounds.top); - MacRootWindowToWindow(&bounds.right, &bounds.bottom); - - //if point is within the bounds, return this item - if( (point.x >= bounds.left && point.x <= bounds.right) && - (point.y >= bounds.top && point.y <= bounds.bottom) ) + 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 ) { - return i - 1; //found + // item not visible, attempt to find a visible one + high = mid - 1; // search lower + } + 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) ) + { + return mid; // found! + } + + if ( point.y < bounds.top ) + high = mid - 1; // index(bounds) greater then key(point) + else + low = mid + 1; // index(bounds) less then key(point) } } - + return wxNOT_FOUND; }