From: Włodzimierz Skiba Date: Mon, 19 Jun 2006 09:02:10 +0000 (+0000) Subject: [ 1507736 ] wxOwnerDrawnComboBox improved list item width checking. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/e5d633423892080a29d08c6f7f13a562a9aa3db3 [ 1507736 ] wxOwnerDrawnComboBox improved list item width checking. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39790 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/odcombo.h b/include/wx/odcombo.h index 0b578c6580..39bfc73cd0 100644 --- a/include/wx/odcombo.h +++ b/include/wx/odcombo.h @@ -118,8 +118,12 @@ protected: // gets value, sends event and dismisses void DismissWithEvent(); - // Re-calculates width for given item - void CheckWidth( int pos ); + // OnMeasureItemWidth will be called on next GetAdjustedSize. + void ItemWidthChanged(unsigned int item) + { + m_widths[item] = -1; + m_widthsDirty = true; + } // Callbacks for drawing and measuring items. Override in a derived class for // owner-drawnness. Font, background and text colour have been prepared according @@ -155,24 +159,35 @@ protected: wxArrayString m_strings; wxArrayPtrVoid m_clientDatas; - wxArrayInt m_widths; // cached line widths wxFont m_useFont; //wxString m_stringValue; // displayed text (may be different than m_strings[m_value]) int m_value; // selection int m_itemHover; // on which item the cursor is - int m_widestWidth; // width of widest item thus far - int m_avgCharWidth; - int m_baseImageWidth; // how much per item drawn in addition to text int m_itemHeight; // default item height (calculate from font size // and used in the absence of callback) wxClientDataType m_clientDataItemsType; private: + // Cached item widths (in pixels). + wxArrayInt m_widths; + + // Width of currently widest item. + int m_widestWidth; + + // Index of currently widest item. + int m_widestItem; + + // Measure some items in next GetAdjustedSize? + bool m_widthsDirty; + + // Find widest item in next GetAdjustedSize? + bool m_findWidest; + // has the mouse been released on this control? - bool m_clicked; + bool m_clicked; DECLARE_EVENT_TABLE() }; diff --git a/src/generic/odcombo.cpp b/src/generic/odcombo.cpp index 037fb88b43..1a1f2e74e4 100644 --- a/src/generic/odcombo.cpp +++ b/src/generic/odcombo.cpp @@ -58,8 +58,9 @@ END_EVENT_TABLE() void wxVListBoxComboPopup::Init() { m_widestWidth = 0; - m_avgCharWidth = 0; - m_baseImageWidth = 0; + m_widestItem = -1; + m_widthsDirty = false; + m_findWidest = false; m_itemHeight = 0; m_value = -1; m_itemHover = -1; @@ -327,26 +328,6 @@ void wxVListBoxComboPopup::OnKey(wxKeyEvent& event) event.Skip(); } -void wxVListBoxComboPopup::CheckWidth( int pos ) -{ - wxCoord x = OnMeasureItemWidth(pos); - - if ( x < 0 ) - { - if ( !m_useFont.Ok() ) - m_useFont = m_combo->GetFont(); - - wxCoord y; - m_combo->GetTextExtent(m_strings[pos], &x, &y, 0, 0, &m_useFont); - x += 4; - } - - if ( m_widestWidth < x ) - { - m_widestWidth = x; - } -} - void wxVListBoxComboPopup::Insert( const wxString& item, int pos ) { // Need to change selection? @@ -358,12 +339,11 @@ void wxVListBoxComboPopup::Insert( const wxString& item, int pos ) } m_strings.Insert(item,pos); + m_widths.Insert(-1,pos); + m_widthsDirty = true; if ( IsCreated() ) wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 ); - - // Calculate width - CheckWidth(pos); } int wxVListBoxComboPopup::Append(const wxString& item) @@ -397,6 +377,10 @@ void wxVListBoxComboPopup::Clear() wxASSERT(m_combo); m_strings.Empty(); + m_widths.Empty(); + + m_widestWidth = 0; + m_widestItem = -1; ClearClientDatas(); @@ -427,6 +411,8 @@ void wxVListBoxComboPopup::SetItemClientData( unsigned int n, m_clientDatas.SetCount(n+1,NULL); m_clientDatas[n] = clientData; + + ItemWidthChanged(n); } void* wxVListBoxComboPopup::GetItemClientData(unsigned int n) const @@ -449,6 +435,10 @@ void wxVListBoxComboPopup::Delete( unsigned int item ) } m_strings.RemoveAt(item); + m_widths.RemoveAt(item); + + if ( (int)item == m_widestItem ) + m_findWidest = true; if ( IsCreated() ) wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 ); @@ -472,6 +462,7 @@ wxString wxVListBoxComboPopup::GetString( int item ) const void wxVListBoxComboPopup::SetString( int item, const wxString& str ) { m_strings[item] = str; + ItemWidthChanged(item); } wxString wxVListBoxComboPopup::GetStringValue() const @@ -537,6 +528,92 @@ wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int else height = 50; + bool doFindWidest = m_findWidest; + + // Measure items with dirty width. + if ( m_widthsDirty ) + { + unsigned int i; + unsigned int n = m_widths.GetCount(); + int dirtyHandled = 0; + wxArrayInt& widths = m_widths; + + // I think using wxDC::GetTextExtent is faster than + // wxWindow::GetTextExtent (assuming same dc is used + // for all calls, as we do here). + wxClientDC dc(m_combo); + dc.SetFont(m_useFont); + + for ( i=0; i= m_widestWidth ) + { + m_widestWidth = x; + m_widestItem = (int)i; + } + else if ( (int)i == m_widestItem ) + { + // Width of previously widest item has been decreased, so + // we'll have to check all to find current widest item. + doFindWidest = true; + } + + dirtyHandled++; + } + } + + m_widthsDirty = false; + } + + if ( doFindWidest ) + { + unsigned int i; + unsigned int n = m_widths.GetCount(); + + int bestWidth = -1; + int bestIndex = -1; + + for ( i=0; i bestWidth ) + { + bestIndex = (int)i; + bestWidth = w; + } + } + + m_widestWidth = bestWidth; + m_widestItem = bestIndex; + + m_findWidest = false; + } + // Take scrollbar into account in width calculations int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); return wxSize(minWidth > widestWidth ? minWidth : widestWidth, @@ -554,9 +631,11 @@ void wxVListBoxComboPopup::Populate( const wxArrayString& choices ) { const wxString& item = choices.Item(i); m_strings.Add(item); - CheckWidth(i); } + m_widths.SetCount(n,-1); + m_widthsDirty = true; + if ( IsCreated() ) wxVListBox::SetItemCount(n);