#pragma hdrstop
#endif
-#if wxUSE_COMBOCTRL
-
+#if wxUSE_COMBOBOX
#include "wx/combobox.h"
+extern WXDLLEXPORT_DATA(const char) wxComboBoxNameStr[] = "comboBox";
+#endif
+
+#if wxUSE_COMBOCTRL
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/log.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
- #include "wx/dialog.h"
#include "wx/timer.h"
#include "wx/textctrl.h"
#endif
#include "wx/combo.h"
+// ----------------------------------------------------------------------------
+// XTI
+// ----------------------------------------------------------------------------
+
+wxDEFINE_FLAGS( wxComboBoxStyle )
+wxBEGIN_FLAGS( wxComboBoxStyle )
+// new style border flags, we put them first to
+// use them for streaming out
+wxFLAGS_MEMBER(wxBORDER_SIMPLE)
+wxFLAGS_MEMBER(wxBORDER_SUNKEN)
+wxFLAGS_MEMBER(wxBORDER_DOUBLE)
+wxFLAGS_MEMBER(wxBORDER_RAISED)
+wxFLAGS_MEMBER(wxBORDER_STATIC)
+wxFLAGS_MEMBER(wxBORDER_NONE)
+
+// old style border flags
+wxFLAGS_MEMBER(wxSIMPLE_BORDER)
+wxFLAGS_MEMBER(wxSUNKEN_BORDER)
+wxFLAGS_MEMBER(wxDOUBLE_BORDER)
+wxFLAGS_MEMBER(wxRAISED_BORDER)
+wxFLAGS_MEMBER(wxSTATIC_BORDER)
+wxFLAGS_MEMBER(wxBORDER)
+
+// standard window styles
+wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
+wxFLAGS_MEMBER(wxCLIP_CHILDREN)
+wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
+wxFLAGS_MEMBER(wxWANTS_CHARS)
+wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
+wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
+wxFLAGS_MEMBER(wxVSCROLL)
+wxFLAGS_MEMBER(wxHSCROLL)
+
+wxFLAGS_MEMBER(wxCB_SIMPLE)
+wxFLAGS_MEMBER(wxCB_SORT)
+wxFLAGS_MEMBER(wxCB_READONLY)
+wxFLAGS_MEMBER(wxCB_DROPDOWN)
+
+wxEND_FLAGS( wxComboBoxStyle )
+
+wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxComboBox, wxControl, "wx/combobox.h")
+
+wxBEGIN_PROPERTIES_TABLE(wxComboBox)
+wxEVENT_PROPERTY( Select, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEvent )
+wxEVENT_PROPERTY( TextEnter, wxEVT_COMMAND_TEXT_ENTER, wxCommandEvent )
+
+// TODO DELEGATES
+wxPROPERTY( Font, wxFont, SetFont, GetFont, wxEMPTY_PARAMETER_VALUE, \
+ 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxPROPERTY_COLLECTION( Choices, wxArrayString, wxString, AppendString, \
+ GetStrings, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Value,wxString, SetValue, GetValue, wxEMPTY_PARAMETER_VALUE, \
+ 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Selection,int, SetSelection, GetSelection, wxEMPTY_PARAMETER_VALUE, \
+ 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+
+wxPROPERTY_FLAGS( WindowStyle, wxComboBoxStyle, long, SetWindowStyleFlag, \
+ GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
+ wxT("Helpstring"), wxT("group")) // style
+wxEND_PROPERTIES_TABLE()
+
+wxEMPTY_HANDLERS_TABLE(wxComboBox)
+
+wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \
+ wxString, Value, wxPoint, Position, wxSize, Size )
// constants
// ----------------------------------------------------------------------------
#if defined(__WXMSW__)
+// Let's use wxFrame as a fall-back solution until wxMSW gets wxNonOwnedWindow
+#include "wx/frame.h"
+#define wxCC_GENERIC_TLW_IS_FRAME
+#define wxComboCtrlGenericTLW wxFrame
+
#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common
// native controls work on it like normal.
#elif defined(__WXGTK__)
-#include "wx/gtk/private.h"
-
// NB: It is not recommended to use wxDialog as popup on wxGTK, because of
// this bug: If wxDialog is hidden, its position becomes corrupt
// between hide and next show, but without internal coordinates being
// reflected (or something like that - atleast commenting out ->Hide()
// seemed to eliminate the position change).
+#include "wx/dialog.h"
+#define wxCC_GENERIC_TLW_IS_DIALOG
+#define wxComboCtrlGenericTLW wxDialog
+
+#if defined(__WXGTK20__)
+# include "wx/gtk/private.h"
+#else
+# include "wx/gtk1/private.h"
+#endif
+
// NB: Let's not be afraid to use wxGTK's wxPopupTransientWindow as a
// 'perfect' popup, as it can succesfully host child controls even in
// popups that are shown in modal dialogs.
#elif defined(__WXMAC__)
+#include "wx/nonownedwnd.h"
+#define wxCC_GENERIC_TLW_IS_NONOWNEDWINDOW
+#define wxComboCtrlGenericTLW wxNonOwnedWindow
+
#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#define TRANSIENT_POPUPWIN_IS_PERFECT 1 // wxPopupTransientWindow works, its child can have focus, and common
// native controls work on it like normal.
#else
+#include "wx/dialog.h"
+#define wxCC_GENERIC_TLW_IS_DIALOG
+#define wxComboCtrlGenericTLW wxDialog
+
#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common
// native controls work on it like normal.
POPUPWIN_NONE = 0,
POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1,
POPUPWIN_WXPOPUPWINDOW = 2,
- POPUPWIN_WXDIALOG = 3
+ POPUPWIN_GENERICTLW = 3
};
#define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW
#define USES_WXPOPUPWINDOW 1
#else
- #define wxComboPopupWindowBase2 wxDialog
- #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG
- #define USES_WXDIALOG 1
+ #define wxComboPopupWindowBase2 wxComboCtrlGenericTLW
+ #define SECONDARY_POPUP_TYPE POPUPWIN_GENERICTLW
+ #define USES_GENERICTLW 1
#endif
#elif wxUSE_POPUPWIN
#define USES_WXPOPUPWINDOW 1
#if !POPUPWIN_IS_PERFECT
- #define wxComboPopupWindowBase2 wxDialog
- #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG
- #define USES_WXDIALOG 1
+ #define wxComboPopupWindowBase2 wxComboCtrlGenericTLW
+ #define SECONDARY_POPUP_TYPE POPUPWIN_GENERICTLW
+ #define USES_GENERICTLW 1
#endif
#else
// wxPopupWindow is not implemented
- #define wxComboPopupWindowBase wxDialog
- #define PRIMARY_POPUP_TYPE POPUPWIN_WXDIALOG
- #define USES_WXDIALOG 1
+ #define wxComboPopupWindowBase wxComboCtrlGenericTLW
+ #define PRIMARY_POPUP_TYPE POPUPWIN_GENERICTLW
+ #define USES_GENERICTLW 1
#endif
#define USES_WXPOPUPWINDOW 0
#endif
-#ifndef USES_WXDIALOG
- #define USES_WXDIALOG 0
+#ifndef USES_GENERICTLW
+ #define USES_GENERICTLW 0
#endif
#endif
+// Returns true if given popup window type can be classified as perfect
+// on this platform.
+static inline bool IsPopupWinTypePerfect( wxByte popupWinType )
+{
+#if POPUPWIN_IS_PERFECT && TRANSIENT_POPUPWIN_IS_PERFECT
+ wxUnusedVar(popupWinType);
+ return true;
+#else
+ return ( popupWinType == POPUPWIN_GENERICTLW
+ #if POPUPWIN_IS_PERFECT
+ || popupWinType == POPUPWIN_WXPOPUPWINDOW
+ #endif
+ #if TRANSIENT_POPUPWIN_IS_PERFECT
+ || popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW
+ #endif
+ );
+#endif
+}
+
+
//
// ** TODO **
// * wxComboPopupWindow for external use (ie. replace old wxUniv wxPopupComboWindow)
winFocused != m_combo->GetButton() // GTK (atleast) requires this
)
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
}
event.Skip();
void wxComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
void wxComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
void wxComboFrameEventHandler::OnClose( wxCloseEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
void wxComboFrameEventHandler::OnActivate( wxActivateEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
void wxComboFrameEventHandler::OnResize( wxSizeEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
void wxComboFrameEventHandler::OnMove( wxMoveEvent& event )
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxComboCtrlBase)),
wxT("parent might not be wxComboCtrl, but check IMPLEMENT_DYNAMIC_CLASS(2) macro for correctness") );
- combo->OnPopupDismiss();
+ combo->OnPopupDismiss(true);
}
#endif // USES_WXPOPUPTRANSIENTWINDOW
void OnSizeEvent( wxSizeEvent& event );
void OnKeyEvent(wxKeyEvent& event);
-#if USES_WXDIALOG
+#if USES_GENERICTLW
void OnActivate( wxActivateEvent& event );
#endif
BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler)
EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent)
EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent)
-#if USES_WXDIALOG
+ EVT_CHAR(wxComboPopupWindowEvtHandler::OnKeyEvent)
+#if USES_GENERICTLW
EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate)
#endif
EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent)
wxWindowList children = m_combo->GetPopupWindow()->GetChildren();
wxWindowList::iterator node = children.begin();
wxWindow* child = (wxWindow*)*node;
- child->GetEventHandler()->AddPendingEvent(event);
+ child->GetEventHandler()->ProcessEvent(event);
}
-#if USES_WXDIALOG
+#if USES_GENERICTLW
void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event )
{
if ( !event.GetActive() )
{
// Tell combo control that we are dismissed.
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
event.Skip();
}
event.Skip();
}
+void wxComboPopup::OnComboCharEvent( wxKeyEvent& event )
+{
+ event.Skip();
+}
+
void wxComboPopup::OnComboDoubleClick()
{
}
{
}
+bool wxComboPopup::FindItem(const wxString& WXUNUSED(item),
+ wxString* WXUNUSED(trueItem))
+{
+ return true;
+}
+
bool wxComboPopup::LazyCreate()
{
return false;
void wxComboPopup::Dismiss()
{
- m_combo->HidePopup();
+ m_combo->HidePopup(true);
}
// ----------------------------------------------------------------------------
// wxEVT_SET_FOCUSes (since m_text->SetFocus is called
// from combo's focus event handler), they should be quite
// harmless.
- wxFocusEvent evt2(event.GetEventType(),m_combo->GetId());
+ wxFocusEvent evt2(event);
+ evt2.SetId(m_combo->GetId());
evt2.SetEventObject(m_combo);
m_combo->GetEventHandler()->ProcessEvent(evt2);
// This is pushed to the event handler queue of the control in popup.
//
-class wxComboPopupExtraEventHandler : public wxEvtHandler
+class wxComboPopupEvtHandler : public wxEvtHandler
{
public:
- wxComboPopupExtraEventHandler( wxComboCtrlBase* combo )
+ wxComboPopupEvtHandler( wxComboCtrlBase* combo )
: wxEvtHandler()
{
m_combo = combo;
m_beenInside = false;
+
+ // Let's make it so that the popup control will not receive mouse
+ // events until mouse left button has been up.
+ m_blockEventsToPopup = true;
}
- virtual ~wxComboPopupExtraEventHandler() { }
+ virtual ~wxComboPopupEvtHandler() { }
void OnMouseEvent( wxMouseEvent& event );
void OnPopupDismiss()
{
m_beenInside = false;
+ m_blockEventsToPopup = true;
}
protected:
wxComboCtrlBase* m_combo;
- bool m_beenInside;
+ bool m_beenInside;
+ bool m_blockEventsToPopup;
private:
DECLARE_EVENT_TABLE()
};
-BEGIN_EVENT_TABLE(wxComboPopupExtraEventHandler, wxEvtHandler)
- EVT_MOUSE_EVENTS(wxComboPopupExtraEventHandler::OnMouseEvent)
+BEGIN_EVENT_TABLE(wxComboPopupEvtHandler, wxEvtHandler)
+ EVT_MOUSE_EVENTS(wxComboPopupEvtHandler::OnMouseEvent)
END_EVENT_TABLE()
-void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event )
+void wxComboPopupEvtHandler::OnMouseEvent( wxMouseEvent& event )
{
wxPoint pt = event.GetPosition();
wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize();
event.Skip();
- if ( evtType == wxEVT_MOTION ||
- evtType == wxEVT_LEFT_DOWN ||
- evtType == wxEVT_RIGHT_DOWN )
+ if ( !isInside || !m_combo->IsPopupShown() )
{
- // Block motion and click events outside the popup
- if ( !isInside || !m_combo->IsPopupShown() )
+ // Mouse is outside the popup or popup is not actually shown (yet)
+
+ if ( evtType == wxEVT_MOTION ||
+ evtType == wxEVT_LEFT_DOWN ||
+ evtType == wxEVT_LEFT_UP ||
+ evtType == wxEVT_RIGHT_DOWN )
{
+ // Block motion and click events outside the popup
event.Skip(false);
}
}
- else if ( evtType == wxEVT_LEFT_UP )
+ else
{
- if ( !m_combo->IsPopupShown() )
- {
- event.Skip(false);
- relayToButton = true;
- }
- else if ( !m_beenInside )
+ // Mouse is inside the popup, which is fully shown
+
+ m_beenInside = true;
+
+ // Do not let the popup control respond to mouse events until
+ // mouse press used to display the popup has been lifted. This
+ // is important for users with slower mouse fingers or mouse
+ // drivers. Note that we have some redundancy here, just in
+ // case the popup is some native control that does not emit all
+ // mouse event types.
+ if ( evtType == wxEVT_MOTION )
{
- if ( isInside )
+ if ( m_blockEventsToPopup )
{
- m_beenInside = true;
+ if ( event.LeftIsDown() )
+ event.Skip(false);
+ else
+ m_blockEventsToPopup = false;
}
- else
+ }
+ else if ( evtType == wxEVT_LEFT_DOWN )
+ {
+ if ( m_blockEventsToPopup )
+ m_blockEventsToPopup = false;
+ }
+ else if ( evtType == wxEVT_LEFT_UP )
+ {
+ if ( m_blockEventsToPopup )
{
+ // On first left up, stop blocking mouse events (but still
+ // block this one)
+ m_blockEventsToPopup = false;
+ event.Skip(false);
+
+ // Also, this button press was (probably) used to display
+ // the popup, so relay it back to the drop-down button
+ // (which supposedly originated it). This is necessary to
+ // refresh it properly.
relayToButton = true;
}
}
+ else if ( m_blockEventsToPopup )
+ {
+ event.Skip(false);
+ }
+ }
+
+ //
+ // Some mouse events to popup that happen outside it, before cursor
+ // has been inside the popup, need to be ignored by it but relayed to
+ // the dropbutton.
+ //
+ if ( evtType == wxEVT_LEFT_UP )
+ {
+ if ( !m_combo->IsPopupShown() )
+ {
+ event.Skip(false);
+ relayToButton = true;
+ }
+ else if ( !isInside && !m_beenInside )
+ {
+ // Popup is shown but the cursor is not inside, nor it has been
+ relayToButton = true;
+ }
}
if ( relayToButton )
{
- //
- // Some mouse events to popup that happen outside it, before cursor
- // has been inside the popup, need to be ignored by it but relayed to
- // the dropbutton.
- //
- wxWindow* eventSink = m_combo;
wxWindow* btn = m_combo->GetButton();
if ( btn )
- eventSink = btn;
-
- eventSink->GetEventHandler()->ProcessEvent(event);
+ btn->GetEventHandler()->ProcessEvent(event);
+ else
+ // Bypass the event handling mechanism. Using it would be
+ // confusing for the platform-specific wxComboCtrl
+ // implementations.
+ m_combo->HandleButtonMouseEvent(event, 0);
}
}
EVT_IDLE(wxComboCtrlBase::OnIdleEvent)
//EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent)
EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent)
+ EVT_CHAR(wxComboCtrlBase::OnCharEvent)
EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent)
EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged)
END_EVENT_TABLE()
m_text = NULL;
m_popupInterface = NULL;
- m_popupExtraHandler = NULL;
+ m_popupEvtHandler = NULL;
m_textEvtHandler = NULL;
#if INSTALL_TOPLEV_HANDLER
m_extRight = 0;
m_marginLeft = -1;
m_iFlags = 0;
+ m_textCtrlStyle = 0;
m_timeCanAcceptClick = 0;
m_resetFocus = false;
}
void
-wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator)
+wxComboCtrlBase::CreateTextCtrl(int style)
{
if ( !(m_windowStyle & wxCB_READONLY) )
{
// not used by the wxPropertyGrid and therefore the tab is processed by
// looking at ancestors to see if they have wxTAB_TRAVERSAL. The
// navigation event is then sent to the wrong window.
- style |= wxTE_PROCESS_TAB;
+ style |= wxTE_PROCESS_TAB | m_textCtrlStyle;
if ( HasFlag(wxTE_PROCESS_ENTER) )
style |= wxTE_PROCESS_ENTER;
m_text = new wxComboCtrlTextCtrl();
m_text->Create(this, wxID_ANY, m_valueString,
wxDefaultPosition, wxSize(10,-1),
- style, validator);
+ style);
+ m_text->SetHint(m_hintText);
}
}
// be the correct colour and themed brush. Instead we'll use
// wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed.
#ifndef __WXMAC__
- SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
-#endif
+ #if defined(__WXMSW__) || defined(__WXGTK__)
+ wxVisualAttributes vattrs = wxComboBox::GetClassDefaultAttributes();
+ #else
+ wxVisualAttributes vattrs;
+ vattrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+ vattrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+ #endif
+
+ // Only change the colours if application has not specified
+ // custom ones.
+ if ( !m_hasFgCol )
+ {
+ SetOwnForegroundColour(vattrs.colFg);
+ m_hasFgCol = false;
+ }
+ if ( !m_hasBgCol )
+ {
+ SetOwnBackgroundColour(vattrs.colBg);
+ m_hasBgCol = false;
+ }
+#endif // !__WXMAC__
}
wxComboCtrlBase::~wxComboCtrlBase()
// There is special custom paint area - it is better to
// use some margin with the wxTextCtrl.
m_text->SetMargins(m_marginLeft);
- x = m_tcArea.x + m_widthCustomPaint +
+ x = m_tcArea.x + m_widthCustomPaint +
m_marginLeft + textCtrlXAdjust;
}
}
#endif // wxUSE_TOOLTIPS
-#if wxUSE_VALIDATORS
-void wxComboCtrlBase::SetValidator(const wxValidator& validator)
+bool wxComboCtrlBase::SetForegroundColour(const wxColour& colour)
{
- wxTextCtrl* textCtrl = GetTextCtrl();
-
- if ( textCtrl )
- textCtrl->SetValidator( validator );
- else
- wxControl::SetValidator( validator );
+ if ( wxControl::SetForegroundColour(colour) )
+ {
+ if ( m_text )
+ m_text->SetForegroundColour(colour);
+ return true;
+ }
+ return false;
}
-wxValidator* wxComboCtrlBase::GetValidator()
+bool wxComboCtrlBase::SetBackgroundColour(const wxColour& colour)
{
- wxTextCtrl* textCtrl = GetTextCtrl();
-
- return textCtrl ? textCtrl->GetValidator() : wxControl::GetValidator();
+ if ( wxControl::SetBackgroundColour(colour) )
+ {
+ if ( m_text )
+ m_text->SetBackgroundColour(colour);
+ return true;
+ }
+ return false;
}
-#endif // wxUSE_VALIDATORS
-
// ----------------------------------------------------------------------------
// painting
// ----------------------------------------------------------------------------
selRect.width -= wcp + (focusSpacingX*2);
wxColour bgCol;
+ wxColour fgCol;
+
bool doDrawSelRect = true;
+ // Determine foreground colour
+ if ( isEnabled )
+ {
+ if ( doDrawFocusRect )
+ {
+ fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ }
+ else if ( m_hasFgCol )
+ {
+ // Honour the custom foreground colour
+ fgCol = GetForegroundColour();
+ }
+ else
+ {
+ fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+ }
+ }
+ else
+ {
+ fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
+ }
+
+ // Determine background colour
if ( isEnabled )
{
- // If popup is hidden and this control is focused,
- // then draw the focus-indicator (selbgcolor background etc.).
if ( doDrawFocusRect )
{
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
}
+ else if ( m_hasBgCol )
+ {
+ // Honour the custom background colour
+ bgCol = GetBackgroundColour();
+ }
else
{
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
#ifndef __WXMAC__ // see note in OnThemeChange
doDrawSelRect = false;
bgCol = GetBackgroundColour();
}
else
{
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) );
#ifndef __WXMAC__ // see note in OnThemeChange
bgCol = GetBackgroundColour();
#else
#endif
}
+ dc.SetTextForeground( fgCol );
dc.SetBrush( bgCol );
if ( doDrawSelRect )
{
wxLongLong t = ::wxGetLocalTimeMillis();
int evtType = event.GetEventType();
-#if USES_WXPOPUPWINDOW || USES_WXDIALOG
+#if USES_WXPOPUPWINDOW || USES_GENERICTLW
if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW )
{
if ( IsPopupWindowState(Visible) &&
( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) )
{
- HidePopup();
+ HidePopup(true);
return true;
}
}
#if USES_WXPOPUPWINDOW
// Click here always hides the popup.
if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW )
- HidePopup();
+ HidePopup(true);
#endif
}
else
}
}
}
- else
- if ( IsPopupShown() )
+ else if ( evtType == wxEVT_MOUSEWHEEL )
{
- // relay (some) mouse events to the popup
- if ( evtType == wxEVT_MOUSEWHEEL )
- m_popup->GetEventHandler()->AddPendingEvent(event);
+ if ( IsPopupShown() )
+ {
+ // relay (some) mouse events to the popup
+ m_popup->GetEventHandler()->ProcessEvent(event);
+ }
+ else if ( event.GetWheelAxis() == 0 &&
+ event.GetWheelRotation() != 0 &&
+ event.GetModifiers() == 0 )
+ {
+ // Translate mousewheel actions into key up/down. This is
+ // the simplest way of getting native behaviour: scrolling the
+ // wheel moves selection up/down by one item.
+ wxKeyEvent kevent(wxEVT_KEY_DOWN);
+ kevent.m_keyCode = event.GetWheelRotation() > 0
+ ? WXK_UP
+ : WXK_DOWN;
+ GetEventHandler()->ProcessEvent(kevent);
+ }
+ else
+ {
+ event.Skip();
+ }
}
else if ( evtType )
+ {
event.Skip();
+ }
}
void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event)
if ( IsPopupShown() )
{
// pass it to the popped up control
- GetPopupControl()->GetControl()->GetEventHandler()->AddPendingEvent(event);
+ GetPopupControl()->GetControl()->GetEventHandler()->ProcessEvent(event);
}
else // no popup
{
- if ( GetParent()->HasFlag(wxTAB_TRAVERSAL) &&
- HandleAsNavigationKey(event) )
- return;
+ wxWindow* mainCtrl = GetMainWindowOfCompositeControl();
+
+ if ( mainCtrl->GetParent()->HasFlag(wxTAB_TRAVERSAL) )
+ {
+ if ( mainCtrl->HandleAsNavigationKey(event) )
+ return;
+ }
if ( IsKeyPopupToggle(event) )
{
}
}
+void wxComboCtrlBase::OnCharEvent(wxKeyEvent& event)
+{
+ if ( IsPopupShown() )
+ {
+ // pass it to the popped up control
+ GetPopupControl()->GetControl()->GetEventHandler()->ProcessEvent(event);
+ }
+ else // no popup
+ {
+ wxComboPopup* popupInterface = GetPopupControl();
+ if ( popupInterface )
+ {
+ popupInterface->OnComboCharEvent(event);
+ }
+ else
+ {
+ event.Skip();
+ }
+ }
+}
+
void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event )
{
if ( event.GetEventType() == wxEVT_SET_FOCUS )
#ifdef wxComboPopupWindowBase2
if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP )
{
- #if !USES_WXDIALOG
+ #if !USES_GENERICTLW
m_winPopup = new wxComboPopupWindowBase2( this, wxNO_BORDER );
#else
+ int tlwFlags = wxNO_BORDER;
+ #ifdef wxCC_GENERIC_TLW_IS_FRAME
+ tlwFlags |= wxFRAME_NO_TASKBAR;
+ #endif
+
+ #ifdef wxCC_GENERIC_TLW_IS_NONOWNEDWINDOW
+ m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY,
+ wxPoint(-21,-21), wxSize(20, 20),
+ tlwFlags );
+ #else
m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY, wxEmptyString,
wxPoint(-21,-21), wxSize(20, 20),
- wxNO_BORDER );
+ tlwFlags );
+ #endif
#endif
m_popupWinType = SECONDARY_POPUP_TYPE;
}
popupInterface->Create(m_winPopup);
m_popup = popup = popupInterface->GetControl();
- m_popupExtraHandler = new wxComboPopupExtraEventHandler(this);
- popup->PushEventHandler( m_popupExtraHandler );
+ m_popupEvtHandler = new wxComboPopupEvtHandler(this);
+ popup->PushEventHandler( m_popupEvtHandler );
// This may be helpful on some platforms
// (eg. it bypasses a wxGTK popupwindow bug where
// Destroy popup window and the child control
void wxComboCtrlBase::DestroyPopup()
{
- HidePopup();
+ HidePopup(true);
if ( m_popup )
- m_popup->RemoveEventHandler(m_popupExtraHandler);
+ m_popup->RemoveEventHandler(m_popupEvtHandler);
- delete m_popupExtraHandler;
+ wxDELETE(m_popupEvtHandler);
- delete m_popupInterface;
+ wxDELETE(m_popupInterface);
if ( m_winPopup )
{
m_winPopup->RemoveEventHandler(m_popupWinEvtHandler);
- delete m_popupWinEvtHandler;
- m_popupWinEvtHandler = NULL;
+ wxDELETE(m_popupWinEvtHandler);
m_winPopup->Destroy();
+ m_winPopup = NULL;
}
- m_popupExtraHandler = NULL;
- m_popupInterface = NULL;
- m_winPopup = NULL;
m_popup = NULL;
}
}
// This must be done after creation
- if ( m_valueString.length() )
+ if ( !m_valueString.empty() )
{
iface->SetStringValue(m_valueString);
//Refresh();
{
// Derived classes can override this method for totally custom
// popup action
- if ( !IsPopupWindowState(Visible) )
- ShowPopup();
- else
- HidePopup();
+ switch ( GetPopupWindowState() )
+ {
+ case Hidden:
+ {
+ Popup();
+ break;
+ }
+
+ case Animating:
+ case Visible:
+ {
+ HidePopup(true);
+ break;
+ }
+ }
+}
+
+void wxComboCtrlBase::Popup()
+{
+ wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_DROPDOWN, GetId());
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
+
+ ShowPopup();
}
void wxComboCtrlBase::ShowPopup()
// that if transient popup is open, then tab traversal is to be ignored.
// However, I think this code would still be needed for cases where
// transient popup doesn't work yet (wxWinCE?).
- wxWindow* parent = GetParent();
+ wxWindow* mainCtrl = GetMainWindowOfCompositeControl();
+ wxWindow* parent = mainCtrl->GetParent();
int parentFlags = parent->GetWindowStyle();
if ( parentFlags & wxTAB_TRAVERSAL )
{
winPopup->Show();
m_popupWinState = Visible;
+
+ // If popup window was a generic top-level window, or the
+ // wxPopupWindow implemenation on this platform is classified as
+ // perfect, then we should be able to safely set focus to the popup
+ // control.
+ if ( IsPopupWinTypePerfect(m_popupWinType) )
+ m_popup->SetFocus();
}
else if ( IsPopupWindowState(Hidden) )
{
Refresh();
}
-void wxComboCtrlBase::OnPopupDismiss()
+void wxComboCtrlBase::OnPopupDismiss(bool generateEvent)
{
// Just in case, avoid double dismiss
if ( IsPopupWindowState(Hidden) )
// Inform popup control itself
m_popupInterface->OnDismiss();
- if ( m_popupExtraHandler )
- ((wxComboPopupExtraEventHandler*)m_popupExtraHandler)->OnPopupDismiss();
+ if ( m_popupEvtHandler )
+ ((wxComboPopupEvtHandler*)m_popupEvtHandler)->OnPopupDismiss();
#if INSTALL_TOPLEV_HANDLER
// Remove top level window event handler
Refresh();
SetFocus();
+
+ if ( generateEvent )
+ {
+ wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_CLOSEUP, GetId());
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
+ }
}
-void wxComboCtrlBase::HidePopup()
+void wxComboCtrlBase::HidePopup(bool generateEvent)
{
// Should be able to call this without popup interface
if ( IsPopupWindowState(Hidden) )
// transfer value and show it in textctrl, if any
if ( !IsPopupWindowState(Animating) )
- SetValue( m_popupInterface->GetStringValue() );
+ SetValueByUser( m_popupInterface->GetStringValue() );
m_winPopup->Hide();
- OnPopupDismiss();
+ OnPopupDismiss(generateEvent);
}
// ----------------------------------------------------------------------------
m_btnSide = side;
m_btnSpacingX = spacingX;
+ if ( width > 0 || height > 0 || spacingX )
+ m_iFlags |= wxCC_IFLAG_HAS_NONSTANDARD_BUTTON;
+
RecalcAndRefresh();
}
return wxPoint(m_marginLeft, -1);
}
-#if WXWIN_COMPATIBILITY_2_6
+#if WXWIN_COMPATIBILITY_2_8
void wxComboCtrlBase::SetTextIndent( int indent )
{
if ( indent < 0 )
return DEFAULT_TEXT_INDENT;
}
+void wxComboCtrlBase::SetTextCtrlStyle( int style )
+{
+ m_textCtrlStyle = style;
+
+ if ( m_text )
+ m_text->SetWindowStyle(style);
+}
+
// ----------------------------------------------------------------------------
-// methods forwarded to wxTextCtrl
+// wxTextEntry interface
// ----------------------------------------------------------------------------
-wxString wxComboCtrlBase::GetValue() const
+wxString wxComboCtrlBase::DoGetValue() const
{
if ( m_text )
return m_text->GetValue();
return m_valueString;
}
-void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent)
+void wxComboCtrlBase::SetValueWithEvent(const wxString& value,
+ bool withEvent)
{
- if ( m_text )
- {
- if ( !withEvent )
- m_ignoreEvtText++;
-
- m_text->SetValue(value);
+ DoSetValue(value, withEvent ? SetValue_SendEvent : 0);
+}
- if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) )
- m_text->SelectAll();
- }
+void wxComboCtrlBase::OnSetValue(const wxString& value)
+{
+ // Note: before wxComboCtrl inherited from wxTextEntry,
+ // this code used to be in SetValueWithEvent().
// Since wxComboPopup may want to paint the combo as well, we need
// to set the string value here (as well as sometimes in ShowPopup).
if ( m_valueString != value )
{
- m_valueString = value;
+ bool found = true;
+ wxString trueValue = value;
- EnsurePopupControl();
+ // Conform to wxComboBox behavior: read-only control can only accept
+ // valid list items and empty string
+ if ( m_popupInterface && HasFlag(wxCB_READONLY) && value.length() )
+ {
+ found = m_popupInterface->FindItem(value,
+ &trueValue);
+ }
- if (m_popupInterface)
- m_popupInterface->SetStringValue(value);
+ if ( found )
+ {
+ m_valueString = trueValue;
+
+ EnsurePopupControl();
+
+ if ( m_popupInterface )
+ m_popupInterface->SetStringValue(trueValue);
+ }
}
Refresh();
}
-void wxComboCtrlBase::SetValue(const wxString& value)
+void wxComboCtrlBase::SetValueByUser(const wxString& value)
{
- SetValueWithEvent(value, false);
+ // NB: Order of function calls is important here. Otherwise
+ // the SelectAll() may not work.
+
+ if ( m_text )
+ {
+ m_text->SetValue(value);
+
+ if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) )
+ m_text->SelectAll();
+ }
+
+ OnSetValue(value);
}
// In this SetValue variant wxComboPopup::SetStringValue is not called
m_text->SetInsertionPoint(pos);
}
-void wxComboCtrlBase::SetInsertionPointEnd()
-{
- if ( m_text )
- m_text->SetInsertionPointEnd();
-}
-
long wxComboCtrlBase::GetInsertionPoint() const
{
if ( m_text )
return 0;
}
+void wxComboCtrlBase::WriteText(const wxString& text)
+{
+ if ( m_text )
+ {
+ m_text->WriteText(text);
+ OnSetValue(m_text->GetValue());
+ }
+ else
+ {
+ OnSetValue(text);
+ }
+}
+
+void wxComboCtrlBase::DoSetValue(const wxString& value, int flags)
+{
+ if ( m_text )
+ {
+ if ( flags & SetValue_SendEvent )
+ m_text->SetValue(value);
+ else
+ m_text->ChangeValue(value);
+ }
+
+ OnSetValue(value);
+}
+
void wxComboCtrlBase::Replace(long from, long to, const wxString& value)
{
if ( m_text )
+ {
m_text->Replace(from, to, value);
+ OnSetValue(m_text->GetValue());
+ }
}
void wxComboCtrlBase::Remove(long from, long to)
{
if ( m_text )
+ {
m_text->Remove(from, to);
+ OnSetValue(m_text->GetValue());
+ }
}
void wxComboCtrlBase::SetSelection(long from, long to)
m_text->SetSelection(from, to);
}
+void wxComboCtrlBase::GetSelection(long *from, long *to) const
+{
+ if ( m_text )
+ {
+ m_text->GetSelection(from, to);
+ }
+ else
+ {
+ *from = 0;
+ *to = 0;
+ }
+}
+
+bool wxComboCtrlBase::IsEditable() const
+{
+ if ( m_text )
+ return m_text->IsEditable();
+ return false;
+}
+
+void wxComboCtrlBase::SetEditable(bool editable)
+{
+ if ( m_text )
+ m_text->SetEditable(editable);
+}
+
void wxComboCtrlBase::Undo()
{
if ( m_text )
m_text->Undo();
}
+void wxComboCtrlBase::Redo()
+{
+ if ( m_text )
+ m_text->Redo();
+}
+
+bool wxComboCtrlBase::CanUndo() const
+{
+ if ( m_text )
+ return m_text->CanUndo();
+
+ return false;
+}
+
+bool wxComboCtrlBase::CanRedo() const
+{
+ if ( m_text )
+ return m_text->CanRedo();
+
+ return false;
+}
+
+bool wxComboCtrlBase::SetHint(const wxString& hint)
+{
+ m_hintText = hint;
+ bool res = true;
+ if ( m_text )
+ res = m_text->SetHint(hint);
+ Refresh();
+ return res;
+}
+
+wxString wxComboCtrlBase::GetHint() const
+{
+ return m_hintText;
+}
+
#endif // wxUSE_COMBOCTRL