1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/odcombo.cpp 
   3 // Purpose:     wxOwnerDrawnComboBox, wxVListBoxComboPopup 
   4 // Author:      Jaakko Salli 
   6 // Created:     Apr-30-2006 
   8 // Copyright:   (c) 2005 Jaakko Salli 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  28 #include "wx/odcombo.h" 
  32     #include "wx/combobox.h" 
  33     #include "wx/dcclient.h" 
  34     #include "wx/settings.h" 
  35     #include "wx/dialog.h" 
  36     #include "wx/textctrl.h" 
  41 // ============================================================================ 
  43 // ============================================================================ 
  45 // time in milliseconds before partial completion buffer drops 
  46 #define wxODCB_PARTIAL_COMPLETION_TIME 1000 
  48 // ---------------------------------------------------------------------------- 
  49 // wxVListBoxComboPopup is a wxVListBox customized to act as a popup control 
  51 // ---------------------------------------------------------------------------- 
  54 BEGIN_EVENT_TABLE(wxVListBoxComboPopup
, wxVListBox
) 
  55     EVT_MOTION(wxVListBoxComboPopup::OnMouseMove
) 
  56     EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey
) 
  57     EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick
) 
  61 void wxVListBoxComboPopup::Init() 
  65     m_widthsDirty 
= false; 
  70     m_clientDataItemsType 
= wxClientData_None
; 
  71     m_partialCompletionString 
= wxEmptyString
; 
  74 bool wxVListBoxComboPopup::Create(wxWindow
* parent
) 
  76     if ( !wxVListBox::Create(parent
, 
  80                              wxBORDER_SIMPLE 
| wxLB_INT_HEIGHT 
| wxWANTS_CHARS
) ) 
  83     m_useFont 
= m_combo
->GetFont(); 
  85     wxVListBox::SetItemCount(m_strings
.GetCount()); 
  87     // TODO: Move this to SetFont 
  88     m_itemHeight 
= GetCharHeight() + 0; 
  93 wxVListBoxComboPopup::~wxVListBoxComboPopup() 
  98 bool wxVListBoxComboPopup::LazyCreate() 
 100     // NB: There is a bug with wxVListBox that can be avoided by creating 
 101     //     it later (bug causes empty space to be shown if initial selection 
 102     //     is at the end of a list longer than the control can show at once). 
 106 // paint the control itself 
 107 void wxVListBoxComboPopup::PaintComboControl( wxDC
& dc
, const wxRect
& rect 
) 
 109     if ( !(m_combo
->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT
) ) 
 111         int flags 
= wxODCB_PAINTING_CONTROL
; 
 113         if ( m_combo
->ShouldDrawFocus() ) 
 114             flags 
|= wxODCB_PAINTING_SELECTED
; 
 116         OnDrawBg(dc
, rect
, m_value
, flags
); 
 120             OnDrawItem(dc
,rect
,m_value
,flags
); 
 125     wxComboPopup::PaintComboControl(dc
,rect
); 
 128 void wxVListBoxComboPopup::OnDrawItem(wxDC
& dc
, const wxRect
& rect
, size_t n
) const 
 130     // TODO: Maybe this code could be moved to wxVListBox::OnPaint? 
 131     dc
.SetFont(m_useFont
); 
 135     // Set correct text colour for selected items 
 136     if ( wxVListBox::GetSelection() == (int) n 
) 
 138         dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) ); 
 139         flags 
|= wxODCB_PAINTING_SELECTED
; 
 143         dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) ); 
 146     OnDrawItem(dc
,rect
,(int)n
,flags
); 
 149 wxCoord 
wxVListBoxComboPopup::OnMeasureItem(size_t n
) const 
 151     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 153     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 154                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 156     wxCoord h 
= combo
->OnMeasureItem(n
); 
 162 wxCoord 
wxVListBoxComboPopup::OnMeasureItemWidth(size_t n
) const 
 164     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 166     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 167                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 169     return combo
