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_CHAR(wxVListBoxComboPopup::OnChar
) 
  58     EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick
) 
  62 void wxVListBoxComboPopup::Init() 
  66     m_widthsDirty 
= false; 
  71     m_clientDataItemsType 
= wxClientData_None
; 
  72     m_partialCompletionString 
= wxEmptyString
; 
  75 bool wxVListBoxComboPopup::Create(wxWindow
* parent
) 
  77     if ( !wxVListBox::Create(parent
, 
  81                              wxBORDER_SIMPLE 
| wxLB_INT_HEIGHT 
| wxWANTS_CHARS
) ) 
  84     m_useFont 
= m_combo
->GetFont(); 
  86     wxVListBox::SetItemCount(m_strings
.GetCount()); 
  88     // TODO: Move this to SetFont 
  89     m_itemHeight 
= GetCharHeight() + 0; 
  94 wxVListBoxComboPopup::~wxVListBoxComboPopup() 
  99 void wxVListBoxComboPopup::SetFocus() 
 101     // Suppress SetFocus() warning by simply not calling it. This combo popup 
 102     // has already been designed with the assumption that SetFocus() may not 
 103     // do anything useful, so it really doesn't need to be called. 
 107     wxVListBox::SetFocus(); 
 111 bool wxVListBoxComboPopup::LazyCreate() 
 113     // NB: There is a bug with wxVListBox that can be avoided by creating 
 114     //     it later (bug causes empty space to be shown if initial selection 
 115     //     is at the end of a list longer than the control can show at once). 
 119 // paint the control itself 
 120 void wxVListBoxComboPopup::PaintComboControl( wxDC
& dc
, const wxRect
& rect 
) 
 122     if ( !(m_combo
->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT
) ) 
 124         int flags 
= wxODCB_PAINTING_CONTROL
; 
 126         if ( m_combo
->ShouldDrawFocus() ) 
 127             flags 
|= wxODCB_PAINTING_SELECTED
; 
 129         OnDrawBg(dc
, rect
, m_value
, flags
); 
 133             OnDrawItem(dc
,rect
,m_value
,flags
); 
 138     wxComboPopup::PaintComboControl(dc
,rect
); 
 141 void wxVListBoxComboPopup::OnDrawItem(wxDC
& dc
, const wxRect
& rect
, size_t n
) const 
 143     // TODO: Maybe this code could be moved to wxVListBox::OnPaint? 
 144     dc
.SetFont(m_useFont
); 
 148     // Set correct text colour for selected items 
 149     if ( wxVListBox::GetSelection() == (int) n 
) 
 151         dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) ); 
 152         flags 
|= wxODCB_PAINTING_SELECTED
; 
 156         dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) ); 
 159     OnDrawItem(dc
,rect
,(int)n
,flags
); 
 162 wxCoord 
wxVListBoxComboPopup::OnMeasureItem(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     wxCoord h 
= combo
->OnMeasureItem(n
); 
 175 wxCoord 
wxVListBoxComboPopup::OnMeasureItemWidth(size_t n
) const 
 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     return combo
->OnMeasureItemWidth(n
); 
 185 void wxVListBoxComboPopup::OnDrawBg( wxDC
& dc
, 
 190     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 192     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 193                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 195     if ( IsCurrent((size_t)item
) && !(flags 
& wxODCB_PAINTING_CONTROL
) ) 
 196         flags 
|= wxODCB_PAINTING_SELECTED
; 
 198     combo
->OnDrawBackground(dc
,rect
,item
,flags
); 
 201 void wxVListBoxComboPopup::OnDrawBackground(wxDC
& dc
, const wxRect
& rect
, size_t n
) const 
 203     OnDrawBg(dc
,rect
,(int)n
,0); 
 206 // This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared 
 207 void wxVListBoxComboPopup::OnDrawItem( wxDC
& dc
, const wxRect
& rect
, int item
, int flags 
) const 
 209     wxOwnerDrawnComboBox
* combo 
= (wxOwnerDrawnComboBox
*) m_combo
; 
 211     wxASSERT_MSG( combo
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)), 
 212                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); 
 214     combo
