#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/dialog.h"
+ #include "wx/textctrl.h"
#endif
#include "wx/combo.h"
{
if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) )
{
- OnDrawBg(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
+ int flags = wxODCB_PAINTING_CONTROL;
+
+ if ( m_combo->ShouldDrawFocus() )
+ flags |= wxODCB_PAINTING_SELECTED;
+
+ OnDrawBg(dc, rect, m_value, flags);
+
if ( m_value >= 0 )
{
- OnDrawItem(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
+ OnDrawItem(dc,rect,m_value,flags);
return;
}
}
// TODO: Maybe this code could be moved to wxVListBox::OnPaint?
dc.SetFont(m_useFont);
+ int flags = 0;
+
// Set correct text colour for selected items
if ( wxVListBox::GetSelection() == (int) n )
+ {
dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
+ flags |= wxODCB_PAINTING_SELECTED;
+ }
else
+ {
dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+ }
- OnDrawItem(dc,rect,(int)n,0);
+ OnDrawItem(dc,rect,(int)n,flags);
}
wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const
wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
+ if ( IsCurrent((size_t)item) && !(flags & wxODCB_PAINTING_CONTROL) )
+ flags |= wxODCB_PAINTING_SELECTED;
+
combo->OnDrawBackground(dc,rect,item,flags);
}
Dismiss();
- wxString valStr;
if ( selection != wxNOT_FOUND )
- valStr = m_strings[selection];
+ m_stringValue = m_strings[selection];
else
- valStr = wxEmptyString;
+ m_stringValue = wxEmptyString;
- m_value = selection;
+ if ( m_stringValue != m_combo->GetValue() )
+ m_combo->SetValueWithEvent(m_stringValue);
- if ( valStr != m_combo->GetValue() )
- m_combo->SetValue(valStr);
+ m_value = selection;
SendComboBoxEvent(selection);
}
// returns true if key was consumed
bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode )
{
+ const int itemCount = GetCount();
+
+ // keys do nothing in the empty control and returning immediately avoids
+ // using invalid indices below
+ if ( !itemCount )
+ return false;
+
int value = m_value;
- int itemCount = GetCount();
int comboStyle = m_combo->GetWindowStyle();
// this is the character equivalent of the code
- wxChar keychar=0;
- if ((keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode))
- {
- keychar = (wxChar)keycode;
- }
- else if (unicode>0)
+ wxChar keychar = 0;
+ if ( keycode < WXK_START )
{
- keychar = unicode;
+ if ( unicode > 0 )
+ {
+ if ( wxIsprint(unicode) )
+ keychar = unicode;
+ }
+ else if ( wxIsprint(keycode) )
+ {
+ keychar = (wxChar) keycode;
+ }
}
if ( keycode == WXK_DOWN || keycode == WXK_RIGHT )
value-=10;
StopPartialCompletion();
}
- else if ( comboStyle & wxCB_READONLY )
+ else if ( keychar && (comboStyle & wxCB_READONLY) )
{
// Try partial completion
const size_t lineMax = GetVisibleEnd();
for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
{
- y -= OnGetLineHeight(line);
+ y -= OnGetRowHeight(line);
if ( y < 0 )
{
// Only change selection if item is fully visible
void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
{
- // Select item if ENTER is pressed
- if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
- {
- DismissWithEvent();
- }
- // Hide popup if ESC is pressed
- else if ( event.GetKeyCode() == WXK_ESCAPE )
+ // Hide popup if certain key or key combination was pressed
+ if ( m_combo->IsKeyPopupToggle(event) )
{
StopPartialCompletion();
Dismiss();
}
+ else if ( event.AltDown() )
+ {
+ // On both wxGTK and wxMSW, pressing Alt down seems to
+ // completely freeze things in popup (ie. arrow keys and
+ // enter won't work).
+ return;
+ }
+ // Select item if ENTER is pressed
+ else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
+ {
+ DismissWithEvent();
+ }
else
{
int comboStyle = m_combo->GetWindowStyle();
}
m_strings.Insert(item,pos);
+ if ( (int)m_clientDatas.size() >= pos )
+ m_clientDatas.Insert(NULL, pos);
+
m_widths.Insert(-1,pos);
m_widthsDirty = true;
// It should be sufficient to update this variable only here
m_clientDataItemsType = clientDataItemsType;
- m_clientDatas.SetCount(n+1,NULL);
m_clientDatas[n] = clientData;
ItemWidthChanged(n);
if ( (int)item == m_widestItem )
m_findWidest = true;
+ int sel = GetSelection();
+
if ( IsCreated() )
wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
+
+ // Fix selection
+ if ( (int)item < sel )
+ SetSelection(sel-1);
+ else if ( (int)item == sel )
+ SetSelection(wxNOT_FOUND);
}
int wxVListBoxComboPopup::FindString(const wxString& s, bool bCase) const
wxString wxVListBoxComboPopup::GetStringValue() const
{
- if ( m_value >= 0 )
- return m_strings[m_value];
- return wxEmptyString;
+ return m_stringValue;
}
void wxVListBoxComboPopup::SetSelection( int item )
m_value = item;
+ if ( item >= 0 )
+ m_stringValue = m_strings[item];
+ else
+ m_stringValue = wxEmptyString;
+
if ( IsCreated() )
wxVListBox::SetSelection(item);
}
{
int index = m_strings.Index(value);
- m_value = index;
+ m_stringValue = value;
- if ( index >= -1 && index < (int)wxVListBox::GetItemCount() )
+ if ( index >= 0 && index < (int)wxVListBox::GetItemCount() )
+ {
wxVListBox::SetSelection(index);
+ m_value = index;
+ }
}
void wxVListBoxComboPopup::CalcWidths()
{
int height = 250;
+ maxHeight -= 2; // Must take borders into account
+
if ( m_strings.GetCount() )
{
if ( prefHeight > 0 )
// NB: Calculations that take variable height into account
// are unnecessary.
int fih = GetLineHeight(0);
- int shown = height/fih;
- height = shown * fih;
+ height -= height % fih;
}
}
else
END_EVENT_TABLE()
+#if wxUSE_EXTENDED_RTTI
+IMPLEMENT_DYNAMIC_CLASS2_XTI(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems, "wx/odcombo.h")
+
+wxBEGIN_PROPERTIES_TABLE(wxOwnerDrawnComboBox)
+wxEND_PROPERTIES_TABLE()
+
+wxBEGIN_HANDLERS_TABLE(wxOwnerDrawnComboBox)
+wxEND_HANDLERS_TABLE()
+
+wxCONSTRUCTOR_5( wxOwnerDrawnComboBox , wxWindow* , Parent , wxWindowID , Id , wxString , Value , wxPoint , Position , wxSize , Size )
+#else
IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems)
+#endif
void wxOwnerDrawnComboBox::Init()
{
// wxOwnerDrawnComboBox item manipulation methods
// ----------------------------------------------------------------------------
-void wxOwnerDrawnComboBox::Clear()
+void wxOwnerDrawnComboBox::DoClear()
{
EnsurePopupControl();
SetValue(wxEmptyString);
}
-void wxOwnerDrawnComboBox::Delete(unsigned int n)
+void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n)
{
wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
return GetVListBoxComboPopup()->GetSelection();
}
-int wxOwnerDrawnComboBox::DoAppend(const wxString& item)
+int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+ unsigned int pos,
+ void **clientData,
+ wxClientDataType type)
{
EnsurePopupControl();
- wxASSERT(m_popupInterface);
- return GetVListBoxComboPopup()->Append(item);
-}
+ const unsigned int count = items.GetCount();
-int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
- EnsurePopupControl();
+ if ( HasFlag(wxCB_SORT) )
+ {
+ int n = pos;
- wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
- wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
+ for ( unsigned int i = 0; i < count; ++i )
+ {
+ int n = GetVListBoxComboPopup()->Append(items[i]);
+ AssignNewItemClientData(n, clientData, i, type);
+ }
- GetVListBoxComboPopup()->Insert(item,pos);
+ return n;
+ }
+ else
+ {
+ for ( unsigned int i = 0; i < count; ++i, ++pos )
+ {
+ GetVListBoxComboPopup()->Insert(items[i], pos);
+ AssignNewItemClientData(pos, clientData, i, type);
+ }
- return pos;
+ return pos - 1;
+ }
}
void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n, void* clientData)
{
EnsurePopupControl();
- GetVListBoxComboPopup()->SetItemClientData(n,clientData,m_clientDataItemsType);
+ GetVListBoxComboPopup()->SetItemClientData(n, clientData,
+ GetClientDataType());
}
void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const
return GetVListBoxComboPopup()->GetItemClientData(n);
}
-void wxOwnerDrawnComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
- DoSetItemClientData(n, (void*) clientData);
-}
-
-wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(unsigned int n) const
-{
- return (wxClientData*) DoGetItemClientData(n);
-}
-
// ----------------------------------------------------------------------------
// wxOwnerDrawnComboBox item drawing and measuring default implementations
// ----------------------------------------------------------------------------
return -1;
}
-void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc, const wxRect& rect, int item, int flags) const
+void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc,
+ const wxRect& rect,
+ int WXUNUSED(item),
+ int flags) const
{
- // we need to render selected and current items differently
- if ( GetVListBoxComboPopup()->IsCurrent((size_t)item) ||
- (flags & wxODCB_PAINTING_CONTROL) )
+ // We need only to explicitly draw background for items
+ // that should have selected background. Also, call PrepareBackground
+ // always when painting the control so that clipping is done properly.
+
+ if ( (flags & wxODCB_PAINTING_SELECTED) ||
+ ((flags & wxODCB_PAINTING_CONTROL) && HasFlag(wxCB_READONLY)) )
{
- int focusFlag = wxCONTROL_SELECTED;
+ int bgFlags = wxCONTROL_SELECTED;
- if ( flags & wxODCB_PAINTING_CONTROL != wxODCB_PAINTING_CONTROL )
- focusFlag |= wxCONTROL_ISSUBMENU;
+ if ( !(flags & wxODCB_PAINTING_CONTROL) )
+ bgFlags |= wxCONTROL_ISSUBMENU;
- DrawFocusBackground(dc, rect, focusFlag );
+ PrepareBackground(dc, rect, bgFlags);
}
- //else: do nothing for the normal items
}
#endif // wxUSE_ODCOMBOBOX