From f3f3b00c6b45fd2651dc2ec7853f5d3f381ff937 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 18:03:37 +0100 Subject: [PATCH 1/9] Actually show messages in the combo sample Messages from wxLogDebug() didn't appear in wxLogTextCtrl log target, so use wxLogMessage() to actually see the messages logged by the sample. --- samples/combo/combo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/combo/combo.cpp b/samples/combo/combo.cpp index 6176989941..c9d9584001 100644 --- a/samples/combo/combo.cpp +++ b/samples/combo/combo.cpp @@ -934,15 +934,15 @@ void MyFrame::OnComboBoxUpdate( wxCommandEvent& event ) if ( event.GetEventType() == wxEVT_COMBOBOX ) { - wxLogDebug("EVT_COMBOBOX(id=%i,selection=%i)",event.GetId(),event.GetSelection()); + wxLogMessage("EVT_COMBOBOX(id=%i,selection=%i)",event.GetId(),event.GetSelection()); } else if ( event.GetEventType() == wxEVT_TEXT ) { - wxLogDebug("EVT_TEXT(id=%i,string=\"%s\")",event.GetId(),event.GetString()); + wxLogMessage("EVT_TEXT(id=%i,string=\"%s\")",event.GetId(),event.GetString()); } else if ( event.GetEventType() == wxEVT_TEXT_ENTER ) { - wxLogDebug("EVT_TEXT_ENTER(id=%i,string=\"%s\")", + wxLogMessage("EVT_TEXT_ENTER(id=%i,string=\"%s\")", event.GetId(), event.GetString()); } } From cf3ebcea1ae691ce98f8461acbfe3703aae62982 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 16:49:57 +0100 Subject: [PATCH 2/9] Merge wxComboCtrl::InstallInputHandlers() into CreateTextCtrl() This function was always called after calling CreateTextCtrl() and couldn't be called at any other moment, so it didn't make much sense to have it as a separate function, just install the custom input handler when (re)creating the text control. This simplifies the derived classes code. --- include/wx/combo.h | 3 --- src/common/combocmn.cpp | 26 +++++++++----------------- src/generic/combog.cpp | 8 -------- src/msw/combo.cpp | 3 --- 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/include/wx/combo.h b/include/wx/combo.h index 8becce369c..91f2e5d392 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -509,9 +509,6 @@ protected: // (e.g. from WriteText()) void OnSetValue(const wxString& value); - // Installs standard input handler to combo (and optionally to the textctrl) - void InstallInputHandlers(); - // Flags for DrawButton enum { diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index b61aac35bf..323d85bd96 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -1068,22 +1068,19 @@ bool wxComboCtrlBase::Create(wxWindow *parent, return true; } -void wxComboCtrlBase::InstallInputHandlers() -{ - if ( m_text ) - { - m_textEvtHandler = new wxComboBoxExtraInputHandler(this); - m_text->PushEventHandler(m_textEvtHandler); - } -} - void wxComboCtrlBase::CreateTextCtrl(int style) { if ( !(m_windowStyle & wxCB_READONLY) ) { if ( m_text ) + { + m_text->RemoveEventHandler(m_textEvtHandler); + delete m_textEvtHandler; + m_textEvtHandler = NULL; + m_text->Destroy(); + } // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is // not used by the wxPropertyGrid and therefore the tab is processed by @@ -1094,14 +1091,6 @@ wxComboCtrlBase::CreateTextCtrl(int style) if ( HasFlag(wxTE_PROCESS_ENTER) ) style |= wxTE_PROCESS_ENTER; - // Ignore EVT_TEXT generated by the constructor (but only - // if the event redirector already exists) - // NB: This must be " = 1" instead of "++"; - if ( m_textEvtHandler ) - m_ignoreEvtText = 1; - else - m_ignoreEvtText = 0; - m_text = new wxComboCtrlTextCtrl(); m_text->Create(this, wxID_ANY, m_valueString, wxDefaultPosition, wxSize(10,-1), @@ -1115,6 +1104,9 @@ wxComboCtrlBase::CreateTextCtrl(int style) } m_text->SetHint(m_hintText); + + m_textEvtHandler = new wxComboBoxExtraInputHandler(this); + m_text->PushEventHandler(m_textEvtHandler); } } diff --git a/src/generic/combog.cpp b/src/generic/combog.cpp index bae13d912f..5b1bcc26ca 100644 --- a/src/generic/combog.cpp +++ b/src/generic/combog.cpp @@ -177,9 +177,6 @@ bool wxGenericComboCtrl::Create(wxWindow *parent, // Create textctrl, if necessary CreateTextCtrl( tcBorder ); - // Add keyboard input handlers for main control and textctrl - InstallInputHandlers(); - // Set background style for double-buffering, when needed // (cannot use when system draws background automatically) if ( !HasTransparentBackground() ) @@ -419,12 +416,7 @@ void wxGenericComboCtrl::SetCustomPaintWidth( int width ) // Common textctrl re-creation code if ( tcCreateStyle != -1 ) { - tc->RemoveEventHandler(m_textEvtHandler); - delete m_textEvtHandler; - CreateTextCtrl( tcCreateStyle ); - - InstallInputHandlers(); } } #endif // UNRELIABLE_TEXTCTRL_BORDER diff --git a/src/msw/combo.cpp b/src/msw/combo.cpp index adb8ccab0d..cac21a05fb 100644 --- a/src/msw/combo.cpp +++ b/src/msw/combo.cpp @@ -120,9 +120,6 @@ bool wxComboCtrl::Create(wxWindow *parent, // Create textctrl, if necessary CreateTextCtrl( wxNO_BORDER ); - // Add keyboard input handlers for main control and textctrl - InstallInputHandlers(); - // SetInitialSize should be called last SetInitialSize(size); From d6426168a3df7264ece4ddf5fd392474faecc6f9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 16:59:11 +0100 Subject: [PATCH 3/9] Remove wxComboBoxExtraInputHandler and use Bind() instead There is no need to use a separate wxEvtHandler here when we can just use Bind() to directly handle the child text control events in wxComboCtrlBase itself, this code was a left over from pre-wx3 days. No real changes, just make the code simpler and smaller (and also marginally more efficient at run-time). --- include/wx/combo.h | 6 +-- src/common/combocmn.cpp | 81 ++++++++++------------------------------- 2 files changed, 22 insertions(+), 65 deletions(-) diff --git a/include/wx/combo.h b/include/wx/combo.h index 91f2e5d392..91ff173e43 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -572,6 +572,9 @@ protected: void OnKeyEvent(wxKeyEvent& event); void OnCharEvent(wxKeyEvent& event); + void OnTextFocus(wxFocusEvent& event); + void OnTextKey(wxKeyEvent& event); + // Set customization flags (directs how wxComboCtrlBase helpers behave) void Customize( wxUint32 flags ) { m_iFlags |= flags; } @@ -627,9 +630,6 @@ protected: // popup interface wxComboPopup* m_popupInterface; - // this is input etc. handler for the text control - wxEvtHandler* m_textEvtHandler; - // this is for the top level window wxEvtHandler* m_toplevEvtHandler; diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 323d85bd96..5ebd705832 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -721,65 +721,30 @@ void wxComboPopup::DestroyPopup() // input handling // ---------------------------------------------------------------------------- -// -// This is pushed to the event handler queue of the child textctrl. -// -class wxComboBoxExtraInputHandler : public wxEvtHandler -{ -public: - - wxComboBoxExtraInputHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() - { - m_combo = combo; - } - virtual ~wxComboBoxExtraInputHandler() { } - void OnKey(wxKeyEvent& event); - void OnFocus(wxFocusEvent& event); - -protected: - wxComboCtrlBase* m_combo; - -private: - wxDECLARE_EVENT_TABLE(); -}; - - -wxBEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) - EVT_KEY_UP(wxComboBoxExtraInputHandler::OnKey) - EVT_CHAR(wxComboBoxExtraInputHandler::OnKey) - EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) - EVT_KILL_FOCUS(wxComboBoxExtraInputHandler::OnFocus) -wxEND_EVENT_TABLE() - - -void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) +void wxComboCtrlBase::OnTextKey(wxKeyEvent& event) { // Let the wxComboCtrl event handler have a go first. - wxComboCtrlBase* combo = m_combo; - wxKeyEvent redirectedEvent(event); - redirectedEvent.SetId(combo->GetId()); - redirectedEvent.SetEventObject(combo); + redirectedEvent.SetId(GetId()); + redirectedEvent.SetEventObject(this); - if ( !combo->GetEventHandler()->ProcessEvent(redirectedEvent) ) + if ( !GetEventHandler()->ProcessEvent(redirectedEvent) ) { event.Skip(); } } -void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) +void wxComboCtrlBase::OnTextFocus(wxFocusEvent& event) { // FIXME: This code does run when control is clicked, // yet on Windows it doesn't select all the text. if ( event.GetEventType() == wxEVT_SET_FOCUS && - !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) + !(GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) { - if ( m_combo->GetTextCtrl() ) - m_combo->GetTextCtrl()->SelectAll(); + if ( GetTextCtrl() ) + GetTextCtrl()->SelectAll(); else - m_combo->SelectAll(); + SelectAll(); } // Send focus indication to parent. @@ -789,9 +754,9 @@ void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) // from combo's focus event handler), they should be quite // harmless. wxFocusEvent evt2(event); - evt2.SetId(m_combo->GetId()); - evt2.SetEventObject(m_combo); - m_combo->GetEventHandler()->ProcessEvent(evt2); + evt2.SetId(GetId()); + evt2.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt2); event.Skip(); } @@ -996,7 +961,6 @@ void wxComboCtrlBase::Init() m_popupInterface = NULL; m_popupEvtHandler = NULL; - m_textEvtHandler = NULL; #if INSTALL_TOPLEV_HANDLER m_toplevEvtHandler = NULL; @@ -1074,13 +1038,7 @@ wxComboCtrlBase::CreateTextCtrl(int style) if ( !(m_windowStyle & wxCB_READONLY) ) { if ( m_text ) - { - m_text->RemoveEventHandler(m_textEvtHandler); - delete m_textEvtHandler; - m_textEvtHandler = NULL; - m_text->Destroy(); - } // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is // not used by the wxPropertyGrid and therefore the tab is processed by @@ -1103,10 +1061,14 @@ wxComboCtrlBase::CreateTextCtrl(int style) m_text->Bind(wxEVT_TEXT_ENTER, &wxComboCtrlBase::OnTextCtrlEvent, this); } - m_text->SetHint(m_hintText); + m_text->Bind(wxEVT_SET_FOCUS, &wxComboCtrlBase::OnTextFocus, this); + m_text->Bind(wxEVT_KILL_FOCUS, &wxComboCtrlBase::OnTextFocus, this); - m_textEvtHandler = new wxComboBoxExtraInputHandler(this); - m_text->PushEventHandler(m_textEvtHandler); + m_text->Bind(wxEVT_KEY_DOWN, &wxComboCtrlBase::OnTextKey, this); + m_text->Bind(wxEVT_CHAR, &wxComboCtrlBase::OnTextKey, this); + m_text->Bind(wxEVT_KEY_UP, &wxComboCtrlBase::OnTextKey, this); + + m_text->SetHint(m_hintText); } } @@ -1152,11 +1114,6 @@ wxComboCtrlBase::~wxComboCtrlBase() #endif DestroyPopup(); - - if ( m_text ) - m_text->RemoveEventHandler(m_textEvtHandler); - - delete m_textEvtHandler; } From f3fb6dc833dcee16a25589e2aa68e6c737ee6088 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 17:14:25 +0100 Subject: [PATCH 4/9] Get rid of wxComboPopupWindowEvtHandler in wxComboCtrlBase too Use Bind() calls instead of another event handler too, for the same reasons as in the previous commit. --- include/wx/combo.h | 7 +++-- src/common/combocmn.cpp | 70 ++++++++++------------------------------- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/include/wx/combo.h b/include/wx/combo.h index 91ff173e43..e35fa94c23 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -575,6 +575,10 @@ protected: void OnTextFocus(wxFocusEvent& event); void OnTextKey(wxKeyEvent& event); + void OnPopupActivate(wxActivateEvent& event); + void OnPopupKey(wxKeyEvent& event); + void OnPopupSize(wxSizeEvent& event); + // Set customization flags (directs how wxComboCtrlBase helpers behave) void Customize( wxUint32 flags ) { m_iFlags |= flags; } @@ -636,9 +640,6 @@ protected: // this is for the control in popup wxEvtHandler* m_popupEvtHandler; - // this is for the popup window - wxEvtHandler* m_popupWinEvtHandler; - // main (ie. topmost) window of a composite control (default = this) wxWindow* m_mainCtrlWnd; diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 5ebd705832..953551f31e 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -527,63 +527,26 @@ void wxComboPopupWindow::OnDismiss() // ---------------------------------------------------------------------------- -// wxComboPopupWindowEvtHandler does bulk of the custom event handling -// of a popup window. It is separate so we can have different types -// of popup windows. +// custom event handling for popup window is done in wxComboCtrlBase so we can +// have different types of popup windows. // ---------------------------------------------------------------------------- -class wxComboPopupWindowEvtHandler : public wxEvtHandler -{ -public: - - wxComboPopupWindowEvtHandler( wxComboCtrlBase *parent ) - { - m_combo = parent; - } - - void OnSizeEvent( wxSizeEvent& event ); - void OnKeyEvent(wxKeyEvent& event); -#if USES_GENERICTLW - void OnActivate( wxActivateEvent& event ); -#endif - -private: -#if USES_GENERICTLW - void HideOnDeactivate(); -#endif // USES_GENERICTLW - wxComboCtrlBase* m_combo; - - wxDECLARE_EVENT_TABLE(); -}; - - -wxBEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent) - EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent) - EVT_CHAR(wxComboPopupWindowEvtHandler::OnKeyEvent) -#if USES_GENERICTLW - EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate) -#endif - EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent) -wxEND_EVENT_TABLE() - - -void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) ) +void wxComboCtrlBase::OnPopupSize( wxSizeEvent& WXUNUSED(event) ) { // Block the event so that the popup control does not get auto-resized. } -void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) +void wxComboCtrlBase::OnPopupKey( wxKeyEvent& event ) { // Relay keyboard event to the main child controls - wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); + wxWindowList children = GetPopupWindow()->GetChildren(); wxWindowList::iterator node = children.begin(); wxWindow* child = (wxWindow*)*node; child->GetEventHandler()->ProcessEvent(event); } #if USES_GENERICTLW -void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) +void wxComboCtrlBase::OnPopupActivate( wxActivateEvent& event ) { if ( !event.GetActive() ) { @@ -593,18 +556,13 @@ void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) // event handler causes some side effects like calling this handler again (Win 7) // or setting the focus improperly (Win 10), so postpone it slightly. // See wxPopupTransientWindow::MSWHandleMessage(). - CallAfter(&wxComboPopupWindowEvtHandler::HideOnDeactivate); + CallAfter(&wxComboCtrlBase::Dismiss); #else // !__WXMSW__ - HideOnDeactivate(); + Dismiss(); #endif // __WXMSW__ / !__WXMSW__ event.Skip(); } } - -void wxComboPopupWindowEvtHandler::HideOnDeactivate() -{ - m_combo->HidePopup(true); -} #endif @@ -2113,8 +2071,14 @@ void wxComboCtrlBase::CreatePopup() m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); m_popupWinType = PRIMARY_POPUP_TYPE; } - m_popupWinEvtHandler = new wxComboPopupWindowEvtHandler(this); - m_winPopup->PushEventHandler(m_popupWinEvtHandler); + + 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 + m_winPopup->Bind(wxEVT_ACTIVATE, &wxComboCtrlBase::OnPopupActivate, this); +#endif + m_winPopup->Bind(wxEVT_SIZE, &wxComboCtrlBase::OnPopupSize, this); } popupInterface->Create(m_winPopup); @@ -2150,8 +2114,6 @@ void wxComboCtrlBase::DestroyPopup() if ( m_winPopup ) { - m_winPopup->RemoveEventHandler(m_popupWinEvtHandler); - wxDELETE(m_popupWinEvtHandler); m_winPopup->Destroy(); m_winPopup = NULL; } From d7d5231e96e83daa6fd6987b80b4c5dbf232b1ca Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 19:33:01 +0100 Subject: [PATCH 5/9] Replace wxComboPopupEvtHandler with calls to Bind() as well This is not as much of a simplification as the previous two commits because there is no simple replacement of EVT_MOUSE_EVENTS() using Bind() and a loop over all mouse event types has to be written explicitly, but it still avoids the need to allocate and delete a separate object, so is still worth it. --- include/wx/combo.h | 9 ++-- src/common/combocmn.cpp | 115 +++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 69 deletions(-) diff --git a/include/wx/combo.h b/include/wx/combo.h index e35fa94c23..18f972fcc8 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -579,6 +579,8 @@ protected: void OnPopupKey(wxKeyEvent& event); void OnPopupSize(wxSizeEvent& event); + void OnPopupMouseEvent(wxMouseEvent& event); + // Set customization flags (directs how wxComboCtrlBase helpers behave) void Customize( wxUint32 flags ) { m_iFlags |= flags; } @@ -637,9 +639,6 @@ protected: // this is for the top level window wxEvtHandler* m_toplevEvtHandler; - // this is for the control in popup - wxEvtHandler* m_popupEvtHandler; - // main (ie. topmost) window of a composite control (default = this) wxWindow* m_mainCtrlWnd; @@ -718,6 +717,10 @@ protected: // is the text-area background colour overridden? bool m_hasTcBgCol; + // flags used while popup is shown + bool m_beenInsidePopup; + bool m_blockEventsToPopup; + private: void Init(); diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 953551f31e..32ee041151 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -720,62 +720,17 @@ void wxComboCtrlBase::OnTextFocus(wxFocusEvent& event) } -// -// This is pushed to the event handler queue of the control in popup. -// - -class wxComboPopupEvtHandler : public wxEvtHandler -{ -public: - - 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 ~wxComboPopupEvtHandler() { } - - void OnMouseEvent( wxMouseEvent& event ); - - // Called from wxComboCtrlBase::OnPopupDismiss - void OnPopupDismiss() - { - m_beenInside = false; - m_blockEventsToPopup = true; - } - -protected: - wxComboCtrlBase* m_combo; - - bool m_beenInside; - bool m_blockEventsToPopup; - -private: - wxDECLARE_EVENT_TABLE(); -}; - - -wxBEGIN_EVENT_TABLE(wxComboPopupEvtHandler, wxEvtHandler) - EVT_MOUSE_EVENTS(wxComboPopupEvtHandler::OnMouseEvent) -wxEND_EVENT_TABLE() - - -void wxComboPopupEvtHandler::OnMouseEvent( wxMouseEvent& event ) +void wxComboCtrlBase::OnPopupMouseEvent( wxMouseEvent& event ) { wxPoint pt = event.GetPosition(); - wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); + wxSize sz = GetPopupControl()->GetControl()->GetClientSize(); int evtType = event.GetEventType(); bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; bool relayToButton = false; event.Skip(); - if ( !isInside || !m_combo->IsPopupShown() ) + if ( !isInside || !IsPopupShown() ) { // Mouse is outside the popup or popup is not actually shown (yet) @@ -792,7 +747,7 @@ void wxComboPopupEvtHandler::OnMouseEvent( wxMouseEvent& event ) { // Mouse is inside the popup, which is fully shown - m_beenInside = true; + m_beenInsidePopup = true; // Do not let the popup control respond to mouse events until // mouse press used to display the popup has been lifted. This @@ -844,12 +799,12 @@ void wxComboPopupEvtHandler::OnMouseEvent( wxMouseEvent& event ) // if ( evtType == wxEVT_LEFT_UP ) { - if ( !m_combo->IsPopupShown() ) + if ( !IsPopupShown() ) { event.Skip(false); relayToButton = true; } - else if ( !isInside && !m_beenInside ) + else if ( !isInside && !m_beenInsidePopup ) { // Popup is shown but the cursor is not inside, nor it has been relayToButton = true; @@ -858,14 +813,14 @@ void wxComboPopupEvtHandler::OnMouseEvent( wxMouseEvent& event ) if ( relayToButton ) { - wxWindow* btn = m_combo->GetButton(); + wxWindow* btn = GetButton(); if ( btn ) 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); + HandleButtonMouseEvent(event, 0); } } @@ -918,8 +873,6 @@ void wxComboCtrlBase::Init() m_text = NULL; m_popupInterface = NULL; - m_popupEvtHandler = NULL; - #if INSTALL_TOPLEV_HANDLER m_toplevEvtHandler = NULL; #endif @@ -950,6 +903,12 @@ void wxComboCtrlBase::Init() m_resetFocus = false; m_hasTcBgCol = false; + + m_beenInsidePopup = 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; } bool wxComboCtrlBase::Create(wxWindow *parent, @@ -2038,7 +1997,6 @@ void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event void wxComboCtrlBase::CreatePopup() { wxComboPopup* popupInterface = m_popupInterface; - wxWindow* popup; if ( !m_winPopup ) { @@ -2082,10 +2040,39 @@ void wxComboCtrlBase::CreatePopup() } popupInterface->Create(m_winPopup); - m_popup = popup = popupInterface->GetControl(); + m_popup = popupInterface->GetControl(); - m_popupEvtHandler = new wxComboPopupEvtHandler(this); - popup->PushEventHandler( m_popupEvtHandler ); + // Bind all mouse events, as used to be done by EVT_MOUSE_EVENTS() event + // table macro, to this handler. + const wxEventTypeTag allMouseEventTypes[] = + { + wxEVT_LEFT_DOWN, + wxEVT_LEFT_UP, + wxEVT_LEFT_DCLICK, + wxEVT_MIDDLE_DOWN, + wxEVT_MIDDLE_UP, + wxEVT_MIDDLE_DCLICK, + wxEVT_RIGHT_DOWN, + wxEVT_RIGHT_UP, + wxEVT_RIGHT_DCLICK, + wxEVT_AUX1_DOWN, + wxEVT_AUX1_UP, + wxEVT_AUX1_DCLICK, + wxEVT_AUX2_DOWN, + wxEVT_AUX2_UP, + wxEVT_AUX2_DCLICK, + wxEVT_MOTION, + wxEVT_LEAVE_WINDOW, + wxEVT_ENTER_WINDOW, + wxEVT_MOUSEWHEEL, + wxEVT_MAGNIFY, + }; + + for ( size_t n = 0; n < WXSIZEOF(allMouseEventTypes); ++n ) + { + m_popup->Bind(allMouseEventTypes[n], + &wxComboCtrlBase::OnPopupMouseEvent, this); + } // This may be helpful on some platforms // (eg. it bypasses a wxGTK popupwindow bug where @@ -2100,11 +2087,6 @@ void wxComboCtrlBase::DestroyPopup() { HidePopup(true); - if ( m_popup ) - m_popup->RemoveEventHandler(m_popupEvtHandler); - - wxDELETE(m_popupEvtHandler); - if ( m_popupInterface ) { // NB: DestroyPopup() performs 'delete this'. @@ -2450,8 +2432,9 @@ void wxComboCtrlBase::OnPopupDismiss(bool generateEvent) // Inform popup control itself m_popupInterface->OnDismiss(); - if ( m_popupEvtHandler ) - ((wxComboPopupEvtHandler*)m_popupEvtHandler)->OnPopupDismiss(); + // Reset popup-related flags. + m_beenInsidePopup = false; + m_blockEventsToPopup = true; #if INSTALL_TOPLEV_HANDLER // Remove top level window event handler From 67f27f1b89e42aee37361a8ce1c7311df55a792c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 17:54:09 +0100 Subject: [PATCH 6/9] Always center text control in wxComboCtrl vertically Simplify the code by removing TEXTCTRL_TEXT_CENTERED, it was only set to 1 for "other" (i.e. not one of the main ones) platforms and if it's really a problem for them, which is not even certain, the solution is to fix them rather than to uglify common code. --- src/common/combocmn.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 32ee041151..d9a5cc15ea 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -136,7 +136,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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. -#define TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered #define FOCUS_RING 0 // No focus ring on wxMSW //#undef wxUSE_POPUPWIN @@ -167,7 +166,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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 TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered #define FOCUS_RING 0 // No focus ring on wxGTK #elif defined(__WXMAC__) @@ -180,7 +178,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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 TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered #define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display #undef DEFAULT_DROPBUTTON_WIDTH @@ -197,7 +194,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered #define FOCUS_RING 0 #endif @@ -1198,15 +1194,10 @@ void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust m_marginLeft + textCtrlXAdjust; } - // Centre textctrl vertically, if needed -#if !TEXTCTRL_TEXT_CENTERED + // Centre textctrl vertically int tcSizeY = m_text->GetBestSize().y; int diff0 = sz.y - tcSizeY; int y = textCtrlYAdjust + (diff0/2); -#else - wxUnusedVar(textCtrlYAdjust); - int y = 0; -#endif if ( y < customBorder ) y = customBorder; From 272b1009ccf5454f198047033891f46fd35309c7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 18:08:12 +0100 Subject: [PATCH 7/9] Define default FOCUS_RING value just once Mac is the only platform which needs, so just define it as 0 for all the other ones. No real changes. --- src/common/combocmn.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index d9a5cc15ea..5dd8142f14 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -136,7 +136,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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. -#define FOCUS_RING 0 // No focus ring on wxMSW //#undef wxUSE_POPUPWIN //#define wxUSE_POPUPWIN 0 @@ -166,7 +165,6 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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 0 // No focus ring on wxGTK #elif defined(__WXMAC__) @@ -194,10 +192,13 @@ wxCONSTRUCTOR_5( wxComboBox, wxWindow*, Parent, wxWindowID, Id, \ #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. -#define FOCUS_RING 0 #endif +// No focus ring by default. +#ifndef FOCUS_RING + #define FOCUS_RING 0 +#endif // Popupwin is really only supported on wxMSW and wxGTK, regardless // what the wxUSE_POPUPWIN says. From aa42d9c8058ca9c7e5cb329a0d1fee47a285e2d0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 18:24:34 +0100 Subject: [PATCH 8/9] 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. --- include/wx/combo.h | 3 - src/common/combocmn.cpp | 246 +++++++--------------------------------- 2 files changed, 39 insertions(+), 210 deletions(-) diff --git a/include/wx/combo.h b/include/wx/combo.h index 18f972fcc8..aefae67cb8 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -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); diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 5dd8142f14..9da9bee49f 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -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) From e631e7da627936c8099d1032bbe9a2e0046082a7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Jul 2021 22:32:24 +0100 Subject: [PATCH 9/9] Avoid using wxDynamicCast() with wxComboCtrl-derived object In wxUniv wxComboBox does derive from wxComboCtrl, but its wxRTTI doesn't use wxComboCtrl as the base class for consistency with the other ports, meaning that wxDynamicCast() to wxComboCtrl fails. Avoid this problem by storing wxComboCtrl in wxComboPopupWindow, as then we can just use it later without any casts -- at the price of storing an extra pointer in a transient object, i.e. without any real cost. See https://github.com/wxWidgets/wxWidgets/pull/2418 --- src/common/combocmn.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 9da9bee49f..5b9bf49c40 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -339,6 +339,7 @@ public: wxSize(20,20), style) #endif + , m_combo(parent) { m_inShow = 0; } @@ -351,7 +352,13 @@ protected: #endif private: + // This is the same as our parent, but has the right type, so that we can + // avoid using casts later. + wxComboCtrlBase* const m_combo; + wxByte m_inShow; + + wxDECLARE_NO_COPY_CLASS(wxComboPopupWindow); }; @@ -391,11 +398,7 @@ bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event) // First thing that happens when a transient popup closes is that this method gets called. void wxComboPopupWindow::OnDismiss() { - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); - wxASSERT_MSG( wxDynamicCast(combo, wxComboCtrlBase), - wxT("parent might not be wxComboCtrl, but check wxIMPLEMENT_DYNAMIC_CLASS2() macro for correctness") ); - - combo->OnPopupDismiss(true); + m_combo->OnPopupDismiss(true); } #endif // wxUSE_POPUPWIN