Use wxPopupTransientWindow in wxComboCtrl in wxMSW too

This seems to work fine with current version of wxPopupTransientWindow
and wxPU_CONTAINS_CONTROLS style and allows to drastically simplify the
whole mess of preprocessor checks in wxComboCtrl code, reducing the
logic to just 2 cases: either wxUSE_POPUPWIN == 1 under any of the major
platforms and then we use wxPopupTransientWindow or wxUSE_POPUPWIN == 0
or we use some other platform and then a TLW-based fallback is used
instead.

In spite of the amount of changes, this should only modify behaviour
under MSW where wxPopupTransientWindow is used now instead of whatever
was used before.
This commit is contained in:
Vadim Zeitlin
2021-07-10 18:24:34 +01:00
parent 272b1009cc
commit aa42d9c805
2 changed files with 39 additions and 210 deletions

View File

@@ -726,9 +726,6 @@ private:
wxByte m_ignoreEvtText; // Number of next EVT_TEXTs to ignore
// Is popup window wxPopupTransientWindow, wxPopupWindow or wxDialog?
wxByte m_popupWinType;
wxDECLARE_EVENT_TABLE();
wxDECLARE_ABSTRACT_CLASS(wxComboCtrlBase);

View File

@@ -132,14 +132,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \
#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.
#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window.
//#undef wxUSE_POPUPWIN
//#define wxUSE_POPUPWIN 0
#elif defined(__WXGTK__)
// NB: It is not recommended to use wxDialog as popup on wxGTK, because of
@@ -157,25 +149,12 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \
# include "wx/gtk1/private.h"
#endif
// NB: Let's not be afraid to use wxGTK's wxPopupTransientWindow as a
// 'perfect' popup, as it can successfully host child controls even in
// popups that are shown in modal dialogs.
#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.
#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window.
#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.
#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window.
#define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display
#undef DEFAULT_DROPBUTTON_WIDTH
@@ -188,10 +167,9 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \
#include "wx/dialog.h"
#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.
#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window.
// Assume we can't use wxPopupTransientWindow on the other platforms.
#undef wxUSE_POPUPWIN
#define wxUSE_POPUPWIN 0
#endif
@@ -200,115 +178,14 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \
#define FOCUS_RING 0
#endif
// Popupwin is really only supported on wxMSW and wxGTK, regardless
// what the wxUSE_POPUPWIN says.
// FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2)
#if (!defined(__WXMSW__) && !defined(__WXGTK__) && !defined(__WXMAC__))
#undef wxUSE_POPUPWIN
#define wxUSE_POPUPWIN 0
#endif
#if wxUSE_POPUPWIN
#include "wx/popupwin.h"
#else
#undef USE_TRANSIENT_POPUP
#define USE_TRANSIENT_POPUP 0
#endif
// Define different types of popup windows
enum
{
POPUPWIN_NONE = 0,
POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1,
POPUPWIN_WXPOPUPWINDOW = 2,
POPUPWIN_GENERICTLW = 3
};
#if USE_TRANSIENT_POPUP
// wxPopupTransientWindow is implemented
#define wxComboPopupWindowBase wxPopupTransientWindow
#define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPTRANSIENTWINDOW
#define USES_WXPOPUPTRANSIENTWINDOW 1
#if TRANSIENT_POPUPWIN_IS_PERFECT
//
#elif POPUPWIN_IS_PERFECT
#define wxComboPopupWindowBase2 wxPopupWindow
#define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW
#define USES_WXPOPUPWINDOW 1
#else
#define wxComboPopupWindowBase2 wxComboCtrlGenericTLW
#define SECONDARY_POPUP_TYPE POPUPWIN_GENERICTLW
#define USES_GENERICTLW 1
#endif
#elif wxUSE_POPUPWIN
// wxPopupWindow (but not wxPopupTransientWindow) is properly implemented
#define wxComboPopupWindowBase wxPopupWindow
#define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW
#define USES_WXPOPUPWINDOW 1
#if !POPUPWIN_IS_PERFECT
#define wxComboPopupWindowBase2 wxComboCtrlGenericTLW
#define SECONDARY_POPUP_TYPE POPUPWIN_GENERICTLW
#define USES_GENERICTLW 1
#endif
#else
// wxPopupWindow is not implemented
#define wxComboPopupWindowBase wxComboCtrlGenericTLW
#define PRIMARY_POPUP_TYPE POPUPWIN_GENERICTLW
#define USES_GENERICTLW 1
#endif
#ifndef USES_WXPOPUPTRANSIENTWINDOW
#define USES_WXPOPUPTRANSIENTWINDOW 0
#endif
#ifndef USES_WXPOPUPWINDOW
#define USES_WXPOPUPWINDOW 0
#endif
#ifndef USES_GENERICTLW
#define USES_GENERICTLW 0
#endif
#if USES_WXPOPUPWINDOW
#define INSTALL_TOPLEV_HANDLER 1
#else
#define INSTALL_TOPLEV_HANDLER 0
#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)
@@ -320,7 +197,7 @@ static inline bool IsPopupWinTypePerfect( wxByte popupWinType )
// in its top level parent.
// ----------------------------------------------------------------------------
#if INSTALL_TOPLEV_HANDLER
#if !wxUSE_POPUPWIN
//
// This will no longer be necessary after wxTransientPopupWindow
@@ -438,7 +315,7 @@ void wxComboFrameEventHandler::OnMove( wxMoveEvent& event )
event.Skip();
}
#endif // INSTALL_TOPLEV_HANDLER
#endif // !wxUSE_POPUPWIN
// ----------------------------------------------------------------------------
// wxComboPopupWindow is, in essence, wxPopupWindow customized for
@@ -451,7 +328,7 @@ public:
wxComboPopupWindow( wxComboCtrlBase *parent,
int style )
#if USES_WXPOPUPWINDOW || USES_WXPOPUPTRANSIENTWINDOW
#if wxUSE_POPUPWIN
: wxComboPopupWindowBase(parent,
style | wxPU_CONTAINS_CONTROLS)
#else
@@ -466,7 +343,7 @@ public:
m_inShow = 0;
}
#if USES_WXPOPUPTRANSIENTWINDOW
#if wxUSE_POPUPWIN
virtual bool Show( bool show ) wxOVERRIDE;
virtual bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE;
protected:
@@ -478,7 +355,7 @@ private:
};
#if USES_WXPOPUPTRANSIENTWINDOW
#if wxUSE_POPUPWIN
bool wxComboPopupWindow::Show( bool show )
{
// Guard against recursion
@@ -520,7 +397,7 @@ void wxComboPopupWindow::OnDismiss()
combo->OnPopupDismiss(true);
}
#endif // USES_WXPOPUPTRANSIENTWINDOW
#endif // wxUSE_POPUPWIN
// ----------------------------------------------------------------------------
@@ -542,7 +419,7 @@ void wxComboCtrlBase::OnPopupKey( wxKeyEvent& event )
child->GetEventHandler()->ProcessEvent(event);
}
#if USES_GENERICTLW
#if !wxUSE_POPUPWIN
void wxComboCtrlBase::OnPopupActivate( wxActivateEvent& event )
{
if ( !event.GetActive() )
@@ -870,7 +747,7 @@ void wxComboCtrlBase::Init()
m_text = NULL;
m_popupInterface = NULL;
#if INSTALL_TOPLEV_HANDLER
#if !wxUSE_POPUPWIN
m_toplevEvtHandler = NULL;
#endif
@@ -886,7 +763,6 @@ void wxComboCtrlBase::Init()
m_btnWidDefault = 0;
m_blankButtonBg = false;
m_ignoreEvtText = 0;
m_popupWinType = POPUPWIN_NONE;
m_btnWid = m_btnHei = -1;
m_btnSide = wxRIGHT;
m_btnSpacingX = 0;
@@ -1022,7 +898,7 @@ wxComboCtrlBase::~wxComboCtrlBase()
if ( HasCapture() )
ReleaseMouse();
#if INSTALL_TOPLEV_HANDLER
#if !wxUSE_POPUPWIN
delete ((wxComboFrameEventHandler*)m_toplevEvtHandler);
m_toplevEvtHandler = NULL;
#endif
@@ -1789,15 +1665,12 @@ bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event,
wxMilliClock_t t = ::wxGetLocalTimeMillis();
int evtType = event.GetEventType();
#if USES_WXPOPUPWINDOW || USES_GENERICTLW
if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW )
#if !wxUSE_POPUPWIN
if ( IsPopupWindowState(Visible) &&
( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) )
{
if ( IsPopupWindowState(Visible) &&
( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) )
{
HidePopup(true);
return true;
}
HidePopup(true);
return true;
}
#endif
@@ -1820,10 +1693,9 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event )
{
if ( GetPopupWindowState() >= Animating )
{
#if USES_WXPOPUPWINDOW
#if !wxUSE_POPUPWIN
// Click here always hides the popup.
if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW )
HidePopup(true);
HidePopup(true);
#endif
}
else
@@ -1992,40 +1864,12 @@ void wxComboCtrlBase::CreatePopup()
if ( !m_winPopup )
{
#ifdef wxComboPopupWindowBase2
if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP )
{
#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),
tlwFlags );
#endif
#endif
m_popupWinType = SECONDARY_POPUP_TYPE;
}
else
#endif // wxComboPopupWindowBase2
{
m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER );
m_popupWinType = PRIMARY_POPUP_TYPE;
}
m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER );
m_winPopup->Bind(wxEVT_KEY_DOWN, &wxComboCtrlBase::OnPopupKey, this);
m_winPopup->Bind(wxEVT_CHAR, &wxComboCtrlBase::OnPopupKey, this);
m_winPopup->Bind(wxEVT_KEY_UP, &wxComboCtrlBase::OnPopupKey, this);
#if USES_GENERICTLW
#if !wxUSE_POPUPWIN
m_winPopup->Bind(wxEVT_ACTIVATE, &wxComboCtrlBase::OnPopupActivate, this);
#endif
m_winPopup->Bind(wxEVT_SIZE, &wxComboCtrlBase::OnPopupSize, this);
@@ -2298,18 +2142,15 @@ void wxComboCtrlBase::ShowPopup()
showFlags |= ShowAbove;
}
#if INSTALL_TOPLEV_HANDLER
#if !wxUSE_POPUPWIN
// Put top level window event handler into place
if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW )
{
if ( !m_toplevEvtHandler )
m_toplevEvtHandler = new wxComboFrameEventHandler(this);
if ( !m_toplevEvtHandler )
m_toplevEvtHandler = new wxComboFrameEventHandler(this);
wxWindow* toplev = ::wxGetTopLevelParent( this );
wxASSERT( toplev );
((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup();
toplev->PushEventHandler( m_toplevEvtHandler );
}
wxWindow* toplev = ::wxGetTopLevelParent( this );
wxASSERT( toplev );
((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup();
toplev->PushEventHandler( m_toplevEvtHandler );
#endif
// Set string selection (must be this way instead of SetStringSelection)
@@ -2375,26 +2216,16 @@ void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) )
// (though the bug was probably fixed).
winPopup->SetSize( rect );
#if USES_WXPOPUPTRANSIENTWINDOW
if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW )
((wxPopupTransientWindow*)winPopup)->Popup(m_popup);
else
#if wxUSE_POPUPWIN
((wxPopupTransientWindow*)winPopup)->Popup(m_popup);
#else
winPopup->Show();
#if !defined(__WXX11__)
m_popup->SetFocus();
#endif
#endif
winPopup->Show();
m_popupWinState = Visible;
// If popup window was a generic top-level window, or the
// wxPopupWindow implementation on this platform is classified as
// perfect, then we should be able to safely set focus to the popup
// control.
// In x11 backend, popup window neither generic top-level nor
// perfect native window. So shouldn't be set focus to the popup control
// same in the OnPopupDismiss function.
#if !defined(__WXX11__)
if ( IsPopupWinTypePerfect(m_popupWinType) )
m_popup->SetFocus();
#endif
}
else if ( IsPopupWindowState(Hidden) )
{
@@ -2428,7 +2259,7 @@ void wxComboCtrlBase::OnPopupDismiss(bool generateEvent)
m_beenInsidePopup = false;
m_blockEventsToPopup = true;
#if INSTALL_TOPLEV_HANDLER
#if !wxUSE_POPUPWIN
// Remove top level window event handler
if ( m_toplevEvtHandler )
{
@@ -2440,8 +2271,9 @@ void wxComboCtrlBase::OnPopupDismiss(bool generateEvent)
m_timeCanAcceptClick = ::wxGetLocalTimeMillis();
if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW )
m_timeCanAcceptClick += 150;
#if wxUSE_POPUPWIN
m_timeCanAcceptClick += 150;
#endif
// If cursor not on dropdown button, then clear its state
// (technically not required by all ports, but do it for all just in case)