->OnMeasureItemWidth(n
); 
 172 void wxVListBoxComboPopup::OnDrawBg( wxDC
& dc
, 
 177     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 179     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 180                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 182     if ( IsCurrent((size_t)item
) && !(flags 
& wxODCB_PAINTING_CONTROL
) ) 
 183         flags 
|= wxODCB_PAINTING_SELECTED
; 
 185     combo
->OnDrawBackground(dc
,rect
,item
,flags
); 
 188 void wxVListBoxComboPopup::OnDrawBackground(wxDC
& dc
, const wxRect
& rect
, size_t n
) const 
 190     OnDrawBg(dc
,rect
,(int)n
,0); 
 193 // This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared 
 194 void wxVListBoxComboPopup::OnDrawItem( wxDC
& dc
, const wxRect
& rect
, int item
, int flags 
) const 
 196     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 198     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 199                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 201     combo
->OnDrawItem(dc
,rect
,item
,flags
); 
 204 void wxVListBoxComboPopup::DismissWithEvent() 
 206     StopPartialCompletion(); 
 208     int selection 
= wxVListBox::GetSelection(); 
 212     if ( selection 
!= wxNOT_FOUND 
) 
 213         m_stringValue 
= m_strings
[selection
]; 
 215         m_stringValue 
= wxEmptyString
; 
 217     if ( m_stringValue 
!= m_combo
->GetValue() ) 
 218         m_combo
->SetValueWithEvent(m_stringValue
); 
 222     SendComboBoxEvent(selection
); 
 225 void wxVListBoxComboPopup::SendComboBoxEvent( int selection 
) 
 227     wxCommandEvent 
evt(wxEVT_COMMAND_COMBOBOX_SELECTED
,m_combo
->GetId()); 
 229     evt
.SetEventObject(m_combo
); 
 231     evt
.SetInt(selection
); 
 233     // Set client data, if any 
 234     if ( selection 
>= 0 && (int)m_clientDatas
.GetCount() > selection 
) 
 236         void* clientData 
= m_clientDatas
[selection
]; 
 237         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 238             evt
.SetClientObject((wxClientData
*)clientData
); 
 240             evt
.SetClientData(clientData
); 
 243     m_combo
->GetEventHandler()->AddPendingEvent(evt
); 
 246 // returns true if key was consumed 
 247 bool wxVListBoxComboPopup::HandleKey( int keycode
, bool saturate
, wxChar unicode 
) 
 249     const int itemCount 
= GetCount(); 
 251     // keys do nothing in the empty control and returning immediately avoids 
 252     // using invalid indices below 
 257     int comboStyle 
= m_combo
->GetWindowStyle(); 
 259     // this is the character equivalent of the code 
 261     if ( keycode 
< WXK_START 
) 
 265             if ( wxIsprint(unicode
) ) 
 268         else if ( wxIsprint(keycode
) ) 
 270             keychar 
= (wxChar
) keycode
; 
 274     if ( keycode 
== WXK_DOWN 
|| keycode 
== WXK_RIGHT 
) 
 277         StopPartialCompletion(); 
 279     else if ( keycode 
== WXK_UP 
|| keycode 
== WXK_LEFT 
) 
 282         StopPartialCompletion(); 
 284     else if ( keycode 
== WXK_PAGEDOWN 
) 
 287         StopPartialCompletion(); 
 289     else if ( keycode 
== WXK_PAGEUP 
) 
 292         StopPartialCompletion(); 
 294     else if ( keychar 
&& (comboStyle 
& wxCB_READONLY
) ) 
 296         // Try partial completion 
 298         // find the new partial completion string 
 300         if (m_partialCompletionTimer
.IsRunning()) 
 301             m_partialCompletionString
+=wxString(keychar
); 
 303 #endif // wxUSE_TIMER 
 304             m_partialCompletionString
=wxString(keychar
); 
 306         // now search through the values to see if this is found 
 308         unsigned int length
=m_partialCompletionString
.length(); 
 310         for (i
=0; i
<itemCount
; i
++) 
 312             wxString item
=GetString(i
); 
 313             if (( item
.length() >= length
) && (!  m_partialCompletionString
.CmpNoCase(item
.Left(length
)))) 
 322             StopPartialCompletion(); 
 324             return true; // to stop the first value being set 
 330             m_partialCompletionTimer
.Start(wxODCB_PARTIAL_COMPLETION_TIME
, true); 
 331 #endif // wxUSE_TIMER 
 339         if ( value 
>= itemCount 
) 
 340             value 
= itemCount 
- 1; 
 341         else if ( value 
< 0 ) 
 346         if ( value 
>= itemCount 
) 
 348         else if ( value 
< 0 ) 
 352     if ( value 
== m_value 
) 
 353         // Even if value was same, don't skip the event 
 354         // (good for consistency) 
 360         m_combo
->SetValue(m_strings
[value
]); 
 362     SendComboBoxEvent(m_value
); 
 367 // stop partial completion 
 368 void wxVListBoxComboPopup::StopPartialCompletion() 
 370     m_partialCompletionString 
= wxEmptyString
; 
 372     m_partialCompletionTimer
.Stop(); 
 373 #endif // wxUSE_TIMER 
 376 void wxVListBoxComboPopup::OnComboDoubleClick() 
 378     // Cycle on dclick (disable saturation to allow true cycling). 
 379     if ( !::wxGetKeyState(WXK_SHIFT
) ) 
 380         HandleKey(WXK_DOWN
,false); 
 382         HandleKey(WXK_UP
,false); 
 385 void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent
& event 
) 
 387     // Saturated key movement on 
 388     if ( !HandleKey(event
.GetKeyCode(),true, 
 390         event
.GetUnicodeKey() 
 398 void wxVListBoxComboPopup::OnPopup() 
 400     // *must* set value after size is set (this is because of a vlbox bug) 
 401     wxVListBox::SetSelection(m_value
); 
 404 void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent
& event
) 
 408     // Move selection to cursor if it is inside the popup 
 410     int y 
= event
.GetPosition().y
; 
 411     int fromBottom 
= GetClientSize().y 
- y
; 
 413     // Since in any case we need to find out if the last item is only 
 414     // partially visible, we might just as well replicate the HitTest 
 416     const size_t lineMax 
= GetVisibleEnd(); 
 417     for ( size_t line 
= GetVisibleBegin(); line 
< lineMax
; line
++ ) 
 419         y 
-= OnGetRowHeight(line
); 
 422             // Only change selection if item is fully visible 
 423             if ( (y 
+ fromBottom
) >= 0 ) 
 425                 wxVListBox::SetSelection((int)line
); 
 432 void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent
& WXUNUSED(event
)) 
 437 void wxVListBoxComboPopup::OnKey(wxKeyEvent
& event
) 
 439     // Hide popup if certain key or key combination was pressed 
 440     if ( m_combo
->IsKeyPopupToggle(event
) ) 
 442         StopPartialCompletion(); 
 445     else if ( event
.AltDown() ) 
 447         // On both wxGTK and wxMSW, pressing Alt down seems to 
 448         // completely freeze things in popup (ie. arrow keys and 
 449         // enter won't work). 
 452     // Select item if ENTER is pressed 
 453     else if ( event
.GetKeyCode() == WXK_RETURN 
|| event
.GetKeyCode() == WXK_NUMPAD_ENTER 
) 
 459         int comboStyle 
