diff --git a/include/wx/msw/textctrl.h b/include/wx/msw/textctrl.h index 1a81e44d71..66950aa494 100644 --- a/include/wx/msw/textctrl.h +++ b/include/wx/msw/textctrl.h @@ -170,6 +170,13 @@ public: // EDIT control has one already) void OnContextMenu(wxContextMenuEvent& event); +#if wxABI_VERSION >= 30002 + // Create context menu for RICHEDIT controls. This may be called once during + // the control's lifetime or every time the menu is shown, depending on + // implementation. + wxMenu *MSWCreateContextMenu(); +#endif + // be sure the caret remains invisible if the user // called HideNativeCaret() before void OnSetFocus(wxFocusEvent& event); diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 473aa0c36e..716dc23cb8 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -40,6 +40,7 @@ #include "wx/wxcrtvararg.h" #endif +#include "wx/scopedptr.h" #include "wx/stack.h" #include "wx/sysopt.h" @@ -68,8 +69,11 @@ // richedit.h at all #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__) #include + #include #endif +#include "wx/msw/ole/oleutils.h" + #endif // wxUSE_RICHEDIT #include "wx/msw/missing.h" @@ -138,6 +142,71 @@ bool wxRichEditModule::ms_inkEditLibLoadAttemped = false; IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule) +#if wxUSE_OLE + +extern wxMenu *wxCurrentPopupMenu; + +class wxTextCtrlOleCallback : public IRichEditOleCallback +{ +public: + wxTextCtrlOleCallback(wxTextCtrl *text) : m_textCtrl(text), m_menu(NULL) {} + ~wxTextCtrlOleCallback() { DeleteContextMenuObject(); } + + STDMETHODIMP ContextSensitiveHelp(BOOL WXUNUSED(enterMode)) { return E_NOTIMPL; } + STDMETHODIMP DeleteObject(LPOLEOBJECT WXUNUSED(oleobj)) { return E_NOTIMPL; } + STDMETHODIMP GetClipboardData(CHARRANGE* WXUNUSED(chrg), DWORD WXUNUSED(reco), LPDATAOBJECT* WXUNUSED(dataobj)) { return E_NOTIMPL; } + STDMETHODIMP GetDragDropEffect(BOOL WXUNUSED(drag), DWORD WXUNUSED(grfKeyState), LPDWORD WXUNUSED(effect)) { return E_NOTIMPL; } + STDMETHODIMP GetInPlaceContext(LPOLEINPLACEFRAME* WXUNUSED(frame), LPOLEINPLACEUIWINDOW* WXUNUSED(doc), LPOLEINPLACEFRAMEINFO WXUNUSED(frameInfo)) { return E_NOTIMPL; } + STDMETHODIMP GetNewStorage(LPSTORAGE *WXUNUSED(stg)) { return E_NOTIMPL; } + STDMETHODIMP QueryAcceptData(LPDATAOBJECT WXUNUSED(dataobj), CLIPFORMAT* WXUNUSED(format), DWORD WXUNUSED(reco), BOOL WXUNUSED(really), HGLOBAL WXUNUSED(hMetaPict)) { return E_NOTIMPL; } + STDMETHODIMP QueryInsertObject(LPCLSID WXUNUSED(clsid), LPSTORAGE WXUNUSED(stg), LONG WXUNUSED(cp)) { return E_NOTIMPL; } + STDMETHODIMP ShowContainerUI(BOOL WXUNUSED(show)) { return E_NOTIMPL; } + + STDMETHODIMP GetContextMenu(WORD WXUNUSED(seltype), LPOLEOBJECT WXUNUSED(oleobj), CHARRANGE* WXUNUSED(chrg), HMENU *menu) + { + // 'menu' will be shown and destroyed by the caller. We need to keep + // its wx counterpart, the wxMenu instance, around until it is + // dismissed, though, so store it in m_menu and destroy sometime later. + DeleteContextMenuObject(); + m_menu = m_textCtrl->MSWCreateContextMenu(); + *menu = m_menu->GetHMenu(); + + // Make wx handle events from the popup menu correctly: + m_menu->SetInvokingWindow(m_textCtrl); + wxCurrentPopupMenu = m_menu; + + return S_OK; + } + + DECLARE_IUNKNOWN_METHODS; + +private: + void DeleteContextMenuObject() + { + if ( m_menu ) + { + m_menu->MSWDetachHMENU(); + if ( wxCurrentPopupMenu == m_menu ) + wxCurrentPopupMenu = NULL; + wxDELETE(m_menu); + } + } + + wxTextCtrl *m_textCtrl; + wxMenu *m_menu; + + wxDECLARE_NO_COPY_CLASS(wxTextCtrlOleCallback); +}; + +BEGIN_IID_TABLE(wxTextCtrlOleCallback) + ADD_IID(Unknown) + ADD_IID(RichEditOleCallback) +END_IID_TABLE; + +IMPLEMENT_IUNKNOWN_METHODS(wxTextCtrlOleCallback) + +#endif // wxUSE_OLE + #endif // wxUSE_RICHEDIT // a small class used to set m_updatesCount to 0 (to filter duplicate events if @@ -198,10 +267,6 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) EVT_KEY_DOWN(wxTextCtrl::OnKeyDown) EVT_DROP_FILES(wxTextCtrl::OnDropFiles) -#if wxUSE_RICHEDIT - EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu) -#endif - EVT_MENU(wxID_CUT, wxTextCtrl::OnCut) EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy) EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste) @@ -492,6 +557,17 @@ bool wxTextCtrl::MSWCreateText(const wxString& value, } ::SendMessage(GetHwnd(), EM_SETEVENTMASK, 0, mask); + + bool contextMenuConnected = false; +#if wxUSE_OLE + if ( m_verRichEdit >= 4 ) + { + wxTextCtrlOleCallback *cb = new wxTextCtrlOleCallback(this); + contextMenuConnected = ::SendMessage(GetHwnd(), EM_SETOLECALLBACK, 0, (LPARAM)cb) != 0; + } +#endif + if ( !contextMenuConnected ) + Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(wxTextCtrl::OnContextMenu)); } else #endif // wxUSE_RICHEDIT @@ -2323,32 +2399,6 @@ void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event) event.Enable( !IsEmpty() ); } -void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event) -{ -#if wxUSE_RICHEDIT - if (IsRich()) - { - if (!m_privateContextMenu) - { - m_privateContextMenu = new wxMenu; - m_privateContextMenu->Append(wxID_UNDO, _("&Undo")); - m_privateContextMenu->Append(wxID_REDO, _("&Redo")); - m_privateContextMenu->AppendSeparator(); - m_privateContextMenu->Append(wxID_CUT, _("Cu&t")); - m_privateContextMenu->Append(wxID_COPY, _("&Copy")); - m_privateContextMenu->Append(wxID_PASTE, _("&Paste")); - m_privateContextMenu->Append(wxID_CLEAR, _("&Delete")); - m_privateContextMenu->AppendSeparator(); - m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All")); - } - PopupMenu(m_privateContextMenu); - return; - } - else -#endif - event.Skip(); -} - void wxTextCtrl::OnSetFocus(wxFocusEvent& event) { // be sure the caret remains invisible if the user had hidden it @@ -2363,6 +2413,34 @@ void wxTextCtrl::OnSetFocus(wxFocusEvent& event) // the rest of the file only deals with the rich edit controls #if wxUSE_RICHEDIT +void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event) +{ + if (IsRich()) + { + if (!m_privateContextMenu) + m_privateContextMenu = MSWCreateContextMenu(); + PopupMenu(m_privateContextMenu); + return; + } + else + event.Skip(); +} + +wxMenu *wxTextCtrl::MSWCreateContextMenu() +{ + wxMenu *m = new wxMenu; + m->Append(wxID_UNDO, _("&Undo")); + m->Append(wxID_REDO, _("&Redo")); + m->AppendSeparator(); + m->Append(wxID_CUT, _("Cu&t")); + m->Append(wxID_COPY, _("&Copy")); + m->Append(wxID_PASTE, _("&Paste")); + m->Append(wxID_CLEAR, _("&Delete")); + m->AppendSeparator(); + m->Append(wxID_SELECTALL, _("Select &All")); + return m; +} + // ---------------------------------------------------------------------------- // EN_LINK processing // ---------------------------------------------------------------------------- diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 37b3a3d0a7..3fe061a126 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -1572,6 +1572,8 @@ bool wxTopLevelWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu) { menu = wxCurrentPopupMenu; isPopup = true; + if ( evtType == wxEVT_MENU_CLOSE ) + wxCurrentPopupMenu = NULL; } else {