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;
{
if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) )
{
- m_combo->DrawFocusBackground(dc,rect,0);
+ OnDrawBg(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
if ( m_value >= 0 )
{
- OnDrawItem(dc,rect,m_value,wxCP_PAINTING_CONTROL);
+ OnDrawItem(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
return;
}
}
OnDrawItem(dc,rect,(int)n,0);
}
-wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t WXUNUSED(n)) const
+wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const
{
- return m_itemHeight;
+ wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
+
+ wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
+
+ wxCoord h = combo->OnMeasureItem(n);
+ if ( h < 0 )
+ h = m_itemHeight;
+ return h;
}
-wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t WXUNUSED(n)) const
+wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t n) const
{
- //return OnMeasureListItemWidth(n);
- return -1;
+ wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
+
+ wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
+
+ return combo->OnMeasureItemWidth(n);
+}
+
+void wxVListBoxComboPopup::OnDrawBg( wxDC& dc,
+ const wxRect& rect,
+ int item,
+ int flags ) const
+{
+ wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
+
+ wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
+
+ combo->OnDrawBackground(dc,rect,item,flags);
}
void wxVListBoxComboPopup::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
{
- // we need to render selected and current items differently
- if ( IsCurrent(n) )
- {
- m_combo->DrawFocusBackground( dc, rect, wxCONTROL_ISSUBMENU|wxCONTROL_SELECTED );
- }
- //else: do nothing for the normal items
+ OnDrawBg(dc,rect,(int)n,0);
}
// This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared
void wxVListBoxComboPopup::OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
{
- if ( flags & wxCP_PAINTING_CONTROL )
- {
- dc.DrawText( m_combo->GetValue(),
- rect.x + m_combo->GetTextIndent(),
- (rect.height-dc.GetCharHeight())/2 + rect.y );
- }
- else
- {
- dc.DrawText( GetString(item), rect.x + 2, rect.y );
- }
+ wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
+
+ wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
+
+ combo->OnDrawItem(dc,rect,item,flags);
}
void wxVListBoxComboPopup::DismissWithEvent()
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?
}
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)
wxASSERT(m_combo);
m_strings.Empty();
+ m_widths.Empty();
+
+ m_widestWidth = 0;
+ m_widestItem = -1;
ClearClientDatas();
m_clientDatas.SetCount(n+1,NULL);
m_clientDatas[n] = clientData;
+
+ ItemWidthChanged(n);
}
void* wxVListBoxComboPopup::GetItemClientData(unsigned int n) const
}
m_strings.RemoveAt(item);
+ m_widths.RemoveAt(item);
+
+ if ( (int)item == m_widestItem )
+ m_findWidest = true;
if ( IsCreated() )
wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
}
-int wxVListBoxComboPopup::FindString(const wxString& s) const
+int wxVListBoxComboPopup::FindString(const wxString& s, bool bCase) const
{
- return m_strings.Index(s);
+ return m_strings.Index(s, bCase);
}
unsigned int wxVListBoxComboPopup::GetCount() const
void wxVListBoxComboPopup::SetString( int item, const wxString& str )
{
m_strings[item] = str;
+ ItemWidthChanged(item);
}
wxString wxVListBoxComboPopup::GetStringValue() const
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,
{
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);
// Find initial selection
wxString strValue = m_combo->GetValue();
- if ( strValue.Length() )
+ if ( strValue.length() )
m_value = m_strings.Index(strValue);
}
m_popupInterface->ClearClientDatas();
}
-void wxOwnerDrawnComboBox::SetPopupControl( wxComboPopup* popup )
+void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup)
{
if ( !popup )
{
popup = new wxVListBoxComboPopup();
}
- wxComboCtrl::SetPopupControl(popup);
+ wxComboCtrl::DoSetPopupControl(popup);
wxASSERT(popup);
m_popupInterface = (wxVListBoxComboPopup*) popup;
unsigned int wxOwnerDrawnComboBox::GetCount() const
{
- wxASSERT_MSG( m_popupInterface, wxT("no popup interface") );
+ if ( !m_popupInterface )
+ return m_initChs.GetCount();
+
return m_popupInterface->GetCount();
}
wxString wxOwnerDrawnComboBox::GetString(unsigned int n) const
{
wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") );
+
+ if ( !m_popupInterface )
+ return m_initChs.Item(n);
+
return m_popupInterface->GetString(n);
}
void wxOwnerDrawnComboBox::SetString(unsigned int n, const wxString& s)
{
+ EnsurePopupControl();
+
wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") );
+
m_popupInterface->SetString(n,s);
}
-int wxOwnerDrawnComboBox::FindString(const wxString& s) const
+int wxOwnerDrawnComboBox::FindString(const wxString& s, bool bCase) const
{
- wxASSERT_MSG( m_popupInterface, wxT("no popup interface") );
- return m_popupInterface->FindString(s);
+ if ( !m_popupInterface )
+ return m_initChs.Index(s, bCase);
+
+ return m_popupInterface->FindString(s, bCase);
}
void wxOwnerDrawnComboBox::Select(int n)
{
- wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") );
EnsurePopupControl();
+ wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") );
+
m_popupInterface->SetSelection(n);
wxString str;
int wxOwnerDrawnComboBox::GetSelection() const
{
- wxASSERT_MSG( m_popupInterface, wxT("no popup interface") );
+ if ( !m_popupInterface )
+ return m_initChs.Index(m_valueString);
+
return m_popupInterface->GetSelection();
}
int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos)
{
+ EnsurePopupControl();
+
wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
- EnsurePopupControl();
m_popupInterface->Insert(item,pos);
return pos;
void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const
{
- wxASSERT_MSG( m_popupInterface, wxT("no popup interface") );
+ if ( !m_popupInterface )
+ return NULL;
+
return m_popupInterface->GetItemClientData(n);
}
return (wxClientData*) DoGetItemClientData(n);
}
+// ----------------------------------------------------------------------------
+// wxOwnerDrawnComboBox item drawing and measuring default implementations
+// ----------------------------------------------------------------------------
+
+void wxOwnerDrawnComboBox::OnDrawItem( wxDC& dc,
+ const wxRect& rect,
+ int item,
+ int flags ) const
+{
+ if ( flags & wxODCB_PAINTING_CONTROL )
+ {
+ dc.DrawText( GetValue(),
+ rect.x + GetTextIndent(),
+ (rect.height-dc.GetCharHeight())/2 + rect.y );
+ }
+ else
+ {
+ dc.DrawText( m_popupInterface->GetString(item), rect.x + 2, rect.y );
+ }
+}
+
+wxCoord wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item) ) const
+{
+ return -1;
+}
+
+wxCoord wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item) ) const
+{
+ return -1;
+}
+
+void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc, const wxRect& rect, int item, int flags) const
+{
+ // we need to render selected and current items differently
+ if ( m_popupInterface->IsCurrent((size_t)item) )
+ {
+ DrawFocusBackground(dc,
+ rect,
+ (flags&wxODCB_PAINTING_CONTROL?0:wxCONTROL_ISSUBMENU) |
+ wxCONTROL_SELECTED);
+ }
+ //else: do nothing for the normal items
+}
+
#endif // wxUSE_ODCOMBOBOX