= m_combo
->GetWindowStyle(); 
 460         int keycode 
= event
.GetKeyCode(); 
 461         // Process partial completion key codes here, but not the arrow keys as the base class will do that for us 
 462         if ((comboStyle 
& wxCB_READONLY
) && 
 463             (keycode 
>= WXK_SPACE
) && (keycode 
<=255) && (keycode 
!= WXK_DELETE
) && wxIsprint(keycode
)) 
 465             OnComboKeyEvent(event
); 
 466             SetSelection(m_value
); // ensure the highlight bar moves 
 473 void wxVListBoxComboPopup::Insert( const wxString
& item
, int pos 
) 
 475     // Need to change selection? 
 477     if ( !(m_combo
->GetWindowStyle() & wxCB_READONLY
) && 
 478          m_combo
->GetValue() == item 
) 
 483     m_strings
.Insert(item
,pos
); 
 484     if ( (int)m_clientDatas
.size() >= pos 
) 
 485         m_clientDatas
.Insert(NULL
, pos
); 
 487     m_widths
.Insert(-1,pos
); 
 488     m_widthsDirty 
= true; 
 491         wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 ); 
 494 int wxVListBoxComboPopup::Append(const wxString
& item
) 
 496     int pos 
= (int)m_strings
.GetCount(); 
 498     if ( m_combo
->GetWindowStyle() & wxCB_SORT 
) 
 501         // TODO: Could be optimized with binary search 
 502         wxArrayString strings 
