#define wxCC_GENERIC_TLW_IS_DIALOG
#define wxComboCtrlGenericTLW wxDialog
-#include "wx/gtk/private.h"
+#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
#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)
// 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);
}
}
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;
// 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;
// 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;
}
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
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;
}
{
// Derived classes can override this method for totally custom
// popup action
- if ( !IsPopupWindowState(Visible) )
+ switch ( GetPopupWindowState() )
{
- wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_DROPDOWN, GetId());
- event.SetEventObject(this);
- HandleWindowEvent(event);
+ case Hidden:
+ {
+ wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_DROPDOWN, GetId());
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
- ShowPopup();
- }
- else
- {
- HidePopup(true);
+ ShowPopup();
+ break;
+ }
+
+ case Animating:
+ case Visible:
+ {
+ HidePopup(true);
+ break;
+ }
}
}
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) )
{
// 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
return DEFAULT_TEXT_INDENT;
}
+void wxComboCtrlBase::SetTextCtrlStyle( int style )
+{
+ m_textCtrlStyle = style;
+
+ if ( m_text )
+ m_text->SetWindowStyle(style);
+}
+
// ----------------------------------------------------------------------------
// methods forwarded to wxTextCtrl
// ----------------------------------------------------------------------------