Use IRichEditOleCallback for wxTextCtrl's context menu.
In wxMSW, use IRichEditOleCallback::GetContextMenu() to provide our default context menu for rich text controls, instead of using EVT_CONTEXT_MENU. The latter completely overrides native control's handling and in particular breaks Windows 8's builtin spellchecking support. Fall back to the previous non-OLE code for older richtext versions. Also make the new MSWCreateContextMenu() method virtual so that the context menu can be customized. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76723 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -170,6 +170,11 @@ public:
|
||||
// EDIT control has one already)
|
||||
void OnContextMenu(wxContextMenuEvent& event);
|
||||
|
||||
// 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.
|
||||
virtual wxMenu *MSWCreateContextMenu();
|
||||
|
||||
// be sure the caret remains invisible if the user
|
||||
// called HideNativeCaret() before
|
||||
void OnSetFocus(wxFocusEvent& event);
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "wx/wxcrtvararg.h"
|
||||
#endif
|
||||
|
||||
#include "wx/scopedptr.h"
|
||||
#include "wx/stack.h"
|
||||
#include "wx/sysopt.h"
|
||||
|
||||
@@ -63,6 +64,8 @@
|
||||
|
||||
#if wxUSE_RICHEDIT
|
||||
#include <richedit.h>
|
||||
#include <richole.h>
|
||||
#include "wx/msw/ole/oleutils.h"
|
||||
#endif // wxUSE_RICHEDIT
|
||||
|
||||
#include "wx/msw/missing.h"
|
||||
@@ -126,6 +129,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
|
||||
@@ -186,10 +254,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)
|
||||
@@ -480,6 +544,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
|
||||
@@ -2278,32 +2353,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
|
||||
@@ -2318,6 +2367,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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@@ -2335,6 +2335,8 @@ bool wxWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)
|
||||
{
|
||||
menu = wxCurrentPopupMenu;
|
||||
isPopup = true;
|
||||
if ( evtType == wxEVT_MENU_CLOSE )
|
||||
wxCurrentPopupMenu = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Reference in New Issue
Block a user