[ 1507736 ] wxOwnerDrawnComboBox improved list item width checking.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39790 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Włodzimierz Skiba
2006-06-19 09:02:10 +00:00
parent 1d39a12a30
commit e5d6334238
2 changed files with 127 additions and 33 deletions

View File

@@ -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()
};

View File

@@ -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<n; i++ )
{
if ( widths[i] < 0 )
{
wxCoord x = OnMeasureItemWidth(i);
if ( x < 0 )
{
const wxString& text = m_strings[i];
// To make sure performance won't suck in extreme scenarios,
// we'll estimate length after some arbitrary number of items
// have been checked precily.
if ( dirtyHandled < 1024 )
{
wxCoord y;
dc.GetTextExtent(text, &x, &y, 0, 0);
x += 4;
}
else
{
x = text.length() * (dc.GetCharWidth()+1);
}
}
widths[i] = x;
if ( x >= 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<n; i++ )
{
int w = m_widths[i];
if ( w > 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);