= m_strings
; 
 505         for ( i
=0; i
<strings
.GetCount(); i
++ ) 
 507             if ( item
.Cmp(strings
.Item(i
)) < 0 ) 
 520 void wxVListBoxComboPopup::Clear() 
 532     m_value 
= wxNOT_FOUND
; 
 535         wxVListBox::SetItemCount(0); 
 538 void wxVListBoxComboPopup::ClearClientDatas() 
 540     if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 543         for ( i
=0; i
<m_clientDatas
.GetCount(); i
++ ) 
 544             delete (wxClientData
*) m_clientDatas
[i
]; 
 547     m_clientDatas
.Empty(); 
 550 void wxVListBoxComboPopup::SetItemClientData( unsigned int n
, 
 552                                               wxClientDataType clientDataItemsType 
) 
 554     // It should be sufficient to update this variable only here 
 555     m_clientDataItemsType 
= clientDataItemsType
; 
 557     m_clientDatas
[n
] = clientData
; 
 562 void* wxVListBoxComboPopup::GetItemClientData(unsigned int n
) const 
 564     if ( m_clientDatas
.GetCount() > n 
) 
 565         return m_clientDatas
[n
]; 
 570 void wxVListBoxComboPopup::Delete( unsigned int item 
) 
 572     // Remove client data, if set 
 573     if ( m_clientDatas
.GetCount() ) 
 575         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 576             delete (wxClientData
*) m_clientDatas
[item
]; 
 578         m_clientDatas
.RemoveAt(item
); 
 581     m_strings
.RemoveAt(item
); 
 582     m_widths
.RemoveAt(item
); 
 584     if ( (int)item 
== m_widestItem 
) 
 587     int sel 
= GetSelection(); 
 590         wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 ); 
 593     if ( (int)item 
< sel 
) 
 595     else if ( (int)item 
== sel 
) 
 596         SetSelection(wxNOT_FOUND
); 
 599 int wxVListBoxComboPopup::FindString(const wxString
& s
, bool bCase
) const 
 601     return m_strings
.Index(s
, bCase
); 
 604 unsigned int wxVListBoxComboPopup::GetCount() const 
 606     return m_strings
.GetCount(); 
 609 wxString 
wxVListBoxComboPopup::GetString( int item 
) const 
 611     return m_strings
[item
]; 
 614 void wxVListBoxComboPopup::SetString( int item
, const wxString
& str 
) 
 616     m_strings
[item
] = str
; 
 617     ItemWidthChanged(item
); 
 620 wxString 
wxVListBoxComboPopup::GetStringValue() const 
 622     return m_stringValue
; 
 625 void wxVListBoxComboPopup::SetSelection( int item 
) 
 627     wxCHECK_RET( item 
== wxNOT_FOUND 
|| ((unsigned int)item 
< GetCount()), 
 628                  wxT("invalid index in wxVListBoxComboPopup::SetSelection") ); 
 633         m_stringValue 
= m_strings
[item
]; 
 635         m_stringValue 
= wxEmptyString
; 
 638         wxVListBox::SetSelection(item
); 
 641 int wxVListBoxComboPopup::GetSelection() const 
 646 void wxVListBoxComboPopup::SetStringValue( const wxString
& value 
) 
 648     int index 
= m_strings
.Index(value
); 
 650     m_stringValue 
= value
; 
 652     if ( index 
>= 0 && index 
< (int)wxVListBox::GetItemCount() ) 
 654         wxVListBox::SetSelection(index
); 
 659 void wxVListBoxComboPopup::CalcWidths() 
 661     bool doFindWidest 