->OnDrawItem(dc
,rect
,item
,flags
); 
 217 void wxVListBoxComboPopup::DismissWithEvent() 
 219     StopPartialCompletion(); 
 221     int selection 
= wxVListBox::GetSelection(); 
 225     if ( selection 
!= wxNOT_FOUND 
) 
 226         m_stringValue 
= m_strings
[selection
]; 
 228         m_stringValue 
= wxEmptyString
; 
 230     if ( m_stringValue 
!= m_combo
->GetValue() ) 
 231         m_combo
->SetValueByUser(m_stringValue
); 
 235     SendComboBoxEvent(selection
); 
 238 void wxVListBoxComboPopup::SendComboBoxEvent( int selection 
) 
 240     wxCommandEvent 
evt(wxEVT_COMMAND_COMBOBOX_SELECTED
,m_combo
->GetId()); 
 242     evt
.SetEventObject(m_combo
); 
 244     evt
.SetInt(selection
); 
 246     // Set client data, if any 
 247     if ( selection 
>= 0 && (int)m_clientDatas
.GetCount() > selection 
) 
 249         void* clientData 
= m_clientDatas
[selection
]; 
 250         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 251             evt
.SetClientObject((wxClientData
*)clientData
); 
 253             evt
.SetClientData(clientData
); 
 256     m_combo
->GetEventHandler()->AddPendingEvent(evt
); 
 259 // returns true if key was consumed 
 260 bool wxVListBoxComboPopup::HandleKey( int keycode
, bool saturate
, wxChar keychar 
) 
 262     const int itemCount 
= GetCount(); 
 264     // keys do nothing in the empty control and returning immediately avoids 
 265     // using invalid indices below 
 270     int comboStyle 
= m_combo
->GetWindowStyle(); 
 274         // we have character equivalent of the keycode; filter out these that 
 275         // are not printable characters 
 276         if ( !wxIsprint(keychar
) ) 
 280     if ( keycode 
== WXK_DOWN 
|| keycode 
== WXK_NUMPAD_DOWN 
|| keycode 
== WXK_RIGHT 
) 
 283         StopPartialCompletion(); 
 285     else if ( keycode 
== WXK_UP 
|| keycode 
== WXK_NUMPAD_UP 
|| keycode 
== WXK_LEFT 
) 
 288         StopPartialCompletion(); 
 290     else if ( keycode 
== WXK_PAGEDOWN 
|| keycode 
== WXK_NUMPAD_PAGEDOWN 
) 
 293         StopPartialCompletion(); 
 295     else if ( keycode 
== WXK_PAGEUP 
|| keycode 
== WXK_NUMPAD_PAGEUP 
) 
 298         StopPartialCompletion(); 
 300     else if ( keycode 
== WXK_HOME 
|| keycode 
== WXK_NUMPAD_HOME 
) 
 303         StopPartialCompletion(); 
 305     else if ( keycode 
== WXK_END 
|| keycode 
== WXK_NUMPAD_END 
) 
 308         StopPartialCompletion(); 
 310     else if ( keychar 
&& (comboStyle 
& wxCB_READONLY
) ) 
 312         // Try partial completion 
 314         // find the new partial completion string 
 316         if (m_partialCompletionTimer
.IsRunning()) 
 317             m_partialCompletionString
+=wxString(keychar
); 
 319 #endif // wxUSE_TIMER 
 320             m_partialCompletionString
=wxString(keychar
); 
 322         // now search through the values to see if this is found 
 324         unsigned int length
=m_partialCompletionString
.length(); 
 326         for (i
=0; i
<itemCount
; i
++) 
 328             wxString item
=GetString(i
); 
 329             if (( item
.length() >= length
) && (!  m_partialCompletionString
.CmpNoCase(item
.Left(length
)))) 
 338             StopPartialCompletion(); 
 340             return true; // to stop the first value being set 
 346             m_partialCompletionTimer
.Start(wxODCB_PARTIAL_COMPLETION_TIME
, true); 
 347 #endif // wxUSE_TIMER 
 355         if ( value 
>= itemCount 
) 
 356             value 
