1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/odcombo.cpp
3 // Purpose: wxOwnerDrawnComboBox, wxVListBoxComboPopup
4 // Author: Jaakko Salli
6 // Created: Apr-30-2006
7 // Copyright: (c) 2005 Jaakko Salli
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
27 #include "wx/odcombo.h"
31 #include "wx/combobox.h"
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
34 #include "wx/dialog.h"
35 #include "wx/textctrl.h"
40 // ============================================================================
42 // ============================================================================
44 // time in milliseconds before partial completion buffer drops
45 #define wxODCB_PARTIAL_COMPLETION_TIME 1000
47 // ----------------------------------------------------------------------------
48 // wxVListBoxComboPopup is a wxVListBox customized to act as a popup control
50 // ----------------------------------------------------------------------------
53 BEGIN_EVENT_TABLE(wxVListBoxComboPopup
, wxVListBox
)
54 EVT_MOTION(wxVListBoxComboPopup::OnMouseMove
)
55 EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey
)
56 EVT_CHAR(wxVListBoxComboPopup::OnChar
)
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 void wxVListBoxComboPopup::SetFocus()
100 // Suppress SetFocus() warning by simply not calling it. This combo popup
101 // has already been designed with the assumption that SetFocus() may not
102 // do anything useful, so it really doesn't need to be called.
106 wxVListBox::SetFocus();
110 bool wxVListBoxComboPopup::LazyCreate()
112 // NB: There is a bug with wxVListBox that can be avoided by creating
113 // it later (bug causes empty space to be shown if initial selection
114 // is at the end of a list longer than the control can show at once).
118 // paint the control itself
119 void wxVListBoxComboPopup::PaintComboControl( wxDC
& dc
, const wxRect
& rect
)
121 if ( !(m_combo
->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT
) )
123 int flags
= wxODCB_PAINTING_CONTROL
;
125 if ( m_combo
->ShouldDrawFocus() )
126 flags
|= wxODCB_PAINTING_SELECTED
;
128 OnDrawBg(dc
, rect
, m_value
, flags
);
132 OnDrawItem(dc
,rect
,m_value
,flags
);
137 wxComboPopup::PaintComboControl(dc
,rect
);
140 void wxVListBoxComboPopup::OnDrawItem(wxDC
& dc
, const wxRect
& rect
, size_t n
) const
142 // TODO: Maybe this code could be moved to wxVListBox::OnPaint?
143 dc
.SetFont(m_useFont
);
147 // Set correct text colour for selected items
148 if ( wxVListBox::GetSelection() == (int) n
)
150 dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) );
151 flags
|= wxODCB_PAINTING_SELECTED
;
155 dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) );
158 OnDrawItem(dc
,rect
,(int)n
,flags
);
161 wxCoord
wxVListBoxComboPopup::OnMeasureItem(size_t n
) const
163 wxOwnerDrawnComboBox
* combo
= (wxOwnerDrawnComboBox
*) m_combo
;
165 wxASSERT_MSG( wxDynamicCast(combo
, wxOwnerDrawnComboBox
),
166 wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
168 wxCoord h
= combo
->OnMeasureItem(n
);
174 wxCoord
wxVListBoxComboPopup::OnMeasureItemWidth(size_t n
) const
176 wxOwnerDrawnComboBox
* combo
= (wxOwnerDrawnComboBox
*) m_combo
;
178 wxASSERT_MSG( wxDynamicCast(combo
, wxOwnerDrawnComboBox
),
179 wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
181 return combo
->OnMeasureItemWidth(n
);
184 void wxVListBoxComboPopup::OnDrawBg( wxDC
& dc
,
189 wxOwnerDrawnComboBox
* combo
= (wxOwnerDrawnComboBox
*) m_combo
;
191 wxASSERT_MSG( wxDynamicCast(combo
, wxOwnerDrawnComboBox
),
192 wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
194 if ( IsCurrent((size_t)item
) && !(flags
& wxODCB_PAINTING_CONTROL
) )
195 flags
|= wxODCB_PAINTING_SELECTED
;
197 combo
->OnDrawBackground(dc
,rect
,item
,flags
);
200 void wxVListBoxComboPopup::OnDrawBackground(wxDC
& dc
, const wxRect
& rect
, size_t n
) const
202 OnDrawBg(dc
,rect
,(int)n
,0);
205 // This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared
206 void wxVListBoxComboPopup::OnDrawItem( wxDC
& dc
, const wxRect
& rect
, int item
, int flags
) const
208 wxOwnerDrawnComboBox
* combo
= (wxOwnerDrawnComboBox
*) m_combo
;
210 wxASSERT_MSG( wxDynamicCast(combo
, wxOwnerDrawnComboBox
),
211 wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
213 combo
->OnDrawItem(dc
,rect
,item
,flags
);
216 void wxVListBoxComboPopup::DismissWithEvent()
218 StopPartialCompletion();
220 int selection
= wxVListBox::GetSelection();
224 if ( selection
!= wxNOT_FOUND
)
225 m_stringValue
= m_strings
[selection
];
227 m_stringValue
= wxEmptyString
;
229 if ( m_stringValue
!= m_combo
->GetValue() )
230 m_combo
->SetValueByUser(m_stringValue
);
234 SendComboBoxEvent(selection
);
237 void wxVListBoxComboPopup::SendComboBoxEvent( int selection
)
239 wxCommandEvent
evt(wxEVT_COMBOBOX
,m_combo
->GetId());
241 evt
.SetEventObject(m_combo
);
243 evt
.SetInt(selection
);
245 // Set client data, if any
246 if ( selection
>= 0 && (int)m_clientDatas
.GetCount() > selection
)
248 void* clientData
= m_clientDatas
[selection
];
249 if ( m_clientDataItemsType
== wxClientData_Object
)
250 evt
.SetClientObject((wxClientData
*)clientData
);
252 evt
.SetClientData(clientData
);
255 m_combo
->GetEventHandler()->AddPendingEvent(evt
);
258 // returns true if key was consumed
259 bool wxVListBoxComboPopup::HandleKey( int keycode
, bool saturate
, wxChar keychar
)
261 const int itemCount
= GetCount();
263 // keys do nothing in the empty control and returning immediately avoids
264 // using invalid indices below
269 int comboStyle
= m_combo
->GetWindowStyle();
273 // we have character equivalent of the keycode; filter out these that
274 // are not printable characters
275 if ( !wxIsprint(keychar
) )
279 const bool readOnly
= (comboStyle
& wxCB_READONLY
) != 0;
281 if ( keycode
== WXK_DOWN
|| keycode
== WXK_NUMPAD_DOWN
|| ( keycode
== WXK_RIGHT
&& readOnly
) )
284 StopPartialCompletion();
286 else if ( keycode
== WXK_UP
|| keycode
== WXK_NUMPAD_UP
|| ( keycode
== WXK_LEFT
&& readOnly
) )
289 StopPartialCompletion();
291 else if ( keycode
== WXK_PAGEDOWN
|| keycode
== WXK_NUMPAD_PAGEDOWN
)
294 StopPartialCompletion();
296 else if ( keycode
== WXK_PAGEUP
|| keycode
== WXK_NUMPAD_PAGEUP
)
299 StopPartialCompletion();
301 else if ( ( keycode
== WXK_HOME
|| keycode
== WXK_NUMPAD_HOME
) && readOnly
)
304 StopPartialCompletion();
306 else if ( ( keycode
== WXK_END
|| keycode
== WXK_NUMPAD_END
) && readOnly
)
309 StopPartialCompletion();
311 else if ( keychar
&& readOnly
)
313 // Try partial completion
315 // find the new partial completion string
317 if (m_partialCompletionTimer
.IsRunning())
318 m_partialCompletionString
+=wxString(keychar
);
320 #endif // wxUSE_TIMER
321 m_partialCompletionString
=wxString(keychar
);
323 // now search through the values to see if this is found
325 unsigned int length
=m_partialCompletionString
.length();
327 for (i
=0; i
<itemCount
; i
++)
329 wxString item
=GetString(i
);
330 if (( item
.length() >= length
) && (! m_partialCompletionString
.CmpNoCase(item
.Left(length
))))
339 StopPartialCompletion();
341 return true; // to stop the first value being set
347 m_partialCompletionTimer
.Start(wxODCB_PARTIAL_COMPLETION_TIME
, true);
348 #endif // wxUSE_TIMER
356 if ( value
>= itemCount
)
357 value
= itemCount
- 1;
358 else if ( value
< 0 )
363 if ( value
>= itemCount
)
365 else if ( value
< 0 )
369 if ( value
== m_value
)
370 // Even if value was same, don't skip the event
371 // (good for consistency)
375 m_combo
->ChangeValue(m_strings
[value
]);
377 // The m_combo->SetValue() call above sets m_value to the index of this
378 // string. But if there are more identical string, the index is of the
379 // first occurrence, which may be wrong, so set the index explicitly here,
380 // _after_ the SetValue() call.
383 SendComboBoxEvent(m_value
);
388 // stop partial completion
389 void wxVListBoxComboPopup::StopPartialCompletion()
391 m_partialCompletionString
= wxEmptyString
;
393 m_partialCompletionTimer
.Stop();
394 #endif // wxUSE_TIMER
397 void wxVListBoxComboPopup::OnComboDoubleClick()
399 // Cycle on dclick (disable saturation to allow true cycling).
400 if ( !::wxGetKeyState(WXK_SHIFT
) )
401 HandleKey(WXK_DOWN
,false);
403 HandleKey(WXK_UP
,false);
406 void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent
& event
)
408 // Saturated key movement on
409 if ( !HandleKey(event
.GetKeyCode(), true) )
413 void wxVListBoxComboPopup::OnComboCharEvent( wxKeyEvent
& event
)
415 // unlike in OnComboKeyEvent, wxEVT_CHAR contains meaningful
416 // printable character information, so pass it
418 const wxChar charcode
= event
.GetUnicodeKey();
420 const wxChar charcode
= (wxChar
)event
.GetKeyCode();
423 if ( !HandleKey(event
.GetKeyCode(), true, charcode
) )
427 void wxVListBoxComboPopup::OnPopup()
429 // *must* set value after size is set (this is because of a vlbox bug)
430 wxVListBox::SetSelection(m_value
);
433 void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent
& event
)
437 // Move selection to cursor if it is inside the popup
439 int y
= event
.GetPosition().y
;
440 int fromBottom
= GetClientSize().y
- y
;
442 // Since in any case we need to find out if the last item is only
443 // partially visible, we might just as well replicate the HitTest
445 const size_t lineMax
= GetVisibleEnd();
446 for ( size_t line
= GetVisibleBegin(); line
< lineMax
; line
++ )
448 y
-= OnGetRowHeight(line
);
451 // Only change selection if item is fully visible
452 if ( (y
+ fromBottom
) >= 0 )
454 wxVListBox::SetSelection((int)line
);
461 void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent
& WXUNUSED(event
))
466 void wxVListBoxComboPopup::OnKey(wxKeyEvent
& event
)
468 // Hide popup if certain key or key combination was pressed
469 if ( m_combo
->IsKeyPopupToggle(event
) )
471 StopPartialCompletion();
474 else if ( event
.AltDown() )
476 // On both wxGTK and wxMSW, pressing Alt down seems to
477 // completely freeze things in popup (ie. arrow keys and
478 // enter won't work).
481 // Select item if ENTER is pressed
482 else if ( event
.GetKeyCode() == WXK_RETURN
|| event
.GetKeyCode() == WXK_NUMPAD_ENTER
)
488 // completion is handled in OnChar() below
493 void wxVListBoxComboPopup::OnChar(wxKeyEvent
& event
)
495 if ( m_combo
->GetWindowStyle() & wxCB_READONLY
)
497 // Process partial completion key codes here, but not the arrow keys as
498 // the base class will do that for us
500 const wxChar charcode
= event
.GetUnicodeKey();
502 const wxChar charcode
= (wxChar
)event
.GetKeyCode();
504 if ( wxIsprint(charcode
) )
506 OnComboCharEvent(event
);
507 SetSelection(m_value
); // ensure the highlight bar moves
508 return; // don't skip the event
515 void wxVListBoxComboPopup::Insert( const wxString
& item
, int pos
)
517 // Need to change selection?
519 if ( !(m_combo
->GetWindowStyle() & wxCB_READONLY
) &&
520 m_combo
->GetValue() == item
)
525 m_strings
.Insert(item
,pos
);
526 if ( (int)m_clientDatas
.size() >= pos
)
527 m_clientDatas
.Insert(NULL
, pos
);
529 m_widths
.Insert(-1,pos
);
530 m_widthsDirty
= true;
533 wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 );
536 int wxVListBoxComboPopup::Append(const wxString
& item
)
538 int pos
= (int)m_strings
.GetCount();
540 if ( m_combo
->GetWindowStyle() & wxCB_SORT
)
543 // TODO: Could be optimized with binary search
544 wxArrayString strings
= m_strings
;
547 for ( i
=0; i
<strings
.GetCount(); i
++ )
549 if ( item
.CmpNoCase(strings
.Item(i
)) <= 0 )
562 void wxVListBoxComboPopup::Clear()
574 m_value
= wxNOT_FOUND
;
577 wxVListBox::SetItemCount(0);
580 void wxVListBoxComboPopup::ClearClientDatas()
582 if ( m_clientDataItemsType
== wxClientData_Object
)
585 for ( i
=0; i
<m_clientDatas
.GetCount(); i
++ )
586 delete (wxClientData
*) m_clientDatas
[i
];
589 m_clientDatas
.Empty();
592 void wxVListBoxComboPopup::SetItemClientData( unsigned int n
,
594 wxClientDataType clientDataItemsType
)
596 // It should be sufficient to update this variable only here
597 m_clientDataItemsType
= clientDataItemsType
;
599 m_clientDatas
[n
] = clientData
;
604 void* wxVListBoxComboPopup::GetItemClientData(unsigned int n
) const
606 if ( m_clientDatas
.GetCount() > n
)
607 return m_clientDatas
[n
];
612 void wxVListBoxComboPopup::Delete( unsigned int item
)
614 // Remove client data, if set
615 if ( m_clientDatas
.GetCount() )
617 if ( m_clientDataItemsType
== wxClientData_Object
)
618 delete (wxClientData
*) m_clientDatas
[item
];
620 m_clientDatas
.RemoveAt(item
);
623 m_strings
.RemoveAt(item
);
624 m_widths
.RemoveAt(item
);
626 if ( (int)item
== m_widestItem
)
629 int sel
= GetSelection();
632 wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
635 if ( (int)item
< sel
)
637 else if ( (int)item
== sel
)
638 SetSelection(wxNOT_FOUND
);
641 int wxVListBoxComboPopup::FindString(const wxString
& s
, bool bCase
) const
643 return m_strings
.Index(s
, bCase
);
646 bool wxVListBoxComboPopup::FindItem(const wxString
& item
, wxString
* trueItem
)
648 int idx
= m_strings
.Index(item
, false);
649 if ( idx
== wxNOT_FOUND
)
651 if ( trueItem
!= NULL
)
652 *trueItem
= m_strings
[idx
];
656 unsigned int wxVListBoxComboPopup::GetCount() const
658 return m_strings
.GetCount();
661 wxString
wxVListBoxComboPopup::GetString( int item
) const
663 return m_strings
[item
];
666 void wxVListBoxComboPopup::SetString( int item
, const wxString
& str
)
668 m_strings
[item
] = str
;
669 ItemWidthChanged(item
);
672 wxString
wxVListBoxComboPopup::GetStringValue() const
674 return m_stringValue
;
677 void wxVListBoxComboPopup::SetSelection( int item
)
679 wxCHECK_RET( item
== wxNOT_FOUND
|| ((unsigned int)item
< GetCount()),
680 wxT("invalid index in wxVListBoxComboPopup::SetSelection") );
685 m_stringValue
= m_strings
[item
];
687 m_stringValue
= wxEmptyString
;
690 wxVListBox::SetSelection(item
);
693 int wxVListBoxComboPopup::GetSelection() const
698 void wxVListBoxComboPopup::SetStringValue( const wxString
& value
)
700 int index
= m_strings
.Index(value
);
702 m_stringValue
= value
;
704 if ( index
>= 0 && index
< (int)wxVListBox::GetItemCount() )
706 wxVListBox::SetSelection(index
);
711 void wxVListBoxComboPopup::CalcWidths()
713 bool doFindWidest
= m_findWidest
;
715 // Measure items with dirty width.
719 unsigned int n
= m_widths
.GetCount();
720 int dirtyHandled
= 0;
721 wxArrayInt
& widths
= m_widths
;
723 // I think using wxDC::GetTextExtent is faster than
724 // wxWindow::GetTextExtent (assuming same dc is used
725 // for all calls, as we do here).
726 wxClientDC
dc(m_combo
);
727 if ( !m_useFont
.IsOk() )
728 m_useFont
= m_combo
->GetFont();
729 dc
.SetFont(m_useFont
);
731 for ( i
=0; i
<n
; i
++ )
735 wxCoord x
= OnMeasureItemWidth(i
);
739 const wxString
& text
= m_strings
[i
];
741 // To make sure performance won't suck in extreme scenarios,
742 // we'll estimate length after some arbitrary number of items
743 // have been checked precily.
744 if ( dirtyHandled
< 1024 )
747 dc
.GetTextExtent(text
, &x
, &y
, 0, 0);
752 x
= text
.length() * (dc
.GetCharWidth()+1);
758 if ( x
>= m_widestWidth
)
761 m_widestItem
= (int)i
;
763 else if ( (int)i
== m_widestItem
)
765 // Width of previously widest item has been decreased, so
766 // we'll have to check all to find current widest item.
774 m_widthsDirty
= false;
780 unsigned int n
= m_widths
.GetCount();
785 for ( i
=0; i
<n
; i
++ )
795 m_widestWidth
= bestWidth
;
796 m_widestItem
= bestIndex
;
798 m_findWidest
= false;
802 wxSize
wxVListBoxComboPopup::GetAdjustedSize( int minWidth
, int prefHeight
, int maxHeight
)
806 maxHeight
-= 2; // Must take borders into account
808 if ( m_strings
.GetCount() )
810 if ( prefHeight
> 0 )
813 if ( height
> maxHeight
)
816 int totalHeight
= GetTotalHeight(); // + 3;
818 // Take borders into account on Mac or scrollbars always appear
819 #if defined(__WXMAC__)
822 if ( height
>= totalHeight
)
824 height
= totalHeight
;
828 // Adjust height to a multiple of the height of the first item
829 // NB: Calculations that take variable height into account
831 int fih
= GetLineHeight(0);
832 height
-= height
% fih
;
840 // Take scrollbar into account in width calculations
841 int widestWidth
= m_widestWidth
+ wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
);
842 return wxSize(minWidth
> widestWidth
? minWidth
: widestWidth
,
846 //void wxVListBoxComboPopup::Populate( int n, const wxString choices[] )
847 void wxVListBoxComboPopup::Populate( const wxArrayString
& choices
)
851 int n
= choices
.GetCount();
853 for ( i
=0; i
<n
; i
++ )
855 const wxString
& item
= choices
.Item(i
);
859 m_widths
.SetCount(n
,-1);
860 m_widthsDirty
= true;
863 wxVListBox::SetItemCount(n
);
865 // Sort the initial choices
866 if ( m_combo
->GetWindowStyle() & wxCB_SORT
)
869 // Find initial selection
870 wxString strValue
= m_combo
->GetValue();
871 if ( !strValue
.empty() )
872 m_value
= m_strings
.Index(strValue
);
875 // ----------------------------------------------------------------------------
876 // wxOwnerDrawnComboBox
877 // ----------------------------------------------------------------------------
880 BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox
, wxComboCtrl
)
883 void wxOwnerDrawnComboBox::Init()
887 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
889 const wxString
& value
,
893 const wxValidator
& validator
,
894 const wxString
& name
)
896 return wxComboCtrl::Create(parent
,id
,value
,pos
,size
,style
,validator
,name
);
899 wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow
*parent
,
901 const wxString
& value
,
904 const wxArrayString
& choices
,
906 const wxValidator
& validator
,
907 const wxString
& name
)
911 Create(parent
,id
,value
,pos
,size
,choices
,style
, validator
, name
);
914 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
916 const wxString
& value
,
919 const wxArrayString
& choices
,
921 const wxValidator
& validator
,
922 const wxString
& name
)
925 //wxCArrayString chs(choices);
927 //return Create(parent, id, value, pos, size, chs.GetCount(),
928 // chs.GetStrings(), style, validator, name);
929 return Create(parent
, id
, value
, pos
, size
, 0,
930 NULL
, style
, validator
, name
);
933 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
935 const wxString
& value
,
939 const wxString choices
[],
941 const wxValidator
& validator
,
942 const wxString
& name
)
945 if ( !Create(parent
, id
, value
, pos
, size
, style
,
952 for ( i
=0; i
<n
; i
++ )
953 m_initChs
.Add(choices
[i
]);
958 wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox()
960 if ( m_popupInterface
)
961 GetVListBoxComboPopup()->ClearClientDatas();
964 void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup
* popup
)
968 popup
= new wxVListBoxComboPopup();
971 wxComboCtrl::DoSetPopupControl(popup
);
975 // Add initial choices to the wxVListBox
976 if ( !GetVListBoxComboPopup()->GetCount() )
978 GetVListBoxComboPopup()->Populate(m_initChs
);
983 // ----------------------------------------------------------------------------
984 // wxOwnerDrawnComboBox item manipulation methods
985 // ----------------------------------------------------------------------------
987 void wxOwnerDrawnComboBox::DoClear()
989 EnsurePopupControl();
991 GetVListBoxComboPopup()->Clear();
993 // NB: This really needs to be SetValue() instead of ChangeValue(),
994 // as wxTextEntry API expects an event to be sent.
995 SetValue(wxEmptyString
);
998 void wxOwnerDrawnComboBox::Clear()
1003 void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n
)
1005 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Delete") );
1007 if ( GetSelection() == (int) n
)
1008 ChangeValue(wxEmptyString
);
1010 GetVListBoxComboPopup()->Delete(n
);
1013 unsigned int wxOwnerDrawnComboBox::GetCount() const
1015 if ( !m_popupInterface
)
1016 return m_initChs
.GetCount();
1018 return GetVListBoxComboPopup()->GetCount();
1021 wxString
wxOwnerDrawnComboBox::GetString(unsigned int n
) const
1023 wxCHECK_MSG( IsValid(n
), wxEmptyString
, wxT("invalid index in wxOwnerDrawnComboBox::GetString") );
1025 if ( !m_popupInterface
)
1026 return m_initChs
.Item(n
);
1028 return GetVListBoxComboPopup()->GetString(n
);
1031 void wxOwnerDrawnComboBox::SetString(unsigned int n
, const wxString
& s
)
1033 EnsurePopupControl();
1035 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::SetString") );
1037 GetVListBoxComboPopup()->SetString(n
,s
);
1040 int wxOwnerDrawnComboBox::FindString(const wxString
& s
, bool bCase
) const
1042 if ( !m_popupInterface
)
1043 return m_initChs
.Index(s
, bCase
);
1045 return GetVListBoxComboPopup()->FindString(s
, bCase
);
1048 void wxOwnerDrawnComboBox::Select(int n
)
1050 EnsurePopupControl();
1052 wxCHECK_RET( (n
== wxNOT_FOUND
) || IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Select") );
1054 GetVListBoxComboPopup()->SetSelection(n
);
1058 str
= GetVListBoxComboPopup()->GetString(n
);
1060 // Refresh text portion in control
1062 m_text
->ChangeValue( str
);
1064 m_valueString
= str
;
1069 int wxOwnerDrawnComboBox::GetSelection() const
1071 if ( !m_popupInterface
)
1072 return m_initChs
.Index(m_valueString
);
1074 return GetVListBoxComboPopup()->GetSelection();
1077 void wxOwnerDrawnComboBox::GetSelection(long *from
, long *to
) const
1079 wxComboCtrl::GetSelection(from
, to
);
1082 int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
,
1085 wxClientDataType type
)
1087 EnsurePopupControl();
1089 const unsigned int count
= items
.GetCount();
1091 if ( HasFlag(wxCB_SORT
) )
1095 for ( unsigned int i
= 0; i
< count
; ++i
)
1097 n
= GetVListBoxComboPopup()->Append(items
[i
]);
1098 AssignNewItemClientData(n
, clientData
, i
, type
);
1105 for ( unsigned int i
= 0; i
< count
; ++i
, ++pos
)
1107 GetVListBoxComboPopup()->Insert(items
[i
], pos
);
1108 AssignNewItemClientData(pos
, clientData
, i
, type
);
1115 void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n
, void* clientData
)
1117 EnsurePopupControl();
1119 GetVListBoxComboPopup()->SetItemClientData(n
, clientData
,
1120 GetClientDataType());
1123 void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n
) const
1125 if ( !m_popupInterface
)
1128 return GetVListBoxComboPopup()->GetItemClientData(n
);
1131 // ----------------------------------------------------------------------------
1132 // wxOwnerDrawnComboBox item drawing and measuring default implementations
1133 // ----------------------------------------------------------------------------
1135 void wxOwnerDrawnComboBox::OnDrawItem( wxDC
& dc
,
1140 if ( flags
& wxODCB_PAINTING_CONTROL
)
1144 if ( !ShouldUseHintText() )
1151 wxColour col
= wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
);
1152 dc
.SetTextForeground(col
);
1156 rect
.x
+ GetMargins().x
,
1157 (rect
.height
-dc
.GetCharHeight())/2 + rect
.y
);
1161 dc
.DrawText( GetVListBoxComboPopup()->GetString(item
), rect
.x
+ 2, rect
.y
);
1165 wxCoord
wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item
) ) const
1170 wxCoord
wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item
) ) const
1175 wxSize
wxOwnerDrawnComboBox::DoGetBestSize() const
1177 wxSize
best( wxComboCtrlBase::DoGetBestSize() );
1179 if ( GetCount() > 0 )
1181 wxOwnerDrawnComboBox
* odc
= const_cast<wxOwnerDrawnComboBox
*>(this);
1182 best
.x
= odc
->GetWidestItemWidth();
1183 // TODO: this class may also have GetHightestItemHeight() and
1184 // GetHightestItem() methods, and so set the whole (edit part + arrow)
1185 // control's height according with this max height, not only max width.
1188 return GetSizeFromTextSize(best
.x
);
1191 void wxOwnerDrawnComboBox::OnDrawBackground(wxDC
& dc
,
1196 // We need only to explicitly draw background for items
1197 // that should have selected background. Also, call PrepareBackground
1198 // always when painting the control so that clipping is done properly.
1200 if ( (flags
& wxODCB_PAINTING_SELECTED
) ||
1201 ((flags
& wxODCB_PAINTING_CONTROL
) && HasFlag(wxCB_READONLY
)) )
1203 int bgFlags
= wxCONTROL_SELECTED
;
1205 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
1206 bgFlags
|= wxCONTROL_ISSUBMENU
;
1208 PrepareBackground(dc
, rect
, bgFlags
);
1212 #endif // wxUSE_ODCOMBOBOX