[ 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:
@@ -118,8 +118,12 @@ protected:
|
|||||||
// gets value, sends event and dismisses
|
// gets value, sends event and dismisses
|
||||||
void DismissWithEvent();
|
void DismissWithEvent();
|
||||||
|
|
||||||
// Re-calculates width for given item
|
// OnMeasureItemWidth will be called on next GetAdjustedSize.
|
||||||
void CheckWidth( int pos );
|
void ItemWidthChanged(unsigned int item)
|
||||||
|
{
|
||||||
|
m_widths[item] = -1;
|
||||||
|
m_widthsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Callbacks for drawing and measuring items. Override in a derived class for
|
// Callbacks for drawing and measuring items. Override in a derived class for
|
||||||
// owner-drawnness. Font, background and text colour have been prepared according
|
// owner-drawnness. Font, background and text colour have been prepared according
|
||||||
@@ -155,24 +159,35 @@ protected:
|
|||||||
|
|
||||||
wxArrayString m_strings;
|
wxArrayString m_strings;
|
||||||
wxArrayPtrVoid m_clientDatas;
|
wxArrayPtrVoid m_clientDatas;
|
||||||
wxArrayInt m_widths; // cached line widths
|
|
||||||
|
|
||||||
wxFont m_useFont;
|
wxFont m_useFont;
|
||||||
|
|
||||||
//wxString m_stringValue; // displayed text (may be different than m_strings[m_value])
|
//wxString m_stringValue; // displayed text (may be different than m_strings[m_value])
|
||||||
int m_value; // selection
|
int m_value; // selection
|
||||||
int m_itemHover; // on which item the cursor is
|
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
|
int m_itemHeight; // default item height (calculate from font size
|
||||||
// and used in the absence of callback)
|
// and used in the absence of callback)
|
||||||
wxClientDataType m_clientDataItemsType;
|
wxClientDataType m_clientDataItemsType;
|
||||||
|
|
||||||
private:
|
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?
|
// has the mouse been released on this control?
|
||||||
bool m_clicked;
|
bool m_clicked;
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
@@ -58,8 +58,9 @@ END_EVENT_TABLE()
|
|||||||
void wxVListBoxComboPopup::Init()
|
void wxVListBoxComboPopup::Init()
|
||||||
{
|
{
|
||||||
m_widestWidth = 0;
|
m_widestWidth = 0;
|
||||||
m_avgCharWidth = 0;
|
m_widestItem = -1;
|
||||||
m_baseImageWidth = 0;
|
m_widthsDirty = false;
|
||||||
|
m_findWidest = false;
|
||||||
m_itemHeight = 0;
|
m_itemHeight = 0;
|
||||||
m_value = -1;
|
m_value = -1;
|
||||||
m_itemHover = -1;
|
m_itemHover = -1;
|
||||||
@@ -327,26 +328,6 @@ void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
|
|||||||
event.Skip();
|
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 )
|
void wxVListBoxComboPopup::Insert( const wxString& item, int pos )
|
||||||
{
|
{
|
||||||
// Need to change selection?
|
// Need to change selection?
|
||||||
@@ -358,12 +339,11 @@ void wxVListBoxComboPopup::Insert( const wxString& item, int pos )
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_strings.Insert(item,pos);
|
m_strings.Insert(item,pos);
|
||||||
|
m_widths.Insert(-1,pos);
|
||||||
|
m_widthsDirty = true;
|
||||||
|
|
||||||
if ( IsCreated() )
|
if ( IsCreated() )
|
||||||
wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 );
|
wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 );
|
||||||
|
|
||||||
// Calculate width
|
|
||||||
CheckWidth(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxVListBoxComboPopup::Append(const wxString& item)
|
int wxVListBoxComboPopup::Append(const wxString& item)
|
||||||
@@ -397,6 +377,10 @@ void wxVListBoxComboPopup::Clear()
|
|||||||
wxASSERT(m_combo);
|
wxASSERT(m_combo);
|
||||||
|
|
||||||
m_strings.Empty();
|
m_strings.Empty();
|
||||||
|
m_widths.Empty();
|
||||||
|
|
||||||
|
m_widestWidth = 0;
|
||||||
|
m_widestItem = -1;
|
||||||
|
|
||||||
ClearClientDatas();
|
ClearClientDatas();
|
||||||
|
|
||||||
@@ -427,6 +411,8 @@ void wxVListBoxComboPopup::SetItemClientData( unsigned int n,
|
|||||||
|
|
||||||
m_clientDatas.SetCount(n+1,NULL);
|
m_clientDatas.SetCount(n+1,NULL);
|
||||||
m_clientDatas[n] = clientData;
|
m_clientDatas[n] = clientData;
|
||||||
|
|
||||||
|
ItemWidthChanged(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* wxVListBoxComboPopup::GetItemClientData(unsigned int n) const
|
void* wxVListBoxComboPopup::GetItemClientData(unsigned int n) const
|
||||||
@@ -449,6 +435,10 @@ void wxVListBoxComboPopup::Delete( unsigned int item )
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_strings.RemoveAt(item);
|
m_strings.RemoveAt(item);
|
||||||
|
m_widths.RemoveAt(item);
|
||||||
|
|
||||||
|
if ( (int)item == m_widestItem )
|
||||||
|
m_findWidest = true;
|
||||||
|
|
||||||
if ( IsCreated() )
|
if ( IsCreated() )
|
||||||
wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
|
wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
|
||||||
@@ -472,6 +462,7 @@ wxString wxVListBoxComboPopup::GetString( int item ) const
|
|||||||
void wxVListBoxComboPopup::SetString( int item, const wxString& str )
|
void wxVListBoxComboPopup::SetString( int item, const wxString& str )
|
||||||
{
|
{
|
||||||
m_strings[item] = str;
|
m_strings[item] = str;
|
||||||
|
ItemWidthChanged(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString wxVListBoxComboPopup::GetStringValue() const
|
wxString wxVListBoxComboPopup::GetStringValue() const
|
||||||
@@ -537,6 +528,92 @@ wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int
|
|||||||
else
|
else
|
||||||
height = 50;
|
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
|
// Take scrollbar into account in width calculations
|
||||||
int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
|
int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
|
||||||
return wxSize(minWidth > widestWidth ? minWidth : widestWidth,
|
return wxSize(minWidth > widestWidth ? minWidth : widestWidth,
|
||||||
@@ -554,9 +631,11 @@ void wxVListBoxComboPopup::Populate( const wxArrayString& choices )
|
|||||||
{
|
{
|
||||||
const wxString& item = choices.Item(i);
|
const wxString& item = choices.Item(i);
|
||||||
m_strings.Add(item);
|
m_strings.Add(item);
|
||||||
CheckWidth(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_widths.SetCount(n,-1);
|
||||||
|
m_widthsDirty = true;
|
||||||
|
|
||||||
if ( IsCreated() )
|
if ( IsCreated() )
|
||||||
wxVListBox::SetItemCount(n);
|
wxVListBox::SetItemCount(n);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user