Reimplement wxPopupWindow as a WS_POPUP window under MSW

Don't use the child window of the desktop window for popup windows under
MSW, while this worked in simplest cases, it didn't allow having
functional controls inside a wxPopupWindow as e.g. wxTextCtrl didn't
accept input it at all if created as a child of such window.

Instead, switch to using a top-level window, with WS_POPUP style, and
fix the problem with the loss of activation by explicitly pretending to
still be active in the owner window when losing activation to our own
popup (thanks to Barmak Shemirani for providing this solution).

Also use an MSW-specific and much simpler implementation of detecting
when the popup should be dismissed in wxPopupTransientWindow: instead of
capturing mouse or tracking focus, just react to activation loss
directly.

Add a wxTextCtrl to the popup in samples/popup to show that editing it
works now.
This commit is contained in:
Vadim Zeitlin
2018-10-20 18:44:18 +02:00
parent 17055fb8c6
commit 56c4191168
6 changed files with 206 additions and 109 deletions

View File

@@ -76,24 +76,16 @@ public:
// when the user clicks mouse outside it or if it loses focus in any other way
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_FWD_CORE wxPopupWindowHandler;
class WXDLLIMPEXP_FWD_CORE wxPopupFocusHandler;
class WXDLLIMPEXP_CORE wxPopupTransientWindow : public wxPopupWindow
// Define the public API of wxPopupTransientWindow:
class WXDLLIMPEXP_CORE wxPopupTransientWindowBase : public wxPopupWindow
{
public:
// ctors
wxPopupTransientWindow() { Init(); }
wxPopupTransientWindow(wxWindow *parent, int style = wxBORDER_NONE);
virtual ~wxPopupTransientWindow();
// popup the window (this will show it too) and keep focus at winFocus
// (or itself if it's NULL), dismiss the popup if we lose focus
virtual void Popup(wxWindow *focus = NULL);
virtual void Popup(wxWindow *focus = NULL) = 0;
// hide the window
virtual void Dismiss();
virtual void Dismiss() = 0;
// can the window be dismissed now?
//
@@ -104,24 +96,74 @@ public:
// called when a mouse is pressed while the popup is shown: return true
// from here to prevent its normal processing by the popup (which consists
// in dismissing it if the mouse is clicked outside it)
virtual bool ProcessLeftDown(wxMouseEvent& event);
// Overridden to grab the input on some plaforms
virtual bool Show( bool show = true ) wxOVERRIDE;
virtual bool ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
{ return false; }
// Override to implement delayed destruction of this window.
virtual bool Destroy() wxOVERRIDE;
protected:
// common part of all ctors
void Init();
// this is called when the popup is disappeared because of anything
// else but direct call to Dismiss()
virtual void OnDismiss();
virtual void OnDismiss() { }
// dismiss and notify the derived class
void DismissAndNotify();
void DismissAndNotify()
{
Dismiss();
OnDismiss();
}
};
#ifdef __WXMSW__
class WXDLLIMPEXP_CORE wxPopupTransientWindow : public wxPopupTransientWindowBase
{
public:
// ctors
wxPopupTransientWindow() { }
wxPopupTransientWindow(wxWindow *parent, int style = wxBORDER_NONE)
{ Create(parent, style); }
// Implement base class pure virtuals.
virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE;
virtual void Dismiss() wxOVERRIDE;
// Override to handle WM_NCACTIVATE.
virtual bool MSWHandleMessage(WXLRESULT *result,
WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam) wxOVERRIDE;
private:
wxDECLARE_DYNAMIC_CLASS(wxPopupTransientWindow);
wxDECLARE_NO_COPY_CLASS(wxPopupTransientWindow);
};
#else // !__WXMSW__
class WXDLLIMPEXP_FWD_CORE wxPopupWindowHandler;
class WXDLLIMPEXP_FWD_CORE wxPopupFocusHandler;
class WXDLLIMPEXP_CORE wxPopupTransientWindow : public wxPopupTransientWindowBase
{
public:
// ctors
wxPopupTransientWindow() { Init(); }
wxPopupTransientWindow(wxWindow *parent, int style = wxBORDER_NONE);
virtual ~wxPopupTransientWindow();
// Implement base class pure virtuals.
virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE;
virtual void Dismiss() wxOVERRIDE;
// Overridden to grab the input on some plaforms
virtual bool Show( bool show = true ) wxOVERRIDE;
protected:
// common part of all ctors
void Init();
// remove our event handlers
void PopHandlers();
@@ -129,7 +171,7 @@ protected:
// get alerted when child gets deleted from under us
void OnDestroy(wxWindowDestroyEvent& event);
#if defined(__WXMSW__) ||(defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON)
#if defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON
// Check if the mouse needs to be captured or released: we must release
// when it's inside our window if we want the embedded controls to work.
void OnIdle(wxIdleEvent& event);
@@ -154,6 +196,8 @@ protected:
wxDECLARE_NO_COPY_CLASS(wxPopupTransientWindow);
};
#endif // __WXMSW__/!__WXMSW__
#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
// ----------------------------------------------------------------------------