]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/textctrl.cpp
don't update m_iconized in IsIconized(), this can break wxFrame::HandleSize() logic...
[wxWidgets.git] / src / msw / textctrl.cpp
index 7151acb27dec4dc928ba40675328e169c6a17e63..180b5bbdd6f75486a78b8406dd20e6190fe15a9f 100644 (file)
 // declarations
 // ============================================================================
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "textctrl.h"
-#endif
-
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
@@ -43,6 +39,7 @@
 #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__)
@@ -98,15 +99,30 @@ public:
     // 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
@@ -256,6 +272,10 @@ void wxTextCtrl::Init()
     m_verRichEdit = 0;
 #endif // wxUSE_RICHEDIT
 
+#if wxUSE_INKEDIT && wxUSE_RICHEDIT
+    m_isInkEdit = 0;
+#endif
+
     m_privateContextMenu = NULL;
     m_updatesCount = -1;
     m_isNativeCaretShown = true;
@@ -325,46 +345,76 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
         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) )
-            {
-                windowClass = _T("RichEdit20")
+        }
+#endif
+
+        if (!IsInkEdit())
+        {
+            if ( m_verRichEdit == 2 )
+            {            
+                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 ( wxRichEditModule::Load(wxRichEditModule::Version_1) )
+                {
+                    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
 
-                wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
+                    if ( !s_errorGiven )
+                    {
+                        wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
 
-                s_errorGiven = true;
+                        s_errorGiven = true;
+                    }
 
-                m_verRichEdit = 0;
+                    m_verRichEdit = 0;
+                }
             }
-        }
+        } // !useInkEdit 
     }
 #endif // wxUSE_RICHEDIT
 
@@ -383,13 +433,25 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
         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
@@ -810,7 +872,10 @@ wxTextCtrl::StreamIn(const wxString& value,
                   (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 )
     {
@@ -962,7 +1027,8 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
         UpdatesCountFilter ucf(m_updatesCount);
 
         ::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
-                      0, (LPARAM)valueDos.c_str());
+                      // EM_REPLACESEL takes 1 to indicate the operation should be redoable
+                      selectionOnly ? 1 : 0, (LPARAM)valueDos.c_str());
 
         if ( !ucf.GotUpdate() )
         {
@@ -1258,10 +1324,14 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
         // 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);
             }
@@ -1277,6 +1347,8 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
         {
             ::SendMessage(GetHwnd(), EM_SETOPTIONS,
                           ECOOP_AND, ~ECO_NOHIDESEL);
+            if ( style != ::GetWindowLong(GetHwnd(), GWL_STYLE) )
+                ::SetWindowLong(GetHwnd(), GWL_STYLE, style);
         }
 #endif // wxUSE_RICHEDIT
     }
@@ -1560,11 +1632,22 @@ wxString wxTextCtrl::GetLineText(long lineNo) const
 void wxTextCtrl::SetMaxLength(unsigned long len)
 {
 #if wxUSE_RICHEDIT
-    if (IsRich())
-        ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, (LPARAM) (DWORD) len);
+    if ( IsRich() )
+    {
+        ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, len ? len : 0x7fffffff);
+    }
     else
-#endif
-    ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+#endif // wxUSE_RICHEDIT
+    {
+        if ( len >= 0xffff )
+        {
+            // this will set it to a platform-dependent maximum (much more
+            // than 64Kb under NT)
+            len = 0;
+        }
+
+        ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -1762,6 +1845,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
                 // Insert tab since calling the default Windows handler
                 // doesn't seem to do it
                 WriteText(wxT("\t"));
+                return;
             }
             break;
     }
@@ -1894,48 +1978,36 @@ WXHBRUSH wxTextCtrl::MSWControlColor(WXHDC hDC, WXHWND hWnd)
     return wxTextCtrlBase::MSWControlColor(hDC, hWnd);
 }
 
-bool wxTextCtrl::AdjustSpaceLimit()
+bool wxTextCtrl::HasSpaceLimit(unsigned int *len) const
 {
-    unsigned int limit = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0);
-
     // HACK: we try to automatically extend the limit for the amount of text
     //       to allow (interactively) entering more than 64Kb of text under
     //       Win9x but we shouldn't reset the text limit which was previously
     //       set explicitly with SetMaxLength()
     //
-    //       we could solve this by storing the limit we set in wxTextCtrl but
-    //       to save space we prefer to simply test here the actual limit
-    //       value: we consider that SetMaxLength() can only be called for
-    //       values < 32Kb
-    if ( limit < 0x8000 )
-    {
-        // we've got more text than limit set by SetMaxLength()
+    //       Unfortunately there is no EM_GETLIMITTEXTSETBYUSER and so we don't
+    //       know the limit we set (if any). We could solve this by storing the
+    //       limit we set in wxTextCtrl but to save space we prefer to simply
+    //       test here the actual limit value: we consider that SetMaxLength()
+    //       can only be called for small values while EN_MAXTEXT is only sent
+    //       for large values (in practice the default limit seems to be 30000
+    //       but make it smaller just to be on the safe side)
+    *len = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0);
+    return *len < 10001;
+
+}
+
+bool wxTextCtrl::AdjustSpaceLimit()
+{
+    unsigned int limit;
+    if ( HasSpaceLimit(&limit) )
         return false;
-    }
 
     unsigned int len = ::GetWindowTextLength(GetHwnd());
     if ( len >= limit )
     {
-        limit = len + 0x8000;    // 32Kb
-
-#if wxUSE_RICHEDIT
-        if ( IsRich() )
-        {
-            // as a nice side effect, this also allows passing limit > 64Kb
-            ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, limit);
-        }
-        else
-#endif // wxUSE_RICHEDIT
-        {
-            if ( limit > 0xffff )
-            {
-                // this will set it to a platform-dependent maximum (much more
-                // than 64Kb under NT)
-                limit = 0;
-            }
-
-            ::SendMessage(GetHwnd(), EM_LIMITTEXT, limit, 0);
-        }
+        // increment in 32Kb chunks
+        SetMaxLength(len + 0x8000);
     }
 
     // we changed the limit
@@ -1960,7 +2032,7 @@ wxSize wxTextCtrl::DoGetBestSize() const
     int hText = cy;
     if ( m_windowStyle & wxTE_MULTILINE )
     {
-        hText *= wxMax(GetNumberOfLines(), 5);
+        hText *= wxMax(wxMin(GetNumberOfLines(), 10), 2);
     }
     //else: for single line control everything is ok
 
@@ -2521,7 +2593,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
 
     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
@@ -2651,6 +2723,10 @@ void wxRichEditModule::OnExit()
             ms_hRichEdit[i] = NULL;
         }
     }
+#if wxUSE_INKEDIT
+    if (ms_inkEditLib.IsLoaded())
+        ms_inkEditLib.Unload();
+#endif
 }
 
 /* static */
@@ -2690,6 +2766,23 @@ bool wxRichEditModule::Load(Version version)
     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__)