From: Vadim Zeitlin Date: Sun, 24 Feb 2013 13:48:13 +0000 (+0000) Subject: Move menu messages handling from wxFrame to wxTLW in wxMSW. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/95316a3f245a4baf3046e97222660bed986153ed?hp=823e18c7bc486a9f0dc3bc096b4991b162079044 Move menu messages handling from wxFrame to wxTLW in wxMSW. This allows to generate the menu open/close/highlight events correctly for the popup menus used in the dialogs. Extend the menu sample with a test using such menus. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73562 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index 63ea382529..2a24661b70 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -649,6 +649,7 @@ wxMSW: - Allow creating wxCursor from ANI files (Catalin Raceanu). - Add wxIcon::CreateFromHICON() (troelsk). - Improve wxCURSOR_RIGHT_ARROW appearance (DoltAlya). +- Generate menu highlight events for popup menus in wxDialog (Sam Partington). wxOSX/Cocoa: diff --git a/include/wx/msw/frame.h b/include/wx/msw/frame.h index 2ea3ed670f..20ce9333ad 100644 --- a/include/wx/msw/frame.h +++ b/include/wx/msw/frame.h @@ -77,7 +77,6 @@ public: // event handlers bool HandleSize(int x, int y, WXUINT flag); bool HandleCommand(WXWORD id, WXWORD cmd, WXHWND control); - bool HandleMenuSelect(WXWORD nItem, WXWORD nFlags, WXHMENU hMenu); // tooltip management #if wxUSE_TOOLTIPS @@ -105,6 +104,9 @@ public: // get the currently active menu: this is the same as the frame menu for // normal frames but is overridden by wxMDIParentFrame virtual WXHMENU MSWGetActiveMenu() const { return m_hMenu; } + + // Look up the menu in the menu bar. + virtual wxMenu* MSWFindMenuFromHMENU(WXHMENU hMenu); #endif // wxUSE_MENUS protected: @@ -131,18 +133,6 @@ protected: // wxMDIChildFrame bool MSWDoTranslateMessage(wxFrame *frame, WXMSG *msg); -#if wxUSE_MENUS - // handle WM_EXITMENULOOP message for Win95 only - bool HandleExitMenuLoop(WXWORD isPopup); - - // handle WM_(UN)INITMENUPOPUP message to generate wxEVT_MENU_OPEN/CLOSE - bool HandleMenuPopup(wxEventType evtType, WXHMENU hMenu); - - // Command part of HandleMenuPopup() and HandleExitMenuLoop(). - bool DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup); -#endif // wxUSE_MENUS - - virtual bool IsMDIChild() const { return false; } // get default (wxWidgets) icon for the frame diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h index 04d5b08947..690536dd82 100644 --- a/include/wx/msw/toplevel.h +++ b/include/wx/msw/toplevel.h @@ -122,6 +122,22 @@ public: // returns true if the platform should explicitly apply a theme border virtual bool CanApplyThemeBorder() const { return false; } +#if wxUSE_MENUS + bool HandleMenuSelect(WXWORD nItem, WXWORD nFlags, WXHMENU hMenu); + + // handle WM_EXITMENULOOP message for Win95 only + bool HandleExitMenuLoop(WXWORD isPopup); + + // handle WM_(UN)INITMENUPOPUP message to generate wxEVT_MENU_OPEN/CLOSE + bool HandleMenuPopup(wxEventType evtType, WXHMENU hMenu); + + // Command part of HandleMenuPopup() and HandleExitMenuLoop(). + bool DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup); + + // Find the menu corresponding to the given handle. + virtual wxMenu* MSWFindMenuFromHMENU(WXHMENU hMenu); +#endif // wxUSE_MENUS + protected: // common part of all ctors void Init(); diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 9f0c365d40..8e9efb300c 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -272,7 +272,6 @@ public: wxWindow *SetTmpDefaultItem(wxWindow *win) { wxWindow *old = GetDefaultItem(); m_winTmpDefault = win; return old; } - // implementation only from now on // ------------------------------- @@ -305,6 +304,13 @@ public: virtual void SetRepresentedFilename(const wxString& WXUNUSED(filename)) { } +#if wxUSE_MENUS || wxUSE_TOOLBAR + // show help text for the currently selected menu or toolbar item + // (typically in the status bar) or hide it and restore the status bar text + // originally shown before the menu was opened if show == false + virtual void DoGiveHelp(const wxString& WXUNUSED(text), bool WXUNUSED(show)) {} +#endif + protected: // the frame client to screen translation should take account of the // toolbar which may shift the origin of the client area diff --git a/samples/menu/menu.cpp b/samples/menu/menu.cpp index e3b11060a2..a99f581954 100644 --- a/samples/menu/menu.cpp +++ b/samples/menu/menu.cpp @@ -88,6 +88,7 @@ protected: void OnClearLog(wxCommandEvent& event); void OnClearLogUpdateUI(wxUpdateUIEvent& event); #endif // USE_LOG_WINDOW + void OnShowDialog(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -138,13 +139,19 @@ protected: void OnMenuOpen(wxMenuEvent& event) { #if USE_LOG_WINDOW - LogMenuOpenOrClose(event, wxT("opened")); event.Skip(); + LogMenuOpenCloseOrHighlight(event, wxT("opened")); event.Skip(); #endif } void OnMenuClose(wxMenuEvent& event) { #if USE_LOG_WINDOW - LogMenuOpenOrClose(event, wxT("closed")); event.Skip(); + LogMenuOpenCloseOrHighlight(event, wxT("closed")); event.Skip(); +#endif + } + void OnMenuHighlight(wxMenuEvent& event) + { +#if USE_LOG_WINDOW + LogMenuOpenCloseOrHighlight(event, wxT("highlighted")); event.Skip(); #endif } @@ -153,7 +160,9 @@ protected: void OnSize(wxSizeEvent& event); private: - void LogMenuOpenOrClose(const wxMenuEvent& event, const wxChar *what); +#if USE_LOG_WINDOW + void LogMenuOpenCloseOrHighlight(const wxMenuEvent& event, const wxChar *what); +#endif void ShowContextMenu(const wxPoint& pos); wxMenu *CreateDummyMenu(wxString *title); @@ -177,6 +186,51 @@ private: DECLARE_EVENT_TABLE() }; +class MyDialog : public wxDialog +{ +public: + MyDialog(wxWindow* parent); + +#if USE_CONTEXT_MENU + void OnContextMenu(wxContextMenuEvent& event); +#else + void OnRightUp(wxMouseEvent& event) + { ShowContextMenu(event.GetPosition()); } +#endif + + void OnMenuOpen(wxMenuEvent& event) + { +#if USE_LOG_WINDOW + LogMenuOpenCloseOrHighlight(event, wxT("opened")); event.Skip(); +#endif + } + void OnMenuClose(wxMenuEvent& event) + { +#if USE_LOG_WINDOW + LogMenuOpenCloseOrHighlight(event, wxT("closed")); event.Skip(); +#endif + } + void OnMenuHighlight(wxMenuEvent& event) + { +#if USE_LOG_WINDOW + LogMenuOpenCloseOrHighlight(event, wxT("highlighted")); event.Skip(); +#endif + } + +private: +#if USE_LOG_WINDOW + void LogMenuOpenCloseOrHighlight(const wxMenuEvent& event, const wxChar *what); +#endif + void ShowContextMenu(const wxPoint& pos); + +#if USE_LOG_WINDOW + // the control used for logging + wxTextCtrl *m_textctrl; +#endif + + DECLARE_EVENT_TABLE() +}; + // A small helper class which intercepts all menu events and logs them class MyEvtHandler : public wxEvtHandler { @@ -206,6 +260,7 @@ enum #if USE_LOG_WINDOW Menu_File_ClearLog = 100, #endif + Menu_File_ShowDialog, Menu_MenuBar_Toggle = 200, Menu_MenuBar_Append, @@ -275,6 +330,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Menu_File_ClearLog, MyFrame::OnClearLog) EVT_UPDATE_UI(Menu_File_ClearLog, MyFrame::OnClearLogUpdateUI) #endif + EVT_MENU(Menu_File_ShowDialog, MyFrame::OnShowDialog) EVT_MENU(Menu_Help_About, MyFrame::OnAbout) @@ -329,10 +385,22 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU_OPEN(MyFrame::OnMenuOpen) EVT_MENU_CLOSE(MyFrame::OnMenuClose) + EVT_MENU_HIGHLIGHT_ALL(MyFrame::OnMenuHighlight) EVT_SIZE(MyFrame::OnSize) END_EVENT_TABLE() +BEGIN_EVENT_TABLE(MyDialog, wxDialog) +#if USE_CONTEXT_MENU + EVT_CONTEXT_MENU(MyDialog::OnContextMenu) +#else + EVT_RIGHT_UP(MyDialog::OnRightUp) +#endif + EVT_MENU_OPEN(MyDialog::OnMenuOpen) + EVT_MENU_CLOSE(MyDialog::OnMenuClose) + EVT_MENU_HIGHLIGHT_ALL(MyDialog::OnMenuHighlight) +END_EVENT_TABLE() + BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler) EVT_MENU(wxID_ANY, MyEvtHandler::OnMenuEvent) END_EVENT_TABLE() @@ -469,6 +537,10 @@ MyFrame::MyFrame() fileMenu->AppendSeparator(); #endif // USE_LOG_WINDOW + fileMenu->Append(Menu_File_ShowDialog, wxT("Show &Dialog\tCtrl-D"), + wxT("Show a dialog")); + fileMenu->AppendSeparator(); + fileMenu->Append(Menu_File_Quit, wxT("E&xit\tAlt-X"), wxT("Quit menu sample")); wxMenu *menubarMenu = new wxMenu; @@ -676,6 +748,12 @@ void MyFrame::OnClearLogUpdateUI(wxUpdateUIEvent& event) #endif // USE_LOG_WINDOW +void MyFrame::OnShowDialog(wxCommandEvent& WXUNUSED(event)) +{ + MyDialog dlg(this); + dlg.ShowModal(); +} + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { (void)wxMessageBox(wxT("wxWidgets menu sample\n(c) 1999-2001 Vadim Zeitlin"), @@ -1122,14 +1200,20 @@ void MyFrame::OnTestRadio(wxCommandEvent& event) } #if USE_LOG_WINDOW -void MyFrame::LogMenuOpenOrClose(const wxMenuEvent& event, const wxChar *what) +void MyFrame::LogMenuOpenCloseOrHighlight(const wxMenuEvent& event, const wxChar *what) { wxString msg; msg << wxT("A ") << ( event.IsPopup() ? wxT("popup ") : wxT("") ) << wxT("menu has been ") - << what - << wxT("."); + << what; + + if ( event.GetEventType() == wxEVT_MENU_HIGHLIGHT ) + { + msg << wxT(" (id=") << event.GetId() << wxT(")"); + } + + msg << wxT("."); wxLogStatus(this, msg.c_str()); } @@ -1189,3 +1273,76 @@ void MyFrame::OnSize(wxSizeEvent& WXUNUSED(event)) #endif // __WXUNIVERSAL__ } +// ---------------------------------------------------------------------------- +// MyDialog +// ---------------------------------------------------------------------------- + +MyDialog::MyDialog(wxWindow* parent) + : wxDialog(parent, wxID_ANY, "Test Dialog") +{ +#if USE_LOG_WINDOW + // create the log text window + m_textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + m_textctrl->SetEditable(false); + + m_textctrl->AppendText(wxT("Dialogs do not have menus, but popup menus should function the same\n\n") + wxT("Right click this text ctrl to test popup menus.\n")); +#endif +#ifdef __POCKETPC__ + EnableContextMenu(); +#endif +} + +#if USE_LOG_WINDOW +void MyDialog::LogMenuOpenCloseOrHighlight(const wxMenuEvent& event, const wxChar *what) +{ + wxString msg; + msg << wxT("A ") + << ( event.IsPopup() ? wxT("popup ") : wxT("") ) + << wxT("menu has been ") + << what; + if ( event.GetEventType() == wxEVT_MENU_HIGHLIGHT ) + { + msg << wxT(" (id=") << event.GetId() << wxT(")"); + } + msg << wxT(".\n"); + + m_textctrl->AppendText(msg); +} +#endif // USE_LOG_WINDOW +#if USE_CONTEXT_MENU +void MyDialog::OnContextMenu(wxContextMenuEvent& event) +{ + wxPoint point = event.GetPosition(); + // If from keyboard + if (point.x == -1 && point.y == -1) { + wxSize size = GetSize(); + point.x = size.x / 2; + point.y = size.y / 2; + } else { + point = ScreenToClient(point); + } + ShowContextMenu(point); +} +#endif + +void MyDialog::ShowContextMenu(const wxPoint& pos) +{ + wxMenu menu; + + menu.Append(Menu_Help_About, wxT("&About")); + menu.Append(Menu_Popup_ToBeDeleted, wxT("To be &deleted")); + menu.AppendCheckItem(Menu_Popup_ToBeChecked, wxT("To be &checked")); + menu.Append(Menu_Popup_ToBeGreyed, wxT("To be &greyed"), + wxT("This menu item should be initially greyed out")); + menu.AppendSeparator(); + menu.Append(Menu_File_Quit, wxT("E&xit")); + + menu.Delete(Menu_Popup_ToBeDeleted); + menu.Check(Menu_Popup_ToBeChecked, true); + menu.Enable(Menu_Popup_ToBeGreyed, false); + + PopupMenu(&menu, pos); +} diff --git a/src/msw/dialog.cpp b/src/msw/dialog.cpp index 8c9b2a8d3e..67144e1bba 100644 --- a/src/msw/dialog.cpp +++ b/src/msw/dialog.cpp @@ -462,7 +462,7 @@ WXLRESULT wxDialog::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPar } if ( !processed ) - rc = wxWindow::MSWWindowProc(message, wParam, lParam); + rc = wxDialogBase::MSWWindowProc(message, wParam, lParam); return rc; } diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index 65b40d01f5..34e00745ec 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -429,6 +429,13 @@ void wxFrame::InternalSetMenuBar() #endif // wxUSE_MENUS_NATIVE +#if wxUSE_MENUS +wxMenu* wxFrame::MSWFindMenuFromHMENU(WXHMENU hMenu) +{ + return GetMenuBar() ? GetMenuBar()->MSWGetMenu(hMenu) : NULL; +} +#endif // wxUSE_MENUS + // Responds to colour changes, and passes event on to children. void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event) { @@ -824,72 +831,6 @@ bool wxFrame::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return wxFrameBase::HandleCommand(id, cmd, control);; } -#if wxUSE_MENUS - -bool -wxFrame::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU WXUNUSED(hMenu)) -{ - // sign extend to int from unsigned short we get from Windows - int item = (signed short)nItem; - - // WM_MENUSELECT is generated for both normal items and menus, including - // the top level menus of the menu bar, which can't be represented using - // any valid identifier in wxMenuEvent so use an otherwise unused value for - // them - if ( flags & (MF_POPUP | MF_SEPARATOR) ) - item = wxID_NONE; - - wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item); - event.SetEventObject(this); - - if ( HandleWindowEvent(event) ) - return true; - - // by default, i.e. if the event wasn't handled above, clear the status bar - // text when an item which can't have any associated help string in wx API - // is selected - if ( item == wxID_NONE ) - DoGiveHelp(wxEmptyString, true); - - return false; -} - -bool -wxFrame::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup) -{ - wxMenuEvent event(evtType, popup ? wxID_ANY : 0, menu); - event.SetEventObject(menu); - - return HandleWindowEvent(event); -} - -bool wxFrame::HandleExitMenuLoop(WXWORD isPopup) -{ - return DoSendMenuOpenCloseEvent(wxEVT_MENU_CLOSE, - isPopup ? wxCurrentPopupMenu : NULL, - isPopup != 0); -} - -bool wxFrame::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu) -{ - bool isPopup = false; - wxMenu* menu = NULL; - if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetHMenu() == hMenu ) - { - menu = wxCurrentPopupMenu; - isPopup = true; - } - else if ( GetMenuBar() ) - { - menu = GetMenuBar()->MSWGetMenu(hMenu); - } - - - return DoSendMenuOpenCloseEvent(evtType, menu, isPopup); -} - -#endif // wxUSE_MENUS - // --------------------------------------------------------------------------- // the window proc for wxFrame // --------------------------------------------------------------------------- @@ -930,36 +871,6 @@ WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPara break; #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) -#if wxUSE_MENUS - case WM_INITMENUPOPUP: - processed = HandleMenuPopup(wxEVT_MENU_OPEN, (WXHMENU)wParam); - break; - - case WM_MENUSELECT: - { - WXWORD item, flags; - WXHMENU hmenu; - UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu); - - processed = HandleMenuSelect(item, flags, hmenu); - } - break; - - case WM_EXITMENULOOP: - // Under Windows 98 and 2000 and later we're going to get - // WM_UNINITMENUPOPUP which will be used to generate this event - // with more information (notably the menu that was closed) so we - // only need this one under old Windows systems where the newer - // event is never sent. - if ( wxGetWinVersion() < wxWinVersion_98 ) - processed = HandleExitMenuLoop(wParam); - break; - - case WM_UNINITMENUPOPUP: - processed = HandleMenuPopup(wxEVT_MENU_CLOSE, (WXHMENU)wParam); - break; -#endif // wxUSE_MENUS - case WM_QUERYDRAGICON: { const wxIcon& icon = GetIcon(); diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 0d1a0735cd..a4610c3c20 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -63,6 +63,15 @@ #define ICON_SMALL 0 #endif +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS || wxUSE_MENUS_NATIVE + extern wxMenu *wxCurrentPopupMenu; +#endif // wxUSE_MENUS || wxUSE_MENUS_NATIVE + + // ---------------------------------------------------------------------------- // stubs for missing functions under MicroWindows // ---------------------------------------------------------------------------- @@ -414,6 +423,38 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX #endif // #ifndef __WXUNIVERSAL__ } break; + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) +#if wxUSE_MENUS + case WM_INITMENUPOPUP: + processed = HandleMenuPopup(wxEVT_MENU_OPEN, (WXHMENU)wParam); + break; + + case WM_MENUSELECT: + { + WXWORD item, flags; + WXHMENU hmenu; + UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu); + + processed = HandleMenuSelect(item, flags, hmenu); + } + break; + + case WM_EXITMENULOOP: + // Under Windows 98 and 2000 and later we're going to get + // WM_UNINITMENUPOPUP which will be used to generate this event + // with more information (notably the menu that was closed) so we + // only need this one under old Windows systems where the newer + // event is never sent. + if ( wxGetWinVersion() < wxWinVersion_98 ) + processed = HandleExitMenuLoop(wParam); + break; + + case WM_UNINITMENUPOPUP: + processed = HandleMenuPopup(wxEVT_MENU_CLOSE, (WXHMENU)wParam); + break; +#endif // wxUSE_MENUS +#endif // !__WXMICROWIN__ } if ( !processed ) @@ -1428,6 +1469,80 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event) } } +#if wxUSE_MENUS + +bool +wxTopLevelWindowMSW::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU WXUNUSED(hMenu)) +{ + // sign extend to int from unsigned short we get from Windows + int item = (signed short)nItem; + + // WM_MENUSELECT is generated for both normal items and menus, including + // the top level menus of the menu bar, which can't be represented using + // any valid identifier in wxMenuEvent so use an otherwise unused value for + // them + if ( flags & (MF_POPUP | MF_SEPARATOR) ) + item = wxID_NONE; + + wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item); + event.SetEventObject(this); + + if ( HandleWindowEvent(event) ) + return true; + + // by default, i.e. if the event wasn't handled above, clear the status bar + // text when an item which can't have any associated help string in wx API + // is selected + if ( item == wxID_NONE ) + DoGiveHelp(wxEmptyString, true); + + return false; +} + +bool +wxTopLevelWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup) +{ + wxMenuEvent event(evtType, popup ? wxID_ANY : 0, menu); + event.SetEventObject(menu); + + return HandleWindowEvent(event); +} + +bool wxTopLevelWindowMSW::HandleExitMenuLoop(WXWORD isPopup) +{ + return DoSendMenuOpenCloseEvent(wxEVT_MENU_CLOSE, + isPopup ? wxCurrentPopupMenu : NULL, + isPopup != 0); +} + +bool wxTopLevelWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu) +{ + bool isPopup = false; + wxMenu* menu = NULL; + if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetHMenu() == hMenu ) + { + menu = wxCurrentPopupMenu; + isPopup = true; + } + else + { + menu = MSWFindMenuFromHMENU(hMenu); + } + + + return DoSendMenuOpenCloseEvent(evtType, menu, isPopup); +} + +wxMenu* wxTopLevelWindowMSW::MSWFindMenuFromHMENU(WXHMENU WXUNUSED(hMenu)) +{ + // We don't have any menus at this level. + return NULL; +} + +#endif // wxUSE_MENUS + + + // the DialogProc for all wxWidgets dialogs LONG APIENTRY _EXPORT wxDlgProc(HWND hDlg,