/////////////////////////////////////////////////////////////////////////////
-// Name: odcombo.cpp
+// Name: src/generic/odcombo.cpp
// Purpose: wxOwnerDrawnComboBox, wxVListBoxComboPopup
// Author: Jaakko Salli
// Modified by:
#pragma hdrstop
#endif
-#if wxUSE_OWNERDRAWNCOMBOBOX
+#if wxUSE_ODCOMBOBOX
+
+#include "wx/odcombo.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/dialog.h"
+ #include "wx/textctrl.h"
#endif
#include "wx/combo.h"
-#include "wx/odcombo.h"
-
// ============================================================================
// implementation
// ============================================================================
+// time in milliseconds before partial completion buffer drops
+#define wxODCB_PARTIAL_COMPLETION_TIME 1000
// ----------------------------------------------------------------------------
// wxVListBoxComboPopup is a wxVListBox customized to act as a popup control
END_EVENT_TABLE()
-wxVListBoxComboPopup::wxVListBoxComboPopup(wxComboControlBase* combo)
- : wxVListBox(),
- wxComboPopup(combo)
+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;
m_clientDataItemsType = wxClientData_None;
+ m_partialCompletionString = wxEmptyString;
}
bool wxVListBoxComboPopup::Create(wxWindow* parent)
wxBORDER_SIMPLE | wxLB_INT_HEIGHT | wxWANTS_CHARS) )
return false;
- wxASSERT( GetParent()->GetParent() );
- SetFont( GetParent()->GetParent()->GetFont() );
+ m_useFont = m_combo->GetFont();
wxVListBox::SetItemCount(m_strings.GetCount());
{
if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) )
{
- m_combo->DrawFocusBackground(dc,rect,0);
+ int flags = wxODCB_PAINTING_CONTROL;
+
+ if ( m_combo->ShouldDrawFocus() )
+ flags |= wxODCB_PAINTING_SELECTED;
+
+ OnDrawBg(dc, rect, m_value, flags);
+
if ( m_value >= 0 )
{
- if ( m_combo->OnDrawListItem(dc,rect,m_value,wxCC_PAINTING_CONTROL) )
- return;
+ OnDrawItem(dc,rect,m_value,flags);
+ return;
}
}
void wxVListBoxComboPopup::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
{
- dc.SetFont( m_font );
+ // TODO: Maybe this code could be moved to wxVListBox::OnPaint?
+ dc.SetFont(m_useFont);
- bool isHilited = GetSelection() == (int) n;
+ int flags = 0;
// Set correct text colour for selected items
- // (must always set the correct colour - atleast GTK may have lost it
- // in between calls).
- if ( isHilited )
+ if ( wxVListBox::GetSelection() == (int) n )
+ {
dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
+ flags |= wxODCB_PAINTING_SELECTED;
+ }
else
+ {
dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+ }
- if ( !m_combo->OnDrawListItem(dc,rect,(int)n,0) )
- dc.DrawText( GetString(n), rect.x + 2, rect.y );
+ OnDrawItem(dc,rect,(int)n,flags);
}
wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const
{
- int itemHeight = m_combo->OnMeasureListItem(n);
- if ( itemHeight < 0 )
- itemHeight = m_itemHeight;
+ wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
+
+ wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
- return itemHeight;
+ wxCoord h = combo->OnMeasureItem(n);
+ if ( h < 0 )
+ h = m_itemHeight;
+ return h;
+}
+
+wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t n) const
+{
+ 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") );
+
+ if ( IsCurrent((size_t)item) && !(flags & wxODCB_PAINTING_CONTROL) )
+ flags |= wxODCB_PAINTING_SELECTED;
+
+ 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);
}
-void wxVListBoxComboPopup::SendComboBoxEvent()
+// 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
+{
+ 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()
+{
+ StopPartialCompletion();
+
+ int selection = wxVListBox::GetSelection();
+
+ Dismiss();
+
+ if ( selection != wxNOT_FOUND )
+ m_stringValue = m_strings[selection];
+ else
+ m_stringValue = wxEmptyString;
+
+ if ( m_stringValue != m_combo->GetValue() )
+ m_combo->SetValueWithEvent(m_stringValue);
+
+ m_value = selection;
+
+ SendComboBoxEvent(selection);
+}
+
+void wxVListBoxComboPopup::SendComboBoxEvent( int selection )
{
wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
- int selection = m_value;
evt.SetEventObject(m_combo);
+
evt.SetInt(selection);
// Set client data, if any
}
// returns true if key was consumed
-bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate )
+bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode )
{
+ const int itemCount = GetCount();
+
+ // keys do nothing in the empty control and returning immediately avoids
+ // using invalid indices below
+ if ( !itemCount )
+ return false;
+
int value = m_value;
- int itemCount = GetCount();
+ int comboStyle = m_combo->GetWindowStyle();
+
+ // this is the character equivalent of the code
+ wxChar keychar = 0;
+ if ( keycode < WXK_START )
+ {
+ if ( unicode > 0 )
+ {
+ if ( wxIsprint(unicode) )
+ keychar = unicode;
+ }
+ else if ( wxIsprint(keycode) )
+ {
+ keychar = (wxChar) keycode;
+ }
+ }
if ( keycode == WXK_DOWN || keycode == WXK_RIGHT )
{
value++;
+ StopPartialCompletion();
}
else if ( keycode == WXK_UP || keycode == WXK_LEFT )
{
value--;
+ StopPartialCompletion();
}
else if ( keycode == WXK_PAGEDOWN )
{
value+=10;
+ StopPartialCompletion();
}
else if ( keycode == WXK_PAGEUP )
{
value-=10;
+ StopPartialCompletion();
}
- /*
- else if ( keycode == WXK_END )
+ else if ( keychar && (comboStyle & wxCB_READONLY) )
{
- value = itemCount-1;
- }
- else if ( keycode == WXK_HOME )
- {
- value = 0;
+ // Try partial completion
+
+ // find the new partial completion string
+#if wxUSE_TIMER
+ if (m_partialCompletionTimer.IsRunning())
+ m_partialCompletionString+=wxString(keychar);
+ else
+#endif // wxUSE_TIMER
+ m_partialCompletionString=wxString(keychar);
+
+ // now search through the values to see if this is found
+ int found = -1;
+ unsigned int length=m_partialCompletionString.length();
+ int i;
+ for (i=0; i<itemCount; i++)
+ {
+ wxString item=GetString(i);
+ if (( item.length() >= length) && (! m_partialCompletionString.CmpNoCase(item.Left(length))))
+ {
+ found=i;
+ break;
+ }
+ }
+
+ if (found<0)
+ {
+ StopPartialCompletion();
+ ::wxBell();
+ return true; // to stop the first value being set
+ }
+ else
+ {
+ value=i;
+#if wxUSE_TIMER
+ m_partialCompletionTimer.Start(wxODCB_PARTIAL_COMPLETION_TIME, true);
+#endif // wxUSE_TIMER
+ }
}
- */
else
return false;
m_value = value;
- wxString valStr;
if ( value >= 0 )
m_combo->SetValue(m_strings[value]);
- SendComboBoxEvent();
+ SendComboBoxEvent(m_value);
return true;
}
+// stop partial completion
+void wxVListBoxComboPopup::StopPartialCompletion()
+{
+ m_partialCompletionString = wxEmptyString;
+#if wxUSE_TIMER
+ m_partialCompletionTimer.Stop();
+#endif // wxUSE_TIMER
+}
+
void wxVListBoxComboPopup::OnComboDoubleClick()
{
// Cycle on dclick (disable saturation to allow true cycling).
void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent& event )
{
// Saturated key movement on
- if ( !HandleKey(event.GetKeyCode(),true) )
+ if ( !HandleKey(event.GetKeyCode(),true,
+#if wxUSE_UNICODE
+ event.GetUnicodeKey()
+#else
+ 0
+#endif
+ ) )
event.Skip();
}
void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent& event)
{
+ event.Skip();
+
// Move selection to cursor if it is inside the popup
- int itemHere = GetItemAtPosition(event.GetPosition());
- if ( itemHere >= 0 )
- wxVListBox::SetSelection(itemHere);
- event.Skip();
+ int y = event.GetPosition().y;
+ int fromBottom = GetClientSize().y - y;
+
+ // Since in any case we need to find out if the last item is only
+ // partially visible, we might just as well replicate the HitTest
+ // loop here.
+ const size_t lineMax = GetVisibleEnd();
+ for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
+ {
+ y -= OnGetRowHeight(line);
+ if ( y < 0 )
+ {
+ // Only change selection if item is fully visible
+ if ( (y + fromBottom) >= 0 )
+ {
+ wxVListBox::SetSelection((int)line);
+ return;
+ }
+ }
+ }
}
void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event))
{
- m_value = wxVListBox::GetSelection();
- Dismiss();
- SendComboBoxEvent();
+ DismissWithEvent();
}
void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
{
- // Select item if ENTER is pressed
- if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
+ // Hide popup if certain key or key combination was pressed
+ if ( m_combo->IsKeyPopupToggle(event) )
{
- m_value = wxVListBox::GetSelection();
+ StopPartialCompletion();
Dismiss();
- SendComboBoxEvent();
}
- // Hide popup if ESC is pressed
- else if ( event.GetKeyCode() == WXK_ESCAPE )
- Dismiss();
- else
- event.Skip();
-}
-
-void wxVListBoxComboPopup::CheckWidth( int pos )
-{
- wxCoord x = m_combo->OnMeasureListItemWidth(pos);
-
- if ( x < 0 )
+ else if ( event.AltDown() )
{
- if ( !m_font.Ok() )
- m_font = m_combo->GetFont();
-
- wxCoord y;
- m_combo->GetTextExtent(m_strings[pos], &x, &y, 0, 0, &m_font);
- x += 4;
+ // On both wxGTK and wxMSW, pressing Alt down seems to
+ // completely freeze things in popup (ie. arrow keys and
+ // enter won't work).
+ return;
}
-
- if ( m_widestWidth < x )
+ // Select item if ENTER is pressed
+ else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
{
- m_widestWidth = x;
+ DismissWithEvent();
+ }
+ else
+ {
+ int comboStyle = m_combo->GetWindowStyle();
+ int keycode = event.GetKeyCode();
+ // Process partial completion key codes here, but not the arrow keys as the base class will do that for us
+ if ((comboStyle & wxCB_READONLY) &&
+ (keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode))
+ {
+ OnComboKeyEvent(event);
+ SetSelection(m_value); // ensure the highlight bar moves
+ }
+ else
+ event.Skip();
}
}
wxString strValue;
if ( !(m_combo->GetWindowStyle() & wxCB_READONLY) &&
m_combo->GetValue() == item )
+ {
m_value = pos;
+ }
m_strings.Insert(item,pos);
+ if ( (int)m_clientDatas.size() >= pos )
+ m_clientDatas.Insert(NULL, 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_value = wxNOT_FOUND;
+
if ( IsCreated() )
wxVListBox::SetItemCount(0);
}
// It should be sufficient to update this variable only here
m_clientDataItemsType = clientDataItemsType;
- 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;
+
+ int sel = GetSelection();
if ( IsCreated() )
wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
+
+ // Fix selection
+ if ( (int)item < sel )
+ SetSelection(sel-1);
+ else if ( (int)item == sel )
+ SetSelection(wxNOT_FOUND);
}
-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
{
- if ( m_value >= 0 )
- return m_strings[m_value];
- return wxEmptyString;
+ return m_stringValue;
}
void wxVListBoxComboPopup::SetSelection( int item )
{
- // This seems to be necessary (2.5.3 w/ MingW atleast)
- if ( item < -1 || item >= (int)m_strings.GetCount() )
- item = -1;
+ wxCHECK_RET( item == wxNOT_FOUND || ((unsigned int)item < GetCount()),
+ wxT("invalid index in wxVListBoxComboPopup::SetSelection") );
m_value = item;
+ if ( item >= 0 )
+ m_stringValue = m_strings[item];
+ else
+ m_stringValue = wxEmptyString;
+
if ( IsCreated() )
wxVListBox::SetSelection(item);
}
+int wxVListBoxComboPopup::GetSelection() const
+{
+ return m_value;
+}
+
void wxVListBoxComboPopup::SetStringValue( const wxString& value )
{
int index = m_strings.Index(value);
- m_value = index;
+ m_stringValue = value;
- if ( index >= -1 && index < (int)wxVListBox::GetItemCount() )
+ if ( index >= 0 && index < (int)wxVListBox::GetItemCount() )
+ {
wxVListBox::SetSelection(index);
+ m_value = index;
+ }
+}
+
+void wxVListBoxComboPopup::CalcWidths()
+{
+ 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;
+ }
}
wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int maxHeight )
{
int height = 250;
+ maxHeight -= 2; // Must take borders into account
+
if ( m_strings.GetCount() )
{
if ( prefHeight > 0 )
// NB: Calculations that take variable height into account
// are unnecessary.
int fih = GetLineHeight(0);
- int shown = height/fih;
- height = shown * fih;
+ height -= height % fih;
}
}
else
height = 50;
+ CalcWidths();
+
// Take scrollbar into account in width calculations
int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
return wxSize(minWidth > widestWidth ? minWidth : widestWidth,
height+2);
}
-void wxVListBoxComboPopup::Populate( int n, const wxString choices[] )
+//void wxVListBoxComboPopup::Populate( int n, const wxString choices[] )
+void wxVListBoxComboPopup::Populate( const wxArrayString& choices )
{
int i;
+ int n = choices.GetCount();
+
for ( i=0; i<n; i++ )
{
- const wxString& item = choices[i];
+ 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);
}
// ----------------------------------------------------------------------------
-BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboControl)
+BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboCtrl)
END_EVENT_TABLE()
-IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboControl, wxControlWithItems)
+#if wxUSE_EXTENDED_RTTI
+IMPLEMENT_DYNAMIC_CLASS2_XTI(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems, "wx/odcombo.h")
+
+wxBEGIN_PROPERTIES_TABLE(wxOwnerDrawnComboBox)
+wxEND_PROPERTIES_TABLE()
+
+wxBEGIN_HANDLERS_TABLE(wxOwnerDrawnComboBox)
+wxEND_HANDLERS_TABLE()
+
+wxCONSTRUCTOR_5( wxOwnerDrawnComboBox , wxWindow* , Parent , wxWindowID , Id , wxString , Value , wxPoint , Position , wxSize , Size )
+#else
+IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems)
+#endif
void wxOwnerDrawnComboBox::Init()
{
const wxValidator& validator,
const wxString& name)
{
- return wxComboControl::Create(parent,id,value,pos,size,style,validator,name);
+ return wxComboCtrl::Create(parent,id,value,pos,size,style,validator,name);
}
wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow *parent,
long style,
const wxValidator& validator,
const wxString& name)
- : wxComboControl()
+ : wxComboCtrl()
{
Init();
const wxValidator& validator,
const wxString& name)
{
- wxCArrayString chs(choices);
+ m_initChs = choices;
+ //wxCArrayString chs(choices);
- return Create(parent, id, value, pos, size, chs.GetCount(),
- chs.GetStrings(), style, validator, name);
+ //return Create(parent, id, value, pos, size, chs.GetCount(),
+ // chs.GetStrings(), style, validator, name);
+ return Create(parent, id, value, pos, size, 0,
+ NULL, style, validator, name);
}
bool wxOwnerDrawnComboBox::Create(wxWindow *parent,
return false;
}
- wxVListBoxComboPopup* iface = new wxVListBoxComboPopup(this);
- SetPopupControl(iface);
-
- // m_popupInterface has been overridden as wxVListBoxComboPopup
- m_popupInterface = iface;
-
- // Add initial choices to the wxVListBox
- iface->Populate(n,choices);
+ int i;
+ for ( i=0; i<n; i++ )
+ m_initChs.Add(choices[i]);
return true;
}
wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox()
{
if ( m_popupInterface )
- m_popupInterface->ClearClientDatas();
+ GetVListBoxComboPopup()->ClearClientDatas();
+}
+
+void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup)
+{
+ if ( !popup )
+ {
+ popup = new wxVListBoxComboPopup();
+ }
+
+ wxComboCtrl::DoSetPopupControl(popup);
+
+ wxASSERT(popup);
+
+ // Add initial choices to the wxVListBox
+ if ( !GetVListBoxComboPopup()->GetCount() )
+ {
+ GetVListBoxComboPopup()->Populate(m_initChs);
+ m_initChs.Clear();
+ }
}
// ----------------------------------------------------------------------------
// wxOwnerDrawnComboBox item manipulation methods
// ----------------------------------------------------------------------------
-void wxOwnerDrawnComboBox::Clear()
+void wxOwnerDrawnComboBox::DoClear()
{
- wxASSERT( m_popupInterface );
+ EnsurePopupControl();
- m_popupInterface->Clear();
+ GetVListBoxComboPopup()->Clear();
- GetTextCtrl()->SetValue(wxEmptyString);
+ SetValue(wxEmptyString);
}
-void wxOwnerDrawnComboBox::Delete(unsigned int n)
+void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n)
{
- wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
+ wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
if ( GetSelection() == (int) n )
SetValue(wxEmptyString);
- m_popupInterface->Delete(n);
+ GetVListBoxComboPopup()->Delete(n);
}
unsigned int wxOwnerDrawnComboBox::GetCount() const
{
- wxASSERT( m_popupInterface );
- return m_popupInterface->GetCount();
+ if ( !m_popupInterface )
+ return m_initChs.GetCount();
+
+ return GetVListBoxComboPopup()->GetCount();
}
wxString wxOwnerDrawnComboBox::GetString(unsigned int n) const
{
- wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") );
- return m_popupInterface->GetString(n);
+ wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") );
+
+ if ( !m_popupInterface )
+ return m_initChs.Item(n);
+
+ return GetVListBoxComboPopup()->GetString(n);
}
void wxOwnerDrawnComboBox::SetString(unsigned int n, const wxString& s)
{
- wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxOwnerDrawnComboBox::SetString") );
- m_popupInterface->SetString(n,s);
+ EnsurePopupControl();
+
+ wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") );
+
+ GetVListBoxComboPopup()->SetString(n,s);
}
-int wxOwnerDrawnComboBox::FindString(const wxString& s) const
+int wxOwnerDrawnComboBox::FindString(const wxString& s, bool bCase) const
{
- wxASSERT( m_popupInterface );
- return m_popupInterface->FindString(s);
+ if ( !m_popupInterface )
+ return m_initChs.Index(s, bCase);
+
+ return GetVListBoxComboPopup()->FindString(s, bCase);
}
void wxOwnerDrawnComboBox::Select(int n)
{
- wxCHECK_RET( (n >= -1) && (n < (int)GetCount()), _T("invalid index in wxOwnerDrawnComboBox::Select") );
- wxASSERT( m_popupInterface );
+ EnsurePopupControl();
- m_popupInterface->SetSelection(n);
+ wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") );
+
+ GetVListBoxComboPopup()->SetSelection(n);
wxString str;
if ( n >= 0 )
- str = m_popupInterface->GetString(n);
+ str = GetVListBoxComboPopup()->GetString(n);
// Refresh text portion in control
if ( m_text )
int wxOwnerDrawnComboBox::GetSelection() const
{
- wxASSERT( m_popupInterface );
- return m_popupInterface->GetSelection();
-}
+ if ( !m_popupInterface )
+ return m_initChs.Index(m_valueString);
-int wxOwnerDrawnComboBox::DoAppend(const wxString& item)
-{
- wxASSERT( m_popupInterface );
- return m_popupInterface->Append(item);
+ return GetVListBoxComboPopup()->GetSelection();
}
-int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos)
+int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+ unsigned int pos,
+ void **clientData,
+ wxClientDataType type)
{
- wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
- wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
+ EnsurePopupControl();
- m_popupInterface->Insert(item,pos);
+ const unsigned int count = items.GetCount();
- return pos;
+ if ( HasFlag(wxCB_SORT) )
+ {
+ int n = pos;
+
+ for ( unsigned int i = 0; i < count; ++i )
+ {
+ int n = GetVListBoxComboPopup()->Append(items[i]);
+ AssignNewItemClientData(n, clientData, i, type);
+ }
+
+ return n;
+ }
+ else
+ {
+ for ( unsigned int i = 0; i < count; ++i, ++pos )
+ {
+ GetVListBoxComboPopup()->Insert(items[i], pos);
+ AssignNewItemClientData(pos, clientData, i, type);
+ }
+
+ return pos - 1;
+ }
}
void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n, void* clientData)
{
- wxASSERT(m_popupInterface);
- m_popupInterface->SetItemClientData(n,clientData,m_clientDataItemsType);
+ EnsurePopupControl();
+
+ GetVListBoxComboPopup()->SetItemClientData(n, clientData,
+ GetClientDataType());
}
void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const
{
- wxASSERT(m_popupInterface);
- return m_popupInterface->GetItemClientData(n);
+ if ( !m_popupInterface )
+ return NULL;
+
+ return GetVListBoxComboPopup()->GetItemClientData(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( GetVListBoxComboPopup()->GetString(item), rect.x + 2, rect.y );
+ }
}
-void wxOwnerDrawnComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
+wxCoord wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item) ) const
{
- DoSetItemClientData(n, (void*) clientData);
+ return -1;
}
-wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(unsigned int n) const
+wxCoord wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item) ) const
{
- return (wxClientData*) DoGetItemClientData(n);
+ return -1;
+}
+
+void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc,
+ const wxRect& rect,
+ int WXUNUSED(item),
+ int flags) const
+{
+ // We need only to explicitly draw background for items
+ // that should have selected background. Also, call PrepareBackground
+ // always when painting the control so that clipping is done properly.
+
+ if ( (flags & wxODCB_PAINTING_SELECTED) ||
+ ((flags & wxODCB_PAINTING_CONTROL) && HasFlag(wxCB_READONLY)) )
+ {
+ int bgFlags = wxCONTROL_SELECTED;
+
+ if ( !(flags & wxODCB_PAINTING_CONTROL) )
+ bgFlags |= wxCONTROL_ISSUBMENU;
+
+ PrepareBackground(dc, rect, bgFlags);
+ }
}
-#endif // wxUSE_OWNERDRAWNCOMBOBOX
+#endif // wxUSE_ODCOMBOBOX