]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/textctrl.cpp
do use the font in DoGetTextExtent()
[wxWidgets.git] / src / msw / textctrl.cpp
index 15311c9683ddc2775dc65738bb44360c7a11230f..04cc73d26a5f82ecc0ce76137e22243c4da43f75 100644 (file)
     #include "wx/app.h"
     #include "wx/menu.h"
     #include "wx/math.h"
+    #include "wx/module.h"
+    #include "wx/wxcrtvararg.h"
 #endif
 
-#include "wx/module.h"
 #include "wx/sysopt.h"
 
 #if wxUSE_CLIPBOARD
@@ -50,7 +51,8 @@
 #include <windowsx.h>
 
 #include "wx/msw/private.h"
-#include "wx/msw/wrapshl.h"
+#include "wx/msw/winundef.h"
+#include "wx/msw/mslu.h"
 
 #include <string.h>
 #include <stdlib.h>
     #include <richedit.h>
 #endif
 
-#include "wx/msw/missing.h"
-
 #endif // wxUSE_RICHEDIT
 
+#include "wx/msw/missing.h"
+
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -135,9 +137,13 @@ public:
     UpdatesCountFilter(int& count)
         : m_count(count)
     {
-        wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") );
+        wxASSERT_MSG( m_count == -1 || m_count == -2,
+                      _T("wrong initial m_updatesCount value") );
 
-        m_count = 0;
+        if (m_count != -2)
+            m_count = 0;
+        //else: we don't want to count how many update events we get as we're going
+        //      to ignore all of them
     }
 
     ~UpdatesCountFilter()
@@ -258,49 +264,10 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
     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
 // ----------------------------------------------------------------------------
@@ -325,7 +292,8 @@ wxTextCtrl::~wxTextCtrl()
     delete m_privateContextMenu;
 }
 
-bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
+bool wxTextCtrl::Create(wxWindow *parent,
+                        wxWindowID id,
                         const wxString& value,
                         const wxPoint& pos,
                         const wxSize& size,
@@ -342,6 +310,16 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
     if ( !CreateControl(parent, id, pos, size, style, validator, name) )
         return false;
 
+    if ( !MSWCreateText(value, pos, size) )
+        return false;
+
+    return true;
+}
+
+bool wxTextCtrl::MSWCreateText(const wxString& value,
+                               const wxPoint& pos,
+                               const wxSize& size)
+{
     // translate wxWin style flags to MSW ones
     WXDWORD msStyle = MSWGetCreateWindowFlags();
 
@@ -350,7 +328,7 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
 
 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
     // A control that capitalizes the first letter
-    if (style & wxTE_CAPITALIZE)
+    if ( HasFlag(wxTE_CAPITALIZE) )
         windowClass = wxT("CAPEDIT");
 #endif
 
@@ -505,7 +483,7 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
            // Windows XP, so if we're sure it works correctly under other
            // systems we could do this only for XP
            SetSize(-1, 1); // 1 is small enough to force vert scrollbar
-           SetSize(size);
+           SetInitialSize(size);
         }
         else if ( m_windowStyle & wxTE_AUTO_URL )
         {
@@ -518,12 +496,6 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
     }
 #endif // wxUSE_RICHEDIT
 
-    if ( style & wxTE_FILENAME )
-        wxEnableFileNameAutoComplete(GetHwnd());
-
-    gs_wndprocEdit = wxSetWindowProc((HWND)GetHwnd(),
-                                     wxTextCtrlWndProc);
-
     return true;
 }
 
@@ -576,9 +548,6 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
     // styles which we alaways add by default
     if ( style & wxTE_MULTILINE )
     {
-        wxASSERT_MSG( !(style & wxTE_PROCESS_ENTER),
-                      wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
-
         msStyle |= ES_MULTILINE | ES_WANTRETURN;
         if ( !(style & wxTE_NO_VSCROLL) )
         {
@@ -640,6 +609,62 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
 
 void wxTextCtrl::SetWindowStyleFlag(long style)
 {
+    // changing the alignment of the control dynamically works under Win2003
+    // (but not older Windows version: it seems to work under some versions of
+    // XP but not other ones, and we have no way to determine it so be
+    // conservative here) and only for plain EDIT controls (not RICH ones) and
+    // we have to recreate the control to make it always work
+    if ( IsRich() || wxGetWinVersion() < wxWinVersion_2003 )
+    {
+        const long alignMask = wxTE_LEFT | wxTE_CENTRE | wxTE_RIGHT;
+        if ( (style & alignMask) != (GetWindowStyle() & alignMask) )
+        {
+            const wxString value = GetValue();
+            const wxPoint pos = GetPosition();
+            const wxSize size = GetSize();
+
+            // delete the old window
+            HWND hwnd = GetHwnd();
+            DissociateHandle();
+            ::DestroyWindow(hwnd);
+
+            // create the new one with the updated flags
+            m_windowStyle = style;
+            MSWCreateText(value, pos, size);
+
+            // and make sure it has the same attributes as before
+            if ( m_hasFont )
+            {
+                // calling SetFont(m_font) would do nothing as the code would
+                // notice that the font didn't change, so force it to believe
+                // that it did
+                wxFont font = m_font;
+                m_font = wxNullFont;
+                SetFont(font);
+            }
+
+            if ( m_hasFgCol )
+            {
+                wxColour colFg = m_foregroundColour;
+                m_foregroundColour = wxNullColour;
+                SetForegroundColour(colFg);
+            }
+
+            if ( m_hasBgCol )
+            {
+                wxColour colBg = m_backgroundColour;
+                m_backgroundColour = wxNullColour;
+                SetBackgroundColour(colBg);
+            }
+
+            // note that text styles are lost but this is probably not a big
+            // problem: if you use styles, you probably don't use nor change
+            // alignment flags anyhow
+
+            return;
+        }
+    }
+
 #if wxUSE_RICHEDIT
     // we have to deal with some styles separately because they can't be
     // changed by simply calling SetWindowLong(GWL_STYLE) but can be changed
@@ -661,6 +686,15 @@ void wxTextCtrl::SetWindowStyleFlag(long style)
 // set/get the controls text
 // ----------------------------------------------------------------------------
 
+bool wxTextCtrl::IsEmpty() const
+{
+    // this is an optimization for multiline controls containing a lot of text
+    if ( IsMultiLine() && GetNumberOfLines() != 1 )
+        return false;
+
+    return wxTextCtrlBase::IsEmpty();
+}
+
 wxString wxTextCtrl::GetValue() const
 {
     // range 0..-1 is special for GetRange() and means to retrieve all text
@@ -784,7 +818,7 @@ wxString wxTextCtrl::GetRange(long from, long to) const
     return str;
 }
 
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::DoSetValue(const wxString& value, int flags)
 {
     // if the text is long enough, it's faster to just set it instead of first
     // comparing it with the old one (chances are that it will be different
@@ -792,7 +826,7 @@ void wxTextCtrl::SetValue(const wxString& value)
     // edit controls mostly)
     if ( (value.length() > 0x400) || (value != GetValue()) )
     {
-        DoWriteText(value, false /* not selection only */);
+        DoWriteText(value, flags /* doesn't include SelectionOnly here */);
 
         // mark the control as being not dirty - we changed its text, not the
         // user
@@ -810,7 +844,8 @@ void wxTextCtrl::SetValue(const wxString& value)
         DiscardEdits();
 
         // still send an event for consistency
-        SendUpdateEvent();
+        if (flags & SetValue_SendEvent)
+            SendUpdateEvent();
     }
 }
 
@@ -1008,8 +1043,9 @@ void wxTextCtrl::WriteText(const wxString& value)
     DoWriteText(value);
 }
 
-void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
+void wxTextCtrl::DoWriteText(const wxString& value, int flags)
 {
+    bool selectionOnly = (flags & SetValue_SelectionOnly) != 0;
     wxString valueDos;
     if ( m_windowStyle & wxTE_MULTILINE )
         valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
@@ -1073,13 +1109,16 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
         // we generate exactly one of them by ignoring all but the first one in
         // SendUpdateEvent() and generating one ourselves if we hadn't got any
         // notifications from Windows
+        if ( !(flags & SetValue_SendEvent) )
+            m_updatesCount = -2;        // suppress any update event
+
         UpdatesCountFilter ucf(m_updatesCount);
 
         ::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
                       // EM_REPLACESEL takes 1 to indicate the operation should be redoable
-                      selectionOnly ? 1 : 0, (LPARAM)valueDos.c_str());
+                      selectionOnly ? 1 : 0, (LPARAM)valueDos.wx_str());
 
-        if ( !ucf.GotUpdate() )
+        if ( !ucf.GotUpdate() && (flags & SetValue_SendEvent) )
         {
             SendUpdateEvent();
         }
@@ -1233,7 +1272,8 @@ void wxTextCtrl::SetInsertionPointEnd()
     // if it doesn't actually move the caret anywhere and so the simple fact of
     // doing it results in horrible flicker when appending big amounts of text
     // to the control in a few chunks (see DoAddText() test in the text sample)
-    if ( GetInsertionPoint() == GetLastPosition() )
+    const wxTextPos lastPosition = GetLastPosition();
+    if ( GetInsertionPoint() == lastPosition )
     {
         return;
     }
@@ -1249,7 +1289,7 @@ void wxTextCtrl::SetInsertionPointEnd()
     else // !RichEdit 1.0
 #endif // wxUSE_RICHEDIT
     {
-        pos = GetLastPosition();
+        pos = lastPosition;
     }
 
     SetInsertionPoint(pos);
@@ -1407,9 +1447,9 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
 // Working with files
 // ----------------------------------------------------------------------------
 
-bool wxTextCtrl::LoadFile(const wxString& file)
+bool wxTextCtrl::DoLoadFile(const wxString& file, int fileType)
 {
-    if ( wxTextCtrlBase::LoadFile(file) )
+    if ( wxTextCtrlBase::DoLoadFile(file, fileType) )
     {
         // update the size limit if needed
         AdjustSpaceLimit();
@@ -1429,7 +1469,7 @@ void wxTextCtrl::Replace(long from, long to, const wxString& value)
     // Set selection and remove it
     DoSetSelection(from, to, false /* don't scroll caret into view */);
 
-    DoWriteText(value, true /* selection only */);
+    DoWriteText(value);
 }
 
 void wxTextCtrl::Remove(long from, long to)
@@ -1784,18 +1824,17 @@ void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
 // kbd input processing
 // ----------------------------------------------------------------------------
 
-bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* pMsg)
+bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* msg)
 {
-    MSG *msg = (MSG *)pMsg;
-
     // check for our special keys here: if we don't do it and the parent frame
     // uses them as accelerators, they wouldn't work at all, so we disable
     // usual preprocessing for them
     if ( msg->message == WM_KEYDOWN )
     {
-        WORD vkey = (WORD) msg->wParam;
-        if ( (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
+        const WPARAM vkey = msg->wParam;
+        if ( HIWORD(msg->lParam) & KF_ALTDOWN )
         {
+            // Alt-Backspace is accelerator for "Undo"
             if ( vkey == VK_BACK )
                 return false;
         }
@@ -1813,6 +1852,9 @@ bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* pMsg)
                     // fall through
 
                 case 0:
+                    if ( IsMultiLine() && vkey == VK_RETURN )
+                        return false;
+                    // fall through
                 case 2:
                     break;
 
@@ -1841,7 +1883,7 @@ bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* pMsg)
         }
     }
 
-    return wxControl::MSWShouldPreProcessMessage(pMsg);
+    return wxControl::MSWShouldPreProcessMessage(msg);
 }
 
 void wxTextCtrl::OnChar(wxKeyEvent& event)
@@ -1906,41 +1948,53 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
 {
     WXLRESULT lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
 
-    if ( nMsg == WM_GETDLGCODE )
+    switch ( nMsg )
     {
-        // we always want the chars and the arrows: the arrows for navigation
-        // and the chars because we want Ctrl-C to work even in a read only
-        // control
-        long lDlgCode = DLGC_WANTCHARS | DLGC_WANTARROWS;
+        case WM_GETDLGCODE:
+            {
+                // we always want the chars and the arrows: the arrows for
+                // navigation and the chars because we want Ctrl-C to work even
+                // in a read only control
+                long lDlgCode = DLGC_WANTCHARS | DLGC_WANTARROWS;
 
-        if ( IsEditable() )
-        {
-            // we may have several different cases:
-            // 1. normal case: both TAB and ENTER are used for dlg navigation
-            // 2. ctrl which wants TAB for itself: ENTER is used to pass to the
-            //    next control in the dialog
-            // 3. ctrl which wants ENTER for itself: TAB is used for dialog
-            //    navigation
-            // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go
-            //    to the next control
-
-            // the multiline edit control should always get <Return> for itself
-            if ( HasFlag(wxTE_PROCESS_ENTER) || HasFlag(wxTE_MULTILINE) )
-                lDlgCode |= DLGC_WANTMESSAGE;
-
-            if ( HasFlag(wxTE_PROCESS_TAB) )
-                lDlgCode |= DLGC_WANTTAB;
-
-            lRc |= lDlgCode;
-        }
-        else // !editable
-        {
-            // NB: use "=", not "|=" as the base class version returns the
-            //     same flags is this state as usual (i.e. including
-            //     DLGC_WANTMESSAGE). This is strange (how does it work in the
-            //     native Win32 apps?) but for now live with it.
-            lRc = lDlgCode;
-        }
+                if ( IsEditable() )
+                {
+                    // we may have several different cases:
+                    // 1. normal: both TAB and ENTER are used for navigation
+                    // 2. ctrl wants TAB for itself: ENTER is used to pass to
+                    //    the next control in the dialog
+                    // 3. ctrl wants ENTER for itself: TAB is used for dialog
+                    //    navigation
+                    // 4. ctrl wants both TAB and ENTER: Ctrl-ENTER is used to
+                    //    go to the next control (we need some way to do it)
+
+                    // multiline controls should always get ENTER for themselves
+                    if ( HasFlag(wxTE_PROCESS_ENTER) || HasFlag(wxTE_MULTILINE) )
+                        lDlgCode |= DLGC_WANTMESSAGE;
+
+                    if ( HasFlag(wxTE_PROCESS_TAB) )
+                        lDlgCode |= DLGC_WANTTAB;
+
+                    lRc |= lDlgCode;
+                }
+                else // !editable
+                {
+                    // NB: use "=", not "|=" as the base class version returns
+                    //     the same flags is this state as usual (i.e.
+                    //     including DLGC_WANTMESSAGE). This is strange (how
+                    //     does it work in the native Win32 apps?) but for now
+                    //     live with it.
+                    lRc = lDlgCode;
+                }
+            }
+            break;
+
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+            if ( HandleClipboardEvent(nMsg) )
+                lRc = 0;
+            break;
     }
 
     return lRc;
@@ -1971,6 +2025,11 @@ bool wxTextCtrl::SendUpdateEvent()
             // we hadn't updated the control ourselves, this event comes from
             // the user, don't need to ignore it nor update the count
             break;
+
+        case -2:
+            // the control was updated programmatically and we do NOT want to
+            // send events
+            return false;
     }
 
     wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
@@ -2564,11 +2623,23 @@ bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
         }
     }
 
-    if (pf.dwMask != 0)
+#if wxUSE_RICHEDIT2
+    if ( m_verRichEdit > 1 )
+    {
+        if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+        {
+            // Use RTL paragraphs in RTL mode to get proper layout
+            pf.dwMask |= PFM_RTLPARA;
+            pf.wEffects |= PFE_RTLPARA;
+        }
+    }
+#endif // wxUSE_RICHEDIT2
+
+    if ( pf.dwMask )
     {
         // do format the selection
         bool ok = ::SendMessage(GetHwnd(), EM_SETPARAFORMAT,
-            0, (LPARAM) &pf) != 0;
+                                0, (LPARAM) &pf) != 0;
         if ( !ok )
         {
             wxLogDebug(_T("SendMessage(EM_SETPARAFORMAT, 0) failed"));