/////////////////////////////////////////////////////////////////////////////
-// Name: msw/textctrl.cpp
+// Name: src/msw/textctrl.cpp
// Purpose: wxTextCtrl
// Author: Julian Smart
// Modified by:
#endif
#include "wx/module.h"
+#include "wx/sysopt.h"
#if wxUSE_CLIPBOARD
#include "wx/clipbrd.h"
#if wxUSE_RICHEDIT
+#if wxUSE_INKEDIT
+#include "wx/dynlib.h"
+#endif
+
// old mingw32 has richedit stuff directly in windows.h and doesn't have
// richedit.h at all
#if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
// load the richedit DLL for the specified version of rich edit
static bool Load(Version version);
+#if wxUSE_INKEDIT
+ // load the InkEdit library
+ static bool LoadInkEdit();
+#endif
+
private:
// the handles to richedit 1.0 and 2.0 (or 3.0) DLLs
static HINSTANCE ms_hRichEdit[Version_Max];
+#if wxUSE_INKEDIT
+ static wxDynamicLibrary ms_inkEditLib;
+ static bool ms_inkEditLibLoadAttemped;
+#endif
+
DECLARE_DYNAMIC_CLASS(wxRichEditModule)
};
HINSTANCE wxRichEditModule::ms_hRichEdit[Version_Max] = { NULL, NULL, NULL };
+#if wxUSE_INKEDIT
+wxDynamicLibrary wxRichEditModule::ms_inkEditLib;
+bool wxRichEditModule::ms_inkEditLibLoadAttemped = false;
+#endif
+
IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
#endif // wxUSE_RICHEDIT
wxFLAGS_MEMBER(wxTE_CENTRE)
wxFLAGS_MEMBER(wxTE_RIGHT)
wxFLAGS_MEMBER(wxTE_DONTWRAP)
- wxFLAGS_MEMBER(wxTE_LINEWRAP)
+ wxFLAGS_MEMBER(wxTE_CHARWRAP)
wxFLAGS_MEMBER(wxTE_WORDWRAP)
wxEND_FLAGS( wxTextCtrlStyle )
wxCONSTRUCTOR_6( wxTextCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , Value , wxPoint , Position , wxSize , Size , long , WindowStyle)
#else
-IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase)
#endif
-BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
EVT_CHAR(wxTextCtrl::OnChar)
EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
EVT_SET_FOCUS(wxTextCtrl::OnSetFocus)
END_EVENT_TABLE()
+// ----------------------------------------------------------------------------
+// function prototypes
+// ----------------------------------------------------------------------------
+
+LRESULT APIENTRY _EXPORT wxTextCtrlWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+// ---------------------------------------------------------------------------
+// global vars
+// ---------------------------------------------------------------------------
+
+// the pointer to standard text control wnd proc
+static WNDPROC gs_wndprocEdit = (WNDPROC)NULL;
+
// ============================================================================
// implementation
// ============================================================================
+// ----------------------------------------------------------------------------
+// wnd proc for subclassed edit control
+// ----------------------------------------------------------------------------
+
+LRESULT APIENTRY _EXPORT wxTextCtrlWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
+
+ switch ( message )
+ {
+ case WM_CUT:
+ case WM_COPY:
+ case WM_PASTE:
+ if( win->HandleClipboardEvent( message ) )
+ return 0;
+ break;
+ }
+ return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam);
+}
+
// ----------------------------------------------------------------------------
// creation
// ----------------------------------------------------------------------------
m_verRichEdit = 0;
#endif // wxUSE_RICHEDIT
+#if wxUSE_INKEDIT && wxUSE_RICHEDIT
+ m_isInkEdit = 0;
+#endif
+
m_privateContextMenu = NULL;
m_updatesCount = -1;
m_isNativeCaretShown = true;
m_verRichEdit = m_windowStyle & wxTE_RICH2 ? 2 : 1;
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
- if ( m_verRichEdit == 2 )
+#if wxUSE_INKEDIT
+ // First test if we can load an ink edit control. Normally, all edit
+ // controls will be made ink edit controls if a tablet environment is
+ // found (or if msw.inkedit != 0 and the InkEd.dll is present).
+ // However, an application can veto ink edit controls by either specifying
+ // msw.inkedit = 0 or by removing wxTE_RICH[2] from the style.
+ //
+ if ((wxSystemSettings::HasFeature(wxSYS_TABLET_PRESENT) || wxSystemOptions::GetOptionInt(wxT("msw.inkedit")) != 0) &&
+ !(wxSystemOptions::HasOption(wxT("msw.inkedit")) && wxSystemOptions::GetOptionInt(wxT("msw.inkedit")) == 0))
{
- if ( wxRichEditModule::Load(wxRichEditModule::Version_41) )
+ if (wxRichEditModule::LoadInkEdit())
{
- // yes, class name for version 4.1 really is 5.0
- windowClass = _T("RICHEDIT50W");
+ windowClass = INKEDIT_CLASS;
+
+#if wxUSE_INKEDIT && wxUSE_RICHEDIT
+ m_isInkEdit = 1;
+#endif
+
+ // Fake rich text version for other calls
+ m_verRichEdit = 2;
}
- else if ( wxRichEditModule::Load(wxRichEditModule::Version_2or3) )
+ }
+#endif
+
+ if (!IsInkEdit())
+ {
+ if ( m_verRichEdit == 2 )
{
- windowClass = _T("RichEdit20")
+ if ( wxRichEditModule::Load(wxRichEditModule::Version_41) )
+ {
+ // yes, class name for version 4.1 really is 5.0
+ windowClass = _T("RICHEDIT50W");
+ }
+ else if ( wxRichEditModule::Load(wxRichEditModule::Version_2or3) )
+ {
+ windowClass = _T("RichEdit20")
#if wxUSE_UNICODE
- _T("W");
+ _T("W");
#else // ANSI
- _T("A");
+ _T("A");
#endif // Unicode/ANSI
+ }
+ else // failed to load msftedit.dll and riched20.dll
+ {
+ m_verRichEdit = 1;
+ }
}
- else // failed to load msftedit.dll and riched20.dll
- {
- m_verRichEdit = 1;
- }
- }
- if ( m_verRichEdit == 1 )
- {
- if ( wxRichEditModule::Load(wxRichEditModule::Version_1) )
- {
- windowClass = _T("RICHEDIT");
- }
- else // failed to load any richedit control DLL
+ if ( m_verRichEdit == 1 )
{
- // only give the error msg once if the DLL can't be loaded
- static bool s_errorGiven = false; // MT ok as only used by GUI
-
- if ( !s_errorGiven )
+ if ( wxRichEditModule::Load(wxRichEditModule::Version_1) )
{
- wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
-
- s_errorGiven = true;
+ windowClass = _T("RICHEDIT");
}
+ else // failed to load any richedit control DLL
+ {
+ // only give the error msg once if the DLL can't be loaded
+ static bool s_errorGiven = false; // MT ok as only used by GUI
+
+ if ( !s_errorGiven )
+ {
+ wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
+
+ s_errorGiven = true;
+ }
- m_verRichEdit = 0;
+ m_verRichEdit = 0;
+ }
}
- }
+ } // !useInkEdit
}
#endif // wxUSE_RICHEDIT
return false;
#if wxUSE_RICHEDIT
- if ( IsRich() )
+ if (IsRich())
{
+#if wxUSE_INKEDIT
+ if (IsInkEdit())
+ {
+ // Pass IEM_InsertText (0) as wParam, in order to have the ink always
+ // converted to text.
+ ::SendMessage(GetHwnd(), EM_SETINKINSERTMODE, 0, 0);
+
+ // Make sure the mouse can be used for input
+ ::SendMessage(GetHwnd(), EM_SETUSEMOUSEFORINPUT, 1, 0);
+ }
+#endif
+
// enable the events we're interested in: we want to get EN_CHANGE as
// for the normal controls
LPARAM mask = ENM_CHANGE;
- if ( GetRichVersion() == 1 )
+ if (GetRichVersion() == 1 && !IsInkEdit())
{
// we also need EN_MSGFILTER for richedit 1.0 for the reasons
// explained in its handler
}
#endif // wxUSE_RICHEDIT
+ gs_wndprocEdit = wxSetWindowProc((HWND)GetHwnd(),
+ wxTextCtrlWndProc);
+
return true;
}
{
DoWriteText(value, false /* not selection only */);
+ // mark the control as being not dirty - we changed its text, not the
+ // user
+ DiscardEdits();
+
// for compatibility, don't move the cursor when doing SetValue()
SetInsertionPoint(0);
}
else // same text
{
+ // still reset the modified flag even if the value didn't really change
+ // because now it comes from the program and not the user (and do it
+ // before generating the event so that the event handler could get the
+ // expected value from IsModified())
+ DiscardEdits();
+
// still send an event for consistency
SendUpdateEvent();
}
-
- // we should reset the modified flag even if the value didn't really change
-
- // mark the control as being not dirty - we changed its text, not the
- // user
- DiscardEdits();
}
#if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU)
(selectionOnly ? SFF_SELECTION : 0),
(LPARAM)&eds);
- wxASSERT_MSG( ucf.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") );
+ // It's okay for EN_UPDATE to not be sent if the selection is empty and
+ // the text is empty, otherwise warn the programmer about it.
+ wxASSERT_MSG( ucf.GotUpdate() || ( !HasSelection() && value.empty() ),
+ _T("EM_STREAMIN didn't send EN_UPDATE?") );
if ( eds.dwError )
{
void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
{
- if ( value.empty() )
- return;
-
wxString valueDos;
if ( m_windowStyle & wxTE_MULTILINE )
valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
// ES_DISABLENOSCROLL
//
// this is very ugly but I don't see any other way to make this work
+ long style = 0;
if ( GetRichVersion() > 1 )
{
if ( !HasFlag(wxTE_NOHIDESEL) )
{
+ // setting ECO_NOHIDESEL also sets WS_VISIBLE and possibly
+ // others, remember the style so we can reset it later if needed
+ style = ::GetWindowLong(GetHwnd(), GWL_STYLE);
::SendMessage(GetHwnd(), EM_SETOPTIONS,
ECOOP_OR, ECO_NOHIDESEL);
}
{
::SendMessage(GetHwnd(), EM_SETOPTIONS,
ECOOP_AND, ~ECO_NOHIDESEL);
+ if ( style != ::GetWindowLong(GetHwnd(), GWL_STYLE) )
+ ::SetWindowLong(GetHwnd(), GWL_STYLE, style);
}
#endif // wxUSE_RICHEDIT
}
switch ( event.GetKeyCode() )
{
case WXK_RETURN:
- if ( !HasFlag(wxTE_MULTILINE) )
{
wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
InitCommandEvent(event);
event.SetString(GetValue());
if ( GetEventHandler()->ProcessEvent(event) )
+ if ( !HasFlag(wxTE_MULTILINE) )
return;
+ //else: multiline controls need Enter for themselves
}
- //else: multiline controls need Enter for themselves
-
break;
case WXK_TAB:
int hText = cy;
if ( m_windowStyle & wxTE_MULTILINE )
{
- hText *= wxMax(wxMin(GetNumberOfLines(), 10), 2);
+ hText *= wxMax(wxMin(GetNumberOfLines(), 10), 2);
}
//else: for single line control everything is ok
if ( changeSel )
{
- DoSetSelection(position, position, false /* don't scroll caret into view */);
+ DoSetSelection(position, position+1, false /* don't scroll caret into view */);
}
// get the selection formatting
ms_hRichEdit[i] = NULL;
}
}
+#if wxUSE_INKEDIT
+ if (ms_inkEditLib.IsLoaded())
+ ms_inkEditLib.Unload();
+#endif
}
/* static */
return true;
}
+#if wxUSE_INKEDIT
+// load the InkEdit library
+bool wxRichEditModule::LoadInkEdit()
+{
+ static wxDynamicLibrary ms_inkEditLib;
+ static bool ms_inkEditLibLoadAttemped;
+ if (ms_inkEditLibLoadAttemped)
+ ms_inkEditLib.IsLoaded();
+
+ ms_inkEditLibLoadAttemped = true;
+
+ wxLogNull logNull;
+ return ms_inkEditLib.Load(wxT("inked"));
+}
+#endif
+
+
#endif // wxUSE_RICHEDIT
#endif // wxUSE_TEXTCTRL && !(__SMARTPHONE__ && __WXWINCE__)