= m_findWidest
; 
 663     // Measure items with dirty width. 
 667         unsigned int n 
= m_widths
.GetCount(); 
 668         int dirtyHandled 
= 0; 
 669         wxArrayInt
& widths 
= m_widths
; 
 671         // I think using wxDC::GetTextExtent is faster than 
 672         // wxWindow::GetTextExtent (assuming same dc is used 
 673         // for all calls, as we do here). 
 674         wxClientDC 
dc(m_combo
); 
 675         dc
.SetFont(m_useFont
); 
 677         for ( i
=0; i
<n
; i
++ ) 
 681                 wxCoord x 
= OnMeasureItemWidth(i
); 
 685                     const wxString
& text 
= m_strings
[i
]; 
 687                     // To make sure performance won't suck in extreme scenarios, 
 688                     // we'll estimate length after some arbitrary number of items 
 689                     // have been checked precily. 
 690                     if ( dirtyHandled 
< 1024 ) 
 693                         dc
.GetTextExtent(text
, &x
, &y
, 0, 0); 
 698                         x 
= text
.length() * (dc
.GetCharWidth()+1); 
 704                 if ( x 
>= m_widestWidth 
) 
 707                     m_widestItem 
= (int)i
; 
 709                 else if ( (int)i 
== m_widestItem 
) 
 711                     // Width of previously widest item has been decreased, so 
 712                     // we'll have to check all to find current widest item. 
 720         m_widthsDirty 
= false; 
 726         unsigned int n 
= m_widths
.GetCount(); 
 731         for ( i
=0; i
<n
; i
++ ) 
 741         m_widestWidth 
= bestWidth
; 
 742         m_widestItem 
= bestIndex
; 
 744         m_findWidest 
= false; 
 748 wxSize 
wxVListBoxComboPopup::GetAdjustedSize( int minWidth
, int prefHeight
, int maxHeight 
) 
 752     maxHeight 
-= 2;  // Must take borders into account 
 754     if ( m_strings
.GetCount() ) 
 756         if ( prefHeight 
> 0 ) 
 759         if ( height 
> maxHeight 
) 
 762         int totalHeight 
= GetTotalHeight(); // + 3; 
 763         if ( height 
>= totalHeight 
) 
 765             height 
= totalHeight
; 
 769             // Adjust height to a multiple of the height of the first item 
 770             // NB: Calculations that take variable height into account 
 772             int fih 
= GetLineHeight(0); 
 773             height 
-= height 
% fih
; 
 781     // Take scrollbar into account in width calculations 
 782     int widestWidth 
= m_widestWidth 
+ wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
 783     return wxSize(minWidth 
> widestWidth 
? minWidth 
: widestWidth
, 
 787 //void wxVListBoxComboPopup::Populate( int n, const wxString choices[] ) 
 788 void wxVListBoxComboPopup::Populate( const wxArrayString
& choices 
) 
 792     int n 
= choices
.GetCount(); 
 794     for ( i
=0; i
<n
; i
++ ) 
 796         const wxString
& item 
= choices
.Item(i
); 
 800     m_widths
.SetCount(n
,-1); 
 801     m_widthsDirty 
= true; 
 804         wxVListBox::SetItemCount(n
); 
 806     // Sort the initial choices 
 807     if ( m_combo
->GetWindowStyle() & wxCB_SORT 
) 
 810     // Find initial selection 
 811     wxString strValue 
= m_combo
->GetValue(); 
 812     if ( strValue
.length() ) 
 813         m_value 
= m_strings
.Index(strValue
); 
 816 // ---------------------------------------------------------------------------- 
 817 // wxOwnerDrawnComboBox 
 818 // ---------------------------------------------------------------------------- 
 821 BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox
, wxComboCtrl
) 
 825 #if wxUSE_EXTENDED_RTTI 
 826 IMPLEMENT_DYNAMIC_CLASS2_XTI(wxOwnerDrawnComboBox
, wxComboCtrl
, wxControlWithItems
, "wx/odcombo.h") 
 828 wxBEGIN_PROPERTIES_TABLE(wxOwnerDrawnComboBox
) 
 829 wxEND_PROPERTIES_TABLE() 
 831 wxBEGIN_HANDLERS_TABLE(wxOwnerDrawnComboBox
) 
 832 wxEND_HANDLERS_TABLE() 
 834 wxCONSTRUCTOR_5( wxOwnerDrawnComboBox 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxString 
, Value 
, wxPoint 
, Position 
, wxSize 
, Size 
) 
 836 IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox
, wxComboCtrl
, wxControlWithItems
) 
 839 void wxOwnerDrawnComboBox::Init() 
 843 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 845                                   const wxString
& value
, 
 849                                   const wxValidator
& validator
, 
 850                                   const wxString
& name
) 
 852     return wxComboCtrl::Create(parent
,id
,value
,pos
,size
,style
,validator
,name
); 
 855 wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow 
*parent
, 
 857                                            const wxString
& value
, 
 860                                            const wxArrayString
& choices
, 
 862                                            const wxValidator
& validator
, 
 863                                            const wxString
& name
) 
 868     Create(parent
,id
,value
,pos
,size
,choices
,style
, validator
, name
); 
 871 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 873                                   const wxString
& value
, 
 876                                   const wxArrayString
& choices
, 
 878                                   const wxValidator
& validator
, 
 879                                   const wxString
& name
) 
 882     //wxCArrayString chs(choices); 
 884     //return Create(parent, id, value, pos, size, chs.GetCount(), 
 885     //              chs.GetStrings(), style, validator, name); 
 886     return Create(parent
, id
, value
, pos
, size
, 0, 
 887                   NULL
, style
, validator
, name
); 
 890 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 892                                   const wxString
& value
, 
 896                                   const wxString choices
[], 
 898                                   const wxValidator
& validator
, 
 899                                   const wxString
& name
) 
 902     if ( !Create(parent
, id
, value
, pos
, size
, style
, 
 909     for ( i
=0; i
<n
; i
++ ) 
 910         m_initChs
.Add(choices
[i
]); 
 915 wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox() 
 917     if ( m_popupInterface 
) 
 918         GetVListBoxComboPopup()->ClearClientDatas(); 
 921 void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup
* popup
) 
 925         popup 
= new wxVListBoxComboPopup(); 
 928     wxComboCtrl::DoSetPopupControl(popup
); 
 932     // Add initial choices to the wxVListBox 
 933     if ( !GetVListBoxComboPopup()->GetCount() ) 
 935         GetVListBoxComboPopup()->Populate(m_initChs
); 
 940 // ---------------------------------------------------------------------------- 
 941 // wxOwnerDrawnComboBox item manipulation methods 
 942 // ---------------------------------------------------------------------------- 
 944 void wxOwnerDrawnComboBox::DoClear() 
 946     EnsurePopupControl(); 
 948     GetVListBoxComboPopup()->Clear(); 
 950     SetValue(wxEmptyString
); 
 953 void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n
) 
 955     wxCHECK_RET( IsValid(n
), _T("invalid index in wxOwnerDrawnComboBox::Delete") ); 
 957     if ( GetSelection() == (int) n 
) 
 958         SetValue(wxEmptyString
); 
 960     GetVListBoxComboPopup()->Delete(n
); 
 963 unsigned int wxOwnerDrawnComboBox::GetCount() const 
 965     if ( !m_popupInterface 
) 
 966         return m_initChs
.GetCount(); 
 968     return GetVListBoxComboPopup()->GetCount(); 
 971 wxString 
wxOwnerDrawnComboBox::GetString(unsigned int n
) const 
 973     wxCHECK_MSG( IsValid(n
), wxEmptyString
, _T("invalid index in wxOwnerDrawnComboBox::GetString") ); 
 975     if ( !m_popupInterface 
) 
 976         return m_initChs
.Item(n
); 
 978     return GetVListBoxComboPopup()->GetString(n
); 
 981 void wxOwnerDrawnComboBox::SetString(unsigned int n
, const wxString
& s
) 
 983     EnsurePopupControl(); 
 985     wxCHECK_RET( IsValid(n
), _T("invalid index in wxOwnerDrawnComboBox::SetString") ); 
 987     GetVListBoxComboPopup()->SetString(n
,s
); 
 990 int wxOwnerDrawnComboBox::FindString(const wxString
& s
, bool bCase
) const 
 992     if ( !m_popupInterface 
) 
 993         return m_initChs
.Index(s
, bCase
); 
 995     return GetVListBoxComboPopup()->FindString(s
, bCase
); 
 998 void wxOwnerDrawnComboBox::Select(int n
) 
1000     EnsurePopupControl(); 
1002     wxCHECK_RET( (n 
== wxNOT_FOUND
) || IsValid(n
), _T("invalid index in wxOwnerDrawnComboBox::Select") ); 
1004     GetVListBoxComboPopup()->SetSelection(n
); 
1008         str 
= GetVListBoxComboPopup()->GetString(n
); 
1010     // Refresh text portion in control 
1012         m_text
->SetValue( str 
); 
1014         m_valueString 
= str
; 
1019 int wxOwnerDrawnComboBox::GetSelection() const 
1021     if ( !m_popupInterface 
) 
1022         return m_initChs
.Index(m_valueString
); 
1024     return GetVListBoxComboPopup()->GetSelection(); 
1027 int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
, 
1030                                         wxClientDataType type
) 
1032     EnsurePopupControl(); 
1034     const unsigned int count 
= items
.GetCount(); 
1036     if ( HasFlag(wxCB_SORT
) ) 
1040         for ( unsigned int i 
= 0; i 
< count
; ++i 
) 
1042             int n 
= GetVListBoxComboPopup()->Append(items
[i
]); 
1043             AssignNewItemClientData(n
, clientData
, i
, type
); 
1050         for ( unsigned int i 
= 0; i 
< count
; ++i
, ++pos 
) 
1052             GetVListBoxComboPopup()->Insert(items
[i
], pos
); 
1053             AssignNewItemClientData(pos
, clientData
, i
, type
); 
1060 void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n
, void* clientData
) 
1062     EnsurePopupControl(); 
1064     GetVListBoxComboPopup()->SetItemClientData(n
, clientData
, 
1065                                                GetClientDataType()); 
1068 void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n
) const 
1070     if ( !m_popupInterface 
) 
1073     return GetVListBoxComboPopup()->GetItemClientData(n
); 
1076 // ---------------------------------------------------------------------------- 
1077 // wxOwnerDrawnComboBox item drawing and measuring default implementations 
1078 // ---------------------------------------------------------------------------- 
1080 void wxOwnerDrawnComboBox::OnDrawItem( wxDC
& dc
, 
1085     if ( flags 
& wxODCB_PAINTING_CONTROL 
) 
1087         dc
.DrawText( GetValue(), 
1088                      rect
.x 
+ GetTextIndent(), 
1089                      (rect
.height
-dc
.GetCharHeight())/2 + rect
.y 
); 
1093         dc
.DrawText( GetVListBoxComboPopup()->GetString(item
), rect
.x 
+ 2, rect
.y 
); 
1097 wxCoord 
wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item
) ) const 
1102 wxCoord 
wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item
) ) const 
1107 void wxOwnerDrawnComboBox::OnDrawBackground(wxDC
& dc
, 
1112     // We need only to explicitly draw background for items 
1113     // that should have selected background. Also, call PrepareBackground 
1114     // always when painting the control so that clipping is done properly. 
1116     if ( (flags 
& wxODCB_PAINTING_SELECTED
) || 
1117          ((flags 
& wxODCB_PAINTING_CONTROL
) && HasFlag(wxCB_READONLY
)) ) 
1119         int bgFlags 
= wxCONTROL_SELECTED
; 
1121         if ( !(flags 
& wxODCB_PAINTING_CONTROL
) ) 
1122             bgFlags 
|= wxCONTROL_ISSUBMENU
; 
1124         PrepareBackground(dc
, rect
, bgFlags
); 
1128 #endif // wxUSE_ODCOMBOBOX