= itemCount 
- 1; 
 357         else if ( value 
< 0 ) 
 362         if ( value 
>= itemCount 
) 
 364         else if ( value 
< 0 ) 
 368     if ( value 
== m_value 
) 
 369         // Even if value was same, don't skip the event 
 370         // (good for consistency) 
 374         m_combo
->ChangeValue(m_strings
[value
]); 
 376     // The m_combo->SetValue() call above sets m_value to the index of this 
 377     // string. But if there are more identical string, the index is of the 
 378     // first occurrence, which may be wrong, so set the index explicitly here, 
 379     // _after_ the SetValue() call. 
 382     SendComboBoxEvent(m_value
); 
 387 // stop partial completion 
 388 void wxVListBoxComboPopup::StopPartialCompletion() 
 390     m_partialCompletionString 
= wxEmptyString
; 
 392     m_partialCompletionTimer
.Stop(); 
 393 #endif // wxUSE_TIMER 
 396 void wxVListBoxComboPopup::OnComboDoubleClick() 
 398     // Cycle on dclick (disable saturation to allow true cycling). 
 399     if ( !::wxGetKeyState(WXK_SHIFT
) ) 
 400         HandleKey(WXK_DOWN
,false); 
 402         HandleKey(WXK_UP
,false); 
 405 void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent
& event 
) 
 407     // Saturated key movement on 
 408     if ( !HandleKey(event
.GetKeyCode(), true) ) 
 412 void wxVListBoxComboPopup::OnComboCharEvent( wxKeyEvent
& event 
) 
 414     // unlike in OnComboKeyEvent, wxEVT_CHAR contains meaningful 
 415     // printable character information, so pass it 
 417     const wxChar charcode 
= event
.GetUnicodeKey(); 
 419     const wxChar charcode 
= (wxChar
)event
.GetKeyCode(); 
 422     if ( !HandleKey(event
.GetKeyCode(), true, charcode
) ) 
 426 void wxVListBoxComboPopup::OnPopup() 
 428     // *must* set value after size is set (this is because of a vlbox bug) 
 429     wxVListBox::SetSelection(m_value
); 
 432 void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent
& event
) 
 436     // Move selection to cursor if it is inside the popup 
 438     int y 
= event
.GetPosition().y
; 
 439     int fromBottom 
= GetClientSize().y 
- y
; 
 441     // Since in any case we need to find out if the last item is only 
 442     // partially visible, we might just as well replicate the HitTest 
 444     const size_t lineMax 
= GetVisibleEnd(); 
 445     for ( size_t line 
= GetVisibleBegin(); line 
< lineMax
; line
++ ) 
 447         y 
-= OnGetRowHeight(line
); 
 450             // Only change selection if item is fully visible 
 451             if ( (y 
+ fromBottom
) >= 0 ) 
 453                 wxVListBox::SetSelection((int)line
); 
 460 void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent
& WXUNUSED(event
)) 
 465 void wxVListBoxComboPopup::OnKey(wxKeyEvent
& event
) 
 467     // Hide popup if certain key or key combination was pressed 
 468     if ( m_combo
->IsKeyPopupToggle(event
) ) 
 470         StopPartialCompletion(); 
 473     else if ( event
.AltDown() ) 
 475         // On both wxGTK and wxMSW, pressing Alt down seems to 
 476         // completely freeze things in popup (ie. arrow keys and 
 477         // enter won't work). 
 480     // Select item if ENTER is pressed 
 481     else if ( event
.GetKeyCode() == WXK_RETURN 
|| event
.GetKeyCode() == WXK_NUMPAD_ENTER 
) 
 487         // completion is handled in OnChar() below 
 492 void wxVListBoxComboPopup::OnChar(wxKeyEvent
& event
) 
 494     if ( m_combo
->GetWindowStyle() & wxCB_READONLY 
) 
 496         // Process partial completion key codes here, but not the arrow keys as 
 497         // the base class will do that for us 
 499         const wxChar charcode 
= event
.GetUnicodeKey(); 
 501         const wxChar charcode 
