diff --git a/include/wx/msw/popupwin.h b/include/wx/msw/popupwin.h index bba24abfae..7a5ce58598 100644 --- a/include/wx/msw/popupwin.h +++ b/include/wx/msw/popupwin.h @@ -40,6 +40,10 @@ public: // Return the top level window parent of this popup or null. wxWindow* MSWGetOwner() const { return m_owner; } + // This is a way to notify non-wxPU_CONTAINS_CONTROLS windows about the + // events that should result in their dismissal. + virtual void MSWDismissUnfocusedPopup() { } + private: wxWindow* m_owner; diff --git a/include/wx/popupwin.h b/include/wx/popupwin.h index bd26b5445a..c3964098b6 100644 --- a/include/wx/popupwin.h +++ b/include/wx/popupwin.h @@ -133,13 +133,6 @@ public: wxPopupTransientWindow() { } wxPopupTransientWindow(wxWindow *parent, int style = wxBORDER_NONE) { Create(parent, style); } - bool Create(wxWindow *parent, int style = wxBORDER_NONE) - { - return wxPopupTransientWindowBase::Create - ( - parent, style | wxPU_CONTAINS_CONTROLS - ); - } // Implement base class pure virtuals. virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE; @@ -151,6 +144,9 @@ public: WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; + // Override to dismiss the popup. + virtual void MSWDismissUnfocusedPopup() wxOVERRIDE; + private: void DismissOnDeactivate(); diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index 9a69411e62..d4c8081b01 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -58,6 +58,10 @@ #include "wx/tipdlg.h" #endif // wxUSE_STARTUP_TIPS +#if wxUSE_TIPWINDOW + #include "wx/tipwin.h" +#endif // wxUSE_TIPWINDOW + #if wxUSE_PROGRESSDLG #if wxUSE_STOPWATCH && wxUSE_LONGLONG #include "wx/datetime.h" // wxDateTime @@ -280,6 +284,10 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(DIALOGS_NOTIFY_MSG, MyFrame::OnNotifMsg) #endif // wxUSE_NOTIFICATION_MESSAGE +#if wxUSE_TIPWINDOW + EVT_MENU(DIALOGS_SHOW_TIP, MyFrame::OnShowTip) + EVT_UPDATE_UI(DIALOGS_SHOW_TIP, MyFrame::OnUpdateShowTipUI) +#endif // wxUSE_TIPWINDOW #if wxUSE_RICHTOOLTIP EVT_MENU(DIALOGS_RICHTIP_DIALOG, MyFrame::OnRichTipDialog) #endif // wxUSE_RICHTOOLTIP @@ -590,6 +598,10 @@ bool MyApp::OnInit() #endif // wxUSE_NOTIFICATION_MESSAGE menuDlg->AppendSubMenu(menuNotif, "&User notifications"); +#if wxUSE_TIPWINDOW + menuDlg->AppendCheckItem(DIALOGS_SHOW_TIP, "Show &tip window\tShift-Ctrl-H"); +#endif // wxUSE_TIPWINDOW + #if wxUSE_RICHTOOLTIP menuDlg->Append(DIALOGS_RICHTIP_DIALOG, "Rich &tooltip dialog...\tCtrl-H"); menuDlg->AppendSeparator(); @@ -713,6 +725,10 @@ MyFrame::MyFrame(const wxString& title) SetOwnBackgroundColour(m_canvas->GetBackgroundColour()); #endif // wxUSE_INFOBAR +#if wxUSE_TIPWINDOW + m_tipWindow = NULL; +#endif // wxUSE_TIPWINDOW + #ifdef __WXMSW__ // Test MSW-specific function allowing to access the "system" menu. wxMenu * const menu = MSWGetSystemMenu(); @@ -2389,6 +2405,35 @@ void MyFrame::OnNotifMsg(wxCommandEvent& WXUNUSED(event)) #endif // wxUSE_NOTIFICATION_MESSAGE +#if wxUSE_TIPWINDOW + +void MyFrame::OnShowTip(wxCommandEvent& WXUNUSED(event)) +{ + if ( m_tipWindow ) + { + m_tipWindow->Close(); + } + else + { + m_tipWindow = new wxTipWindow + ( + this, + "This is just some text to be shown in the tip " + "window, broken into multiple lines, each less " + "than 60 logical pixels wide.", + FromDIP(60), + &m_tipWindow + ); + } +} + +void MyFrame::OnUpdateShowTipUI(wxUpdateUIEvent& event) +{ + event.Check(m_tipWindow != NULL); +} + +#endif // wxUSE_TIPWINDOW + #if wxUSE_RICHTOOLTIP #include "wx/richtooltip.h" diff --git a/samples/dialogs/dialogs.h b/samples/dialogs/dialogs.h index 4bde46e3c6..3b058c1cca 100644 --- a/samples/dialogs/dialogs.h +++ b/samples/dialogs/dialogs.h @@ -544,6 +544,13 @@ private: SettingsData m_settingsData; #endif // USE_SETTINGS_DIALOG +#if wxUSE_TIPWINDOW + void OnShowTip(wxCommandEvent& event); + void OnUpdateShowTipUI(wxUpdateUIEvent& event); + + wxTipWindow *m_tipWindow; +#endif // wxUSE_TIPWINDOW + wxDECLARE_EVENT_TABLE(); }; @@ -623,6 +630,7 @@ enum DIALOGS_REPLACE, DIALOGS_REQUEST, DIALOGS_NOTIFY_MSG, + DIALOGS_SHOW_TIP, DIALOGS_RICHTIP_DIALOG, DIALOGS_PROPERTY_SHEET, DIALOGS_PROPERTY_SHEET_TOOLBOOK, diff --git a/samples/popup/popup.cpp b/samples/popup/popup.cpp index 1e0cf61912..09a80b9df2 100644 --- a/samples/popup/popup.cpp +++ b/samples/popup/popup.cpp @@ -108,7 +108,9 @@ wxBEGIN_EVENT_TABLE(SimpleTransientPopup,wxPopupTransientWindow) wxEND_EVENT_TABLE() SimpleTransientPopup::SimpleTransientPopup( wxWindow *parent, bool scrolled ) - :wxPopupTransientWindow( parent ) + :wxPopupTransientWindow( parent, + wxBORDER_NONE | + wxPU_CONTAINS_CONTROLS ) { m_panel = new wxScrolledWindow( this, wxID_ANY ); m_panel->SetBackgroundColour( *wxLIGHT_GREY ); diff --git a/src/generic/tipwin.cpp b/src/generic/tipwin.cpp index f73dbf82bd..b3f56f51d6 100644 --- a/src/generic/tipwin.cpp +++ b/src/generic/tipwin.cpp @@ -136,7 +136,9 @@ wxTipWindow::wxTipWindow(wxWindow *parent, // set size, position and show it m_view = new wxTipWindowView(this); m_view->Adjust(text, maxLength); +#if !wxUSE_POPUPWIN m_view->SetFocus(); +#endif int x, y; wxGetMousePosition(&x, &y); diff --git a/src/msw/popupwin.cpp b/src/msw/popupwin.cpp index c3f42860f9..6491a6f007 100644 --- a/src/msw/popupwin.cpp +++ b/src/msw/popupwin.cpp @@ -180,10 +180,10 @@ void wxPopupTransientWindow::Popup(wxWindow* focus) { Show(); - // We can only set focus to one of our children as setting it to another - // window would result in an immediate loss of activation and popup - // disappearance. - if ( focus && IsDescendant(focus) ) + // We can only set focus when using wxPU_CONTAINS_CONTROLS and then only to + // one of our children as setting it to another window would result in an + // immediate loss of activation and popup disappearance. + if ( HasFlag(wxPU_CONTAINS_CONTROLS) && focus && IsDescendant(focus) ) focus->SetFocus(); } @@ -195,7 +195,7 @@ void wxPopupTransientWindow::Dismiss() void wxPopupTransientWindow::DismissOnDeactivate() { // Hide the window automatically when it loses activation. - Dismiss(); + DismissAndNotify(); // Activation might have gone to a different window or maybe // even a different application, don't let our owner continue @@ -210,6 +210,19 @@ void wxPopupTransientWindow::DismissOnDeactivate() } } +void wxPopupTransientWindow::MSWDismissUnfocusedPopup() +{ + // When we use wxPU_CONTAINS_CONTROLS, we can react to the popup + // deactivation in MSWHandleMessage(), but if we don't have focus, we don't + // get any events ourselves, so we rely on wxWindow to forward them to us. + if ( !HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + // It doesn't seem necessary to use CallAfter() here, as dismissing + // this window shouldn't affect the focus, as it never has it anyhow. + DismissAndNotify(); + } +} + bool wxPopupTransientWindow::MSWHandleMessage(WXLRESULT *result, WXUINT message, diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2e5be999d9..2a2864cedf 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -3844,6 +3844,42 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, } } + // Special hook for dismissing the current popup if it's active. It's a bit + // ugly to have to do this here, but the only alternatives seem to be + // installing a WH_CBT hook in wxPopupTransientWindow code, which is not + // really much better. +#if wxUSE_POPUPWIN + if ( wxCurrentPopupWindow ) + { + switch ( message ) + { + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: + + case WM_SETFOCUS: + case WM_KILLFOCUS: + wxCurrentPopupWindow->MSWDismissUnfocusedPopup(); + } + } +#endif // wxUSE_POPUPWIN + if ( !processed ) return false;