// Author: Jaakko Salli
// Modified by:
// Created: Apr-30-2006
-// RCS-ID: $Id$
// Copyright: (c) 2005 Jaakko Salli
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(wxVListBoxComboPopup, wxVListBox)
EVT_MOTION(wxVListBoxComboPopup::OnMouseMove)
EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey)
+ EVT_CHAR(wxVListBoxComboPopup::OnChar)
EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick)
END_EVENT_TABLE()
Clear();
}
+void wxVListBoxComboPopup::SetFocus()
+{
+ // Suppress SetFocus() warning by simply not calling it. This combo popup
+ // has already been designed with the assumption that SetFocus() may not
+ // do anything useful, so it really doesn't need to be called.
+#ifdef __WXMSW__
+ //
+#else
+ wxVListBox::SetFocus();
+#endif
+}
+
bool wxVListBoxComboPopup::LazyCreate()
{
// NB: There is a bug with wxVListBox that can be avoided by creating
{
wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
- wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxASSERT_MSG( wxDynamicCast(combo, wxOwnerDrawnComboBox),
wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
wxCoord h = combo->OnMeasureItem(n);
{
wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
- wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxASSERT_MSG( wxDynamicCast(combo, wxOwnerDrawnComboBox),
wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
return combo->OnMeasureItemWidth(n);
{
wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
- wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxASSERT_MSG( wxDynamicCast(combo, wxOwnerDrawnComboBox),
wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
if ( IsCurrent((size_t)item) && !(flags & wxODCB_PAINTING_CONTROL) )
{
wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
- wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
+ wxASSERT_MSG( wxDynamicCast(combo, wxOwnerDrawnComboBox),
wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
combo->OnDrawItem(dc,rect,item,flags);
m_stringValue = wxEmptyString;
if ( m_stringValue != m_combo->GetValue() )
- m_combo->SetValueWithEvent(m_stringValue);
+ m_combo->SetValueByUser(m_stringValue);
m_value = selection;
void wxVListBoxComboPopup::SendComboBoxEvent( int selection )
{
- wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
+ wxCommandEvent evt(wxEVT_COMBOBOX,m_combo->GetId());
evt.SetEventObject(m_combo);
}
// returns true if key was consumed
-bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode )
+bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar keychar )
{
const int itemCount = GetCount();
int value = m_value;
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))
+ if ( keychar > 0 )
{
- keychar = (wxChar)keycode;
- }
- else if (unicode>0)
- {
- keychar = unicode;
+ // we have character equivalent of the keycode; filter out these that
+ // are not printable characters
+ if ( !wxIsprint(keychar) )
+ keychar = 0;
}
- if ( keycode == WXK_DOWN || keycode == WXK_RIGHT )
+ const bool readOnly = (comboStyle & wxCB_READONLY) != 0;
+
+ if ( keycode == WXK_DOWN || keycode == WXK_NUMPAD_DOWN || ( keycode == WXK_RIGHT && readOnly ) )
{
value++;
StopPartialCompletion();
}
- else if ( keycode == WXK_UP || keycode == WXK_LEFT )
+ else if ( keycode == WXK_UP || keycode == WXK_NUMPAD_UP || ( keycode == WXK_LEFT && readOnly ) )
{
value--;
StopPartialCompletion();
}
- else if ( keycode == WXK_PAGEDOWN )
+ else if ( keycode == WXK_PAGEDOWN || keycode == WXK_NUMPAD_PAGEDOWN )
{
value+=10;
StopPartialCompletion();
}
- else if ( keycode == WXK_PAGEUP )
+ else if ( keycode == WXK_PAGEUP || keycode == WXK_NUMPAD_PAGEUP )
{
value-=10;
StopPartialCompletion();
}
- else if ( comboStyle & wxCB_READONLY )
+ else if ( ( keycode == WXK_HOME || keycode == WXK_NUMPAD_HOME ) && readOnly )
+ {
+ value=0;
+ StopPartialCompletion();
+ }
+ else if ( ( keycode == WXK_END || keycode == WXK_NUMPAD_END ) && readOnly )
+ {
+ value=itemCount-1;
+ StopPartialCompletion();
+ }
+ else if ( keychar && readOnly )
{
// Try partial completion
// (good for consistency)
return true;
- m_value = value;
-
if ( value >= 0 )
- m_combo->SetValue(m_strings[value]);
+ m_combo->ChangeValue(m_strings[value]);
+
+ // The m_combo->SetValue() call above sets m_value to the index of this
+ // string. But if there are more identical string, the index is of the
+ // first occurrence, which may be wrong, so set the index explicitly here,
+ // _after_ the SetValue() call.
+ m_value = value;
SendComboBoxEvent(m_value);
void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent& event )
{
// Saturated key movement on
- if ( !HandleKey(event.GetKeyCode(),true,
+ if ( !HandleKey(event.GetKeyCode(), true) )
+ event.Skip();
+}
+
+void wxVListBoxComboPopup::OnComboCharEvent( wxKeyEvent& event )
+{
+ // unlike in OnComboKeyEvent, wxEVT_CHAR contains meaningful
+ // printable character information, so pass it
#if wxUSE_UNICODE
- event.GetUnicodeKey()
+ const wxChar charcode = event.GetUnicodeKey();
#else
- 0
+ const wxChar charcode = (wxChar)event.GetKeyCode();
#endif
- ) )
+
+ if ( !HandleKey(event.GetKeyCode(), true, charcode) )
event.Skip();
}
}
else
{
- int comboStyle = m_combo->GetWindowStyle();
- int keycode = event.GetKeyCode();
- // Process partial completion key codes here, but not the arrow keys as the base class will do that for us
- if ((comboStyle & wxCB_READONLY) &&
- (keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode))
+ // completion is handled in OnChar() below
+ event.Skip();
+ }
+}
+
+void wxVListBoxComboPopup::OnChar(wxKeyEvent& event)
+{
+ if ( m_combo->GetWindowStyle() & wxCB_READONLY )
+ {
+ // Process partial completion key codes here, but not the arrow keys as
+ // the base class will do that for us
+#if wxUSE_UNICODE
+ const wxChar charcode = event.GetUnicodeKey();
+#else
+ const wxChar charcode = (wxChar)event.GetKeyCode();
+#endif
+ if ( wxIsprint(charcode) )
{
- OnComboKeyEvent(event);
+ OnComboCharEvent(event);
SetSelection(m_value); // ensure the highlight bar moves
+ return; // don't skip the event
}
- else
- event.Skip();
}
+
+ event.Skip();
}
void wxVListBoxComboPopup::Insert( const wxString& item, int pos )
}
m_strings.Insert(item,pos);
- if ( m_clientDatas.size() >= pos )
+ if ( (int)m_clientDatas.size() >= pos )
m_clientDatas.Insert(NULL, pos);
m_widths.Insert(-1,pos);
for ( i=0; i<strings.GetCount(); i++ )
{
- if ( item.Cmp(strings.Item(i)) < 0 )
+ if ( item.CmpNoCase(strings.Item(i)) <= 0 )
{
pos = (int)i;
break;
return m_strings.Index(s, bCase);
}
+bool wxVListBoxComboPopup::FindItem(const wxString& item, wxString* trueItem)
+{
+ int idx = m_strings.Index(item, false);
+ if ( idx == wxNOT_FOUND )
+ return false;
+ if ( trueItem != NULL )
+ *trueItem = m_strings[idx];
+ return true;
+}
+
unsigned int wxVListBoxComboPopup::GetCount() const
{
return m_strings.GetCount();
// wxWindow::GetTextExtent (assuming same dc is used
// for all calls, as we do here).
wxClientDC dc(m_combo);
+ if ( !m_useFont.IsOk() )
+ m_useFont = m_combo->GetFont();
dc.SetFont(m_useFont);
for ( i=0; i<n; i++ )
height = maxHeight;
int totalHeight = GetTotalHeight(); // + 3;
+
+ // Take borders into account on Mac or scrollbars always appear
+#if defined(__WXMAC__)
+ totalHeight += 2;
+#endif
if ( height >= totalHeight )
{
height = totalHeight;
// Find initial selection
wxString strValue = m_combo->GetValue();
- if ( strValue.length() )
+ if ( !strValue.empty() )
m_value = m_strings.Index(strValue);
}
BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboCtrl)
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()
{
}
long style,
const wxValidator& validator,
const wxString& name)
- : wxComboCtrl()
{
Init();
GetVListBoxComboPopup()->Clear();
+ // NB: This really needs to be SetValue() instead of ChangeValue(),
+ // as wxTextEntry API expects an event to be sent.
SetValue(wxEmptyString);
}
+void wxOwnerDrawnComboBox::Clear()
+{
+ DoClear();
+}
+
void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n)
{
- wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
+ wxCHECK_RET( IsValid(n), wxT("invalid index in wxOwnerDrawnComboBox::Delete") );
if ( GetSelection() == (int) n )
- SetValue(wxEmptyString);
+ ChangeValue(wxEmptyString);
GetVListBoxComboPopup()->Delete(n);
}
wxString wxOwnerDrawnComboBox::GetString(unsigned int n) const
{
- wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") );
+ wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("invalid index in wxOwnerDrawnComboBox::GetString") );
if ( !m_popupInterface )
return m_initChs.Item(n);
{
EnsurePopupControl();
- wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") );
+ wxCHECK_RET( IsValid(n), wxT("invalid index in wxOwnerDrawnComboBox::SetString") );
GetVListBoxComboPopup()->SetString(n,s);
}
{
EnsurePopupControl();
- wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") );
+ wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), wxT("invalid index in wxOwnerDrawnComboBox::Select") );
GetVListBoxComboPopup()->SetSelection(n);
// Refresh text portion in control
if ( m_text )
- m_text->SetValue( str );
+ m_text->ChangeValue( str );
else
m_valueString = str;
return GetVListBoxComboPopup()->GetSelection();
}
+void wxOwnerDrawnComboBox::GetSelection(long *from, long *to) const
+{
+ wxComboCtrl::GetSelection(from, to);
+}
+
int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
unsigned int pos,
void **clientData,
for ( unsigned int i = 0; i < count; ++i )
{
- int n = GetVListBoxComboPopup()->Append(items[i]);
+ n = GetVListBoxComboPopup()->Append(items[i]);
AssignNewItemClientData(n, clientData, i, type);
}
{
if ( flags & wxODCB_PAINTING_CONTROL )
{
- dc.DrawText( GetValue(),
- rect.x + GetTextIndent(),
+ wxString text;
+
+ if ( !ShouldUseHintText() )
+ {
+ text = GetValue();
+ }
+ else
+ {
+ text = GetHint();
+ wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
+ dc.SetTextForeground(col);
+ }
+
+ dc.DrawText( text,
+ rect.x + GetMargins().x,
(rect.height-dc.GetCharHeight())/2 + rect.y );
}
else
return -1;
}
+wxSize wxOwnerDrawnComboBox::DoGetBestSize() const
+{
+ wxSize best( wxComboCtrlBase::DoGetBestSize() );
+
+ if ( GetCount() > 0 )
+ {
+ wxOwnerDrawnComboBox* odc = const_cast<wxOwnerDrawnComboBox*>(this);
+ best.x = odc->GetWidestItemWidth();
+ // TODO: this class may also have GetHightestItemHeight() and
+ // GetHightestItem() methods, and so set the whole (edit part + arrow)
+ // control's height according with this max height, not only max width.
+ }
+
+ return GetSizeFromTextSize(best.x);
+}
+
void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc,
const wxRect& rect,
int WXUNUSED(item),