= (wxChar
)event
.GetKeyCode(); 
 503         if ( wxIsprint(charcode
) ) 
 505             OnComboCharEvent(event
); 
 506             SetSelection(m_value
); // ensure the highlight bar moves 
 507             return; // don't skip the event 
 514 void wxVListBoxComboPopup::Insert( const wxString
& item
, int pos 
) 
 516     // Need to change selection? 
 518     if ( !(m_combo
->GetWindowStyle() & wxCB_READONLY
) && 
 519          m_combo
->GetValue() == item 
) 
 524     m_strings
.Insert(item
,pos
); 
 525     if ( (int)m_clientDatas
.size() >= pos 
) 
 526         m_clientDatas
.Insert(NULL
, pos
); 
 528     m_widths
.Insert(-1,pos
); 
 529     m_widthsDirty 
= true; 
 532         wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 ); 
 535 int wxVListBoxComboPopup::Append(const wxString
& item
) 
 537     int pos 
= (int)m_strings
.GetCount(); 
 539     if ( m_combo
->GetWindowStyle() & wxCB_SORT 
) 
 542         // TODO: Could be optimized with binary search 
 543         wxArrayString strings 
= m_strings
; 
 546         for ( i
=0; i
<strings
.GetCount(); i
++ ) 
 548             if ( item
.CmpNoCase(strings
.Item(i
)) <= 0 ) 
 561 void wxVListBoxComboPopup::Clear() 
 573     m_value 
= wxNOT_FOUND
; 
 576         wxVListBox::SetItemCount(0); 
 579 void wxVListBoxComboPopup::ClearClientDatas() 
 581     if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 584         for ( i
=0; i
<m_clientDatas
.GetCount(); i
++ ) 
 585             delete (wxClientData
*) m_clientDatas
[i
]; 
 588     m_clientDatas
.Empty(); 
 591 void wxVListBoxComboPopup::SetItemClientData( unsigned int n
, 
 593                                               wxClientDataType clientDataItemsType 
) 
 595     // It should be sufficient to update this variable only here 
 596     m_clientDataItemsType 
= clientDataItemsType
; 
 598     m_clientDatas
[n
] = clientData
; 
 603 void* wxVListBoxComboPopup::GetItemClientData(unsigned int n
) const 
 605     if ( m_clientDatas
.GetCount() > n 
) 
 606         return m_clientDatas
[n
]; 
 611 void wxVListBoxComboPopup::Delete( unsigned int item 
) 
 613     // Remove client data, if set 
 614     if ( m_clientDatas
.GetCount() ) 
 616         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 617             delete (wxClientData
*) m_clientDatas
[item
]; 
 619         m_clientDatas
.RemoveAt(item
); 
 622     m_strings
.RemoveAt(item
); 
 623     m_widths
.RemoveAt(item
); 
 625     if ( (int)item 
== m_widestItem 
) 
 628     int sel 
= GetSelection(); 
 631         wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 ); 
 634     if ( (int)item 
< sel 
) 
 636     else if ( (int)item 
== sel 
) 
 637         SetSelection(wxNOT_FOUND
); 
 640 int wxVListBoxComboPopup::FindString(const wxString
& s
, bool bCase
) const 
 642     return m_strings
.Index(s
, bCase
); 
 645 bool wxVListBoxComboPopup::FindItem(const wxString
& item
, wxString
* trueItem
) 
 647     int idx 
= m_strings
.Index(item
, false); 
 648     if ( idx 
== wxNOT_FOUND 
) 
 650     if ( trueItem 
!= NULL 
) 
 651         *trueItem 
= m_strings
[idx
]; 
 655 unsigned int wxVListBoxComboPopup::GetCount() const 
 657     return m_strings
.GetCount(); 
 660 wxString 
wxVListBoxComboPopup::GetString( int item 
) const 
 662     return m_strings
[item
]; 
 665 void wxVListBoxComboPopup::SetString( int item
, const wxString
& str 
) 
 667     m_strings
[item
] = str
; 
 668     ItemWidthChanged(item
); 
 671 wxString 
wxVListBoxComboPopup::GetStringValue() const 
 673     return m_stringValue
; 
 676 void wxVListBoxComboPopup::SetSelection( int item 
) 
 678     wxCHECK_RET( item 
== wxNOT_FOUND 
|| ((unsigned int)item 
< GetCount()), 
 679                  wxT("invalid index in wxVListBoxComboPopup::SetSelection") ); 
 684         m_stringValue 
= m_strings
[item
]; 
 686         m_stringValue 
= wxEmptyString
; 
 689         wxVListBox::SetSelection(item
); 
 692 int wxVListBoxComboPopup::GetSelection() const 
 697 void wxVListBoxComboPopup::SetStringValue( const wxString
& value 
) 
 699     int index 
= m_strings
.Index(value
); 
 701     m_stringValue 
= value
; 
 703     if ( index 
>= 0 && index 
< (int)wxVListBox::GetItemCount() ) 
 705         wxVListBox::SetSelection(index
); 
 710 void wxVListBoxComboPopup::CalcWidths() 
 712     bool doFindWidest 
= m_findWidest
; 
 714     // Measure items with dirty width. 
 718         unsigned int n 
= m_widths
.GetCount(); 
 719         int dirtyHandled 
= 0; 
 720         wxArrayInt
& widths 
= m_widths
; 
 722         // I think using wxDC::GetTextExtent is faster than 
 723         // wxWindow::GetTextExtent (assuming same dc is used 
 724         // for all calls, as we do here). 
 725         wxClientDC 
dc(m_combo
); 
 726         dc
.SetFont(m_useFont
); 
 728         for ( i
=0; i
<n
; i
++ ) 
 732                 wxCoord x 
= OnMeasureItemWidth(i
); 
 736                     const wxString
& text 
= m_strings
[i
]; 
 738                     // To make sure performance won't suck in extreme scenarios, 
 739                     // we'll estimate length after some arbitrary number of items 
 740                     // have been checked precily. 
 741                     if ( dirtyHandled 
< 1024 ) 
 744                         dc
.GetTextExtent(text
, &x
, &y
, 0, 0); 
 749                         x 
= text
.length() * (dc
.GetCharWidth()+1); 
 755                 if ( x 
>= m_widestWidth 
) 
 758                     m_widestItem 
= (int)i
; 
 760                 else if ( (int)i 
== m_widestItem 
) 
 762                     // Width of previously widest item has been decreased, so 
 763                     // we'll have to check all to find current widest item. 
 771         m_widthsDirty 
= false; 
 777         unsigned int n 
= m_widths
.GetCount(); 
 782         for ( i
=0; i
<n
; i
++ ) 
 792         m_widestWidth 
= bestWidth
; 
 793         m_widestItem 
= bestIndex
; 
 795         m_findWidest 
= false; 
 799 wxSize 
wxVListBoxComboPopup::GetAdjustedSize( int minWidth
, int prefHeight
, int maxHeight 
) 
 803     maxHeight 
-= 2;  // Must take borders into account 
 805     if ( m_strings
.GetCount() ) 
 807         if ( prefHeight 
> 0 ) 
 810         if ( height 
> maxHeight 
) 
 813         int totalHeight 
= GetTotalHeight(); // + 3; 
 815         // Take borders into account on Mac or scrollbars always appear 
 816 #if defined(__WXMAC__) 
 819         if ( height 
>= totalHeight 
) 
 821             height 
= totalHeight
; 
 825             // Adjust height to a multiple of the height of the first item 
 826             // NB: Calculations that take variable height into account 
 828             int fih 
= GetLineHeight(0); 
 829             height 
-= height 
% fih
; 
 837     // Take scrollbar into account in width calculations 
 838     int widestWidth 
= m_widestWidth 
+ wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
 839     return wxSize(minWidth 
> widestWidth 
? minWidth 
: widestWidth
, 
 843 //void wxVListBoxComboPopup::Populate( int n, const wxString choices[] ) 
 844 void wxVListBoxComboPopup::Populate( const wxArrayString
& choices 
) 
 848     int n 
= choices
.GetCount(); 
 850     for ( i
=0; i
<n
; i
++ ) 
 852         const wxString
& item 
= choices
.Item(i
); 
 856     m_widths
.SetCount(n
,-1); 
 857     m_widthsDirty 
= true; 
 860         wxVListBox::SetItemCount(n
); 
 862     // Sort the initial choices 
 863     if ( m_combo
->GetWindowStyle() & wxCB_SORT 
) 
 866     // Find initial selection 
 867     wxString strValue 
= m_combo
->GetValue(); 
 868     if ( !strValue
.empty() ) 
 869         m_value 
= m_strings
.Index(strValue
); 
 872 // ---------------------------------------------------------------------------- 
 873 // wxOwnerDrawnComboBox 
 874 // ---------------------------------------------------------------------------- 
 877 BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox
, wxComboCtrl
) 
 880 void wxOwnerDrawnComboBox::Init() 
 884 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 886                                   const wxString
& value
, 
 890                                   const wxValidator
& validator
, 
 891                                   const wxString
& name
) 
 893     return wxComboCtrl::Create(parent
,id
,value
,pos
,size
,style
,validator
,name
); 
 896 wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow 
*parent
, 
 898                                            const wxString
& value
, 
 901                                            const wxArrayString
& choices
, 
 903                                            const wxValidator
& validator
, 
 904                                            const wxString
& name
) 
 908     Create(parent
,id
,value
,pos
,size
,choices
,style
, validator
, name
); 
 911 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 913                                   const wxString
& value
, 
 916                                   const wxArrayString
& choices
, 
 918                                   const wxValidator
& validator
, 
 919                                   const wxString
& name
) 
 922     //wxCArrayString chs(choices); 
 924     //return Create(parent, id, value, pos, size, chs.GetCount(), 
 925     //              chs.GetStrings(), style, validator, name); 
 926     return Create(parent
, id
, value
, pos
, size
, 0, 
 927                   NULL
, style
, validator
, name
); 
 930 bool wxOwnerDrawnComboBox::Create(wxWindow 
*parent
, 
 932                                   const wxString
& value
, 
 936                                   const wxString choices
[], 
 938                                   const wxValidator
& validator
, 
 939                                   const wxString
& name
) 
 942     if ( !Create(parent
, id
, value
, pos
, size
, style
, 
 949     for ( i
=0; i
<n
; i
++ ) 
 950         m_initChs
.Add(choices
[i
]); 
 955 wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox() 
 957     if ( m_popupInterface 
) 
 958         GetVListBoxComboPopup()->ClearClientDatas(); 
 961 void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup
* popup
) 
 965         popup 
= new wxVListBoxComboPopup(); 
 968     wxComboCtrl::DoSetPopupControl(popup
); 
 972     // Add initial choices to the wxVListBox 
 973     if ( !GetVListBoxComboPopup()->GetCount() ) 
 975         GetVListBoxComboPopup()->Populate(m_initChs
); 
 980 // ---------------------------------------------------------------------------- 
 981 // wxOwnerDrawnComboBox item manipulation methods 
 982 // ---------------------------------------------------------------------------- 
 984 void wxOwnerDrawnComboBox::DoClear() 
 986     EnsurePopupControl(); 
 988     GetVListBoxComboPopup()->Clear(); 
 990     // NB: This really needs to be SetValue() instead of ChangeValue(), 
 991     //     as wxTextEntry API expects an event to be sent. 
 992     SetValue(wxEmptyString
); 
 995 void wxOwnerDrawnComboBox::Clear() 
1000 void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n
) 
1002     wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Delete") ); 
1004     if ( GetSelection() == (int) n 
) 
1005         ChangeValue(wxEmptyString
); 
1007     GetVListBoxComboPopup()->Delete(n
); 
1010 unsigned int wxOwnerDrawnComboBox::GetCount() const 
1012     if ( !m_popupInterface 
) 
1013         return m_initChs
.GetCount(); 
1015     return GetVListBoxComboPopup()->GetCount(); 
1018 wxString 
wxOwnerDrawnComboBox::GetString(unsigned int n
) const 
1020     wxCHECK_MSG( IsValid(n
), wxEmptyString
, wxT("invalid index in wxOwnerDrawnComboBox::GetString") ); 
1022     if ( !m_popupInterface 
) 
1023         return m_initChs
.Item(n
); 
1025     return GetVListBoxComboPopup()->GetString(n
); 
1028 void wxOwnerDrawnComboBox::SetString(unsigned int n
, const wxString
& s
) 
1030     EnsurePopupControl(); 
1032     wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::SetString") ); 
1034     GetVListBoxComboPopup()->SetString(n
,s
); 
1037 int wxOwnerDrawnComboBox::FindString(const wxString
& s
, bool bCase
) const 
1039     if ( !m_popupInterface 
) 
1040         return m_initChs
.Index(s
, bCase
); 
1042     return GetVListBoxComboPopup()->FindString(s
, bCase
); 
1045 void wxOwnerDrawnComboBox::Select(int n
) 
1047     EnsurePopupControl(); 
1049     wxCHECK_RET( (n 
== wxNOT_FOUND
) || IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Select") ); 
1051     GetVListBoxComboPopup()->SetSelection(n
); 
1055         str 
= GetVListBoxComboPopup()->GetString(n
); 
1057     // Refresh text portion in control 
1059         m_text
->ChangeValue( str 
); 
1061         m_valueString 
= str
; 
1066 int wxOwnerDrawnComboBox::GetSelection() const 
1068     if ( !m_popupInterface 
) 
1069         return m_initChs
.Index(m_valueString
); 
1071     return GetVListBoxComboPopup()->GetSelection(); 
1074 void wxOwnerDrawnComboBox::GetSelection(long *from
, long *to
) const 
1076     wxComboCtrl::GetSelection(from
, to
); 
1079 int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
, 
1082                                         wxClientDataType type
) 
1084     EnsurePopupControl(); 
1086     const unsigned int count 
= items
.GetCount(); 
1088     if ( HasFlag(wxCB_SORT
) ) 
1092         for ( unsigned int i 
= 0; i 
< count
; ++i 
) 
1094             n 
= GetVListBoxComboPopup()->Append(items
[i
]); 
1095             AssignNewItemClientData(n
, clientData
, i
, type
); 
1102         for ( unsigned int i 
= 0; i 
< count
; ++i
, ++pos 
) 
1104             GetVListBoxComboPopup()->Insert(items
[i
], pos
); 
1105             AssignNewItemClientData(pos
, clientData
, i
, type
); 
1112 void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n
, void* clientData
) 
1114     EnsurePopupControl(); 
1116     GetVListBoxComboPopup()->SetItemClientData(n
, clientData
, 
1117                                                GetClientDataType()); 
1120 void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n
) const 
1122     if ( !m_popupInterface 
) 
1125     return GetVListBoxComboPopup()->GetItemClientData(n
); 
1128 // ---------------------------------------------------------------------------- 
1129 // wxOwnerDrawnComboBox item drawing and measuring default implementations 
1130 // ---------------------------------------------------------------------------- 
1132 void wxOwnerDrawnComboBox::OnDrawItem( wxDC
& dc
, 
1137     if ( flags 
& wxODCB_PAINTING_CONTROL 
) 
1141         if ( !ShouldUseHintText() ) 
1148             wxColour col 
= wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
); 
1149             dc
.SetTextForeground(col
); 
1153                      rect
.x 
+ GetMargins().x
, 
1154                      (rect
.height
-dc
.GetCharHeight())/2 + rect
.y 
); 
1158         dc
.DrawText( GetVListBoxComboPopup()->GetString(item
), rect
.x 
+ 2, rect
.y 
); 
1162 wxCoord 
wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item
) ) const 
1167 wxCoord 
wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item
) ) const 
1172 void wxOwnerDrawnComboBox::OnDrawBackground(wxDC
& dc
, 
1177     // We need only to explicitly draw background for items 
1178     // that should have selected background. Also, call PrepareBackground 
1179     // always when painting the control so that clipping is done properly. 
1181     if ( (flags 
& wxODCB_PAINTING_SELECTED
) || 
1182          ((flags 
& wxODCB_PAINTING_CONTROL
) && HasFlag(wxCB_READONLY
)) ) 
1184         int bgFlags 
= wxCONTROL_SELECTED
; 
1186         if ( !(flags 
& wxODCB_PAINTING_CONTROL
) ) 
1187             bgFlags 
|= wxCONTROL_ISSUBMENU
; 
1189         PrepareBackground(dc
, rect
, bgFlags
); 
1193 #endif // wxUSE_ODCOMBOBOX