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 occurence, 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
.length() )
869 m_value
= m_strings
.Index(strValue
);
872 // ----------------------------------------------------------------------------
873 // wxOwnerDrawnComboBox
874 // ----------------------------------------------------------------------------
877 BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox
, wxComboCtrl
)
881 #if wxUSE_EXTENDED_RTTI
882 IMPLEMENT_DYNAMIC_CLASS2_XTI(wxOwnerDrawnComboBox
, wxComboCtrl
, wxControlWithItems
, "wx/odcombo.h")
884 wxBEGIN_PROPERTIES_TABLE(wxOwnerDrawnComboBox
)
885 wxEND_PROPERTIES_TABLE()
887 wxBEGIN_HANDLERS_TABLE(wxOwnerDrawnComboBox
)
888 wxEND_HANDLERS_TABLE()
890 wxCONSTRUCTOR_5( wxOwnerDrawnComboBox
, wxWindow
* , Parent
, wxWindowID
, Id
, wxString
, Value
, wxPoint
, Position
, wxSize
, Size
)
892 IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox
, wxComboCtrl
, wxControlWithItems
)
895 void wxOwnerDrawnComboBox::Init()
899 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
901 const wxString
& value
,
905 const wxValidator
& validator
,
906 const wxString
& name
)
908 return wxComboCtrl::Create(parent
,id
,value
,pos
,size
,style
,validator
,name
);
911 wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow
*parent
,
913 const wxString
& value
,
916 const wxArrayString
& choices
,
918 const wxValidator
& validator
,
919 const wxString
& name
)
924 Create(parent
,id
,value
,pos
,size
,choices
,style
, validator
, name
);
927 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
929 const wxString
& value
,
932 const wxArrayString
& choices
,
934 const wxValidator
& validator
,
935 const wxString
& name
)
938 //wxCArrayString chs(choices);
940 //return Create(parent, id, value, pos, size, chs.GetCount(),
941 // chs.GetStrings(), style, validator, name);
942 return Create(parent
, id
, value
, pos
, size
, 0,
943 NULL
, style
, validator
, name
);
946 bool wxOwnerDrawnComboBox::Create(wxWindow
*parent
,
948 const wxString
& value
,
952 const wxString choices
[],
954 const wxValidator
& validator
,
955 const wxString
& name
)
958 if ( !Create(parent
, id
, value
, pos
, size
, style
,
965 for ( i
=0; i
<n
; i
++ )
966 m_initChs
.Add(choices
[i
]);
971 wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox()
973 if ( m_popupInterface
)
974 GetVListBoxComboPopup()->ClearClientDatas();
977 void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup
* popup
)
981 popup
= new wxVListBoxComboPopup();
984 wxComboCtrl::DoSetPopupControl(popup
);
988 // Add initial choices to the wxVListBox
989 if ( !GetVListBoxComboPopup()->GetCount() )
991 GetVListBoxComboPopup()->Populate(m_initChs
);
996 // ----------------------------------------------------------------------------
997 // wxOwnerDrawnComboBox item manipulation methods
998 // ----------------------------------------------------------------------------
1000 void wxOwnerDrawnComboBox::DoClear()
1002 EnsurePopupControl();
1004 GetVListBoxComboPopup()->Clear();
1006 // NB: This really needs to be SetValue() instead of ChangeValue(),
1007 // as wxTextEntry API expects an event to be sent.
1008 SetValue(wxEmptyString
);
1011 void wxOwnerDrawnComboBox::Clear()
1016 void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n
)
1018 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Delete") );
1020 if ( GetSelection() == (int) n
)
1021 ChangeValue(wxEmptyString
);
1023 GetVListBoxComboPopup()->Delete(n
);
1026 unsigned int wxOwnerDrawnComboBox::GetCount() const
1028 if ( !m_popupInterface
)
1029 return m_initChs
.GetCount();
1031 return GetVListBoxComboPopup()->GetCount();
1034 wxString
wxOwnerDrawnComboBox::GetString(unsigned int n
) const
1036 wxCHECK_MSG( IsValid(n
), wxEmptyString
, wxT("invalid index in wxOwnerDrawnComboBox::GetString") );
1038 if ( !m_popupInterface
)
1039 return m_initChs
.Item(n
);
1041 return GetVListBoxComboPopup()->GetString(n
);
1044 void wxOwnerDrawnComboBox::SetString(unsigned int n
, const wxString
& s
)
1046 EnsurePopupControl();
1048 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::SetString") );
1050 GetVListBoxComboPopup()->SetString(n
,s
);
1053 int wxOwnerDrawnComboBox::FindString(const wxString
& s
, bool bCase
) const
1055 if ( !m_popupInterface
)
1056 return m_initChs
.Index(s
, bCase
);
1058 return GetVListBoxComboPopup()->FindString(s
, bCase
);
1061 void wxOwnerDrawnComboBox::Select(int n
)
1063 EnsurePopupControl();
1065 wxCHECK_RET( (n
== wxNOT_FOUND
) || IsValid(n
), wxT("invalid index in wxOwnerDrawnComboBox::Select") );
1067 GetVListBoxComboPopup()->SetSelection(n
);
1071 str
= GetVListBoxComboPopup()->GetString(n
);
1073 // Refresh text portion in control
1075 m_text
->ChangeValue( str
);
1077 m_valueString
= str
;
1082 int wxOwnerDrawnComboBox::GetSelection() const
1084 if ( !m_popupInterface
)
1085 return m_initChs
.Index(m_valueString
);
1087 return GetVListBoxComboPopup()->GetSelection();
1090 void wxOwnerDrawnComboBox::GetSelection(long *from
, long *to
) const
1092 wxComboCtrl::GetSelection(from
, to
);
1095 int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
,
1098 wxClientDataType type
)
1100 EnsurePopupControl();
1102 const unsigned int count
= items
.GetCount();
1104 if ( HasFlag(wxCB_SORT
) )
1108 for ( unsigned int i
= 0; i
< count
; ++i
)
1110 n
= GetVListBoxComboPopup()->Append(items
[i
]);
1111 AssignNewItemClientData(n
, clientData
, i
, type
);
1118 for ( unsigned int i
= 0; i
< count
; ++i
, ++pos
)
1120 GetVListBoxComboPopup()->Insert(items
[i
], pos
);
1121 AssignNewItemClientData(pos
, clientData
, i
, type
);
1128 void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n
, void* clientData
)
1130 EnsurePopupControl();
1132 GetVListBoxComboPopup()->SetItemClientData(n
, clientData
,
1133 GetClientDataType());
1136 void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n
) const
1138 if ( !m_popupInterface
)
1141 return GetVListBoxComboPopup()->GetItemClientData(n
);
1144 // ----------------------------------------------------------------------------
1145 // wxOwnerDrawnComboBox item drawing and measuring default implementations
1146 // ----------------------------------------------------------------------------
1148 void wxOwnerDrawnComboBox::OnDrawItem( wxDC
& dc
,
1153 if ( flags
& wxODCB_PAINTING_CONTROL
)
1157 if ( !ShouldUseHintText() )
1164 wxColour col
= wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
);
1165 dc
.SetTextForeground(col
);
1169 rect
.x
+ GetMargins().x
,
1170 (rect
.height
-dc
.GetCharHeight())/2 + rect
.y
);
1174 dc
.DrawText( GetVListBoxComboPopup()->GetString(item
), rect
.x
+ 2, rect
.y
);
1178 wxCoord
wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item
) ) const
1183 wxCoord
wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item
) ) const
1188 void wxOwnerDrawnComboBox::OnDrawBackground(wxDC
& dc
,
1193 // We need only to explicitly draw background for items
1194 // that should have selected background. Also, call PrepareBackground
1195 // always when painting the control so that clipping is done properly.
1197 if ( (flags
& wxODCB_PAINTING_SELECTED
) ||
1198 ((flags
& wxODCB_PAINTING_CONTROL
) && HasFlag(wxCB_READONLY
)) )
1200 int bgFlags
= wxCONTROL_SELECTED
;
1202 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
1203 bgFlags
|= wxCONTROL_ISSUBMENU
;
1205 PrepareBackground(dc
, rect
, bgFlags
);
1209 #endif // wxUSE_ODCOMBOBOX