]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/textctrl.cpp
eVC4 updates
[wxWidgets.git] / src / msw / textctrl.cpp
index fda9d0207d5935e029991083d892078f26c1e0f8..7dd6a84fcfc42c2de707c7a87a0f025cf8046b56 100644 (file)
 
 #endif // wxUSE_RICHEDIT
 
-// ----------------------------------------------------------------------------
-// private functions
-// ----------------------------------------------------------------------------
-
-#if wxUSE_RICHEDIT
-
-DWORD CALLBACK wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb);
-
-#endif // wxUSE_RICHEDIT
-
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -119,68 +109,68 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
 #if wxUSE_EXTENDED_RTTI
 WX_DEFINE_FLAGS( wxTextCtrlStyle )
 
-WX_BEGIN_FLAGS( wxTextCtrlStyle )
+wxBEGIN_FLAGS( wxTextCtrlStyle )
     // new style border flags, we put them first to
     // use them for streaming out
-    WX_FLAGS_MEMBER(wxBORDER_SIMPLE)
-    WX_FLAGS_MEMBER(wxBORDER_SUNKEN)
-    WX_FLAGS_MEMBER(wxBORDER_DOUBLE)
-    WX_FLAGS_MEMBER(wxBORDER_RAISED)
-    WX_FLAGS_MEMBER(wxBORDER_STATIC)
-    WX_FLAGS_MEMBER(wxBORDER_NONE)
+    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
+    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
+    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
+    wxFLAGS_MEMBER(wxBORDER_RAISED)
+    wxFLAGS_MEMBER(wxBORDER_STATIC)
+    wxFLAGS_MEMBER(wxBORDER_NONE)
     
     // old style border flags
-    WX_FLAGS_MEMBER(wxSIMPLE_BORDER)
-    WX_FLAGS_MEMBER(wxSUNKEN_BORDER)
-    WX_FLAGS_MEMBER(wxDOUBLE_BORDER)
-    WX_FLAGS_MEMBER(wxRAISED_BORDER)
-    WX_FLAGS_MEMBER(wxSTATIC_BORDER)
-    WX_FLAGS_MEMBER(wxNO_BORDER)
+    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
+    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
+    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
+    wxFLAGS_MEMBER(wxRAISED_BORDER)
+    wxFLAGS_MEMBER(wxSTATIC_BORDER)
+    wxFLAGS_MEMBER(wxBORDER)
 
     // standard window styles
-    WX_FLAGS_MEMBER(wxTAB_TRAVERSAL)
-    WX_FLAGS_MEMBER(wxCLIP_CHILDREN)
-    WX_FLAGS_MEMBER(wxTRANSPARENT_WINDOW)
-    WX_FLAGS_MEMBER(wxWANTS_CHARS)
-    WX_FLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
-    WX_FLAGS_MEMBER(wxALWAYS_SHOW_SB )
-    WX_FLAGS_MEMBER(wxVSCROLL)
-    WX_FLAGS_MEMBER(wxHSCROLL)
-
-    WX_FLAGS_MEMBER(wxTE_PROCESS_ENTER)
-    WX_FLAGS_MEMBER(wxTE_PROCESS_TAB)
-    WX_FLAGS_MEMBER(wxTE_MULTILINE)
-    WX_FLAGS_MEMBER(wxTE_PASSWORD)
-    WX_FLAGS_MEMBER(wxTE_READONLY)
-    WX_FLAGS_MEMBER(wxHSCROLL)
-    WX_FLAGS_MEMBER(wxTE_RICH)
-    WX_FLAGS_MEMBER(wxTE_RICH2)
-    WX_FLAGS_MEMBER(wxTE_AUTO_URL)
-    WX_FLAGS_MEMBER(wxTE_NOHIDESEL)
-    WX_FLAGS_MEMBER(wxTE_LEFT)
-    WX_FLAGS_MEMBER(wxTE_CENTRE)
-    WX_FLAGS_MEMBER(wxTE_RIGHT)
-    WX_FLAGS_MEMBER(wxTE_DONTWRAP)
-    WX_FLAGS_MEMBER(wxTE_LINEWRAP)
-    WX_FLAGS_MEMBER(wxTE_WORDWRAP)
-
-WX_END_FLAGS( wxTextCtrlStyle )
+    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
+    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
+    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
+    wxFLAGS_MEMBER(wxWANTS_CHARS)
+    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
+    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
+    wxFLAGS_MEMBER(wxVSCROLL)
+    wxFLAGS_MEMBER(wxHSCROLL)
+
+    wxFLAGS_MEMBER(wxTE_PROCESS_ENTER)
+    wxFLAGS_MEMBER(wxTE_PROCESS_TAB)
+    wxFLAGS_MEMBER(wxTE_MULTILINE)
+    wxFLAGS_MEMBER(wxTE_PASSWORD)
+    wxFLAGS_MEMBER(wxTE_READONLY)
+    wxFLAGS_MEMBER(wxHSCROLL)
+    wxFLAGS_MEMBER(wxTE_RICH)
+    wxFLAGS_MEMBER(wxTE_RICH2)
+    wxFLAGS_MEMBER(wxTE_AUTO_URL)
+    wxFLAGS_MEMBER(wxTE_NOHIDESEL)
+    wxFLAGS_MEMBER(wxTE_LEFT)
+    wxFLAGS_MEMBER(wxTE_CENTRE)
+    wxFLAGS_MEMBER(wxTE_RIGHT)
+    wxFLAGS_MEMBER(wxTE_DONTWRAP)
+    wxFLAGS_MEMBER(wxTE_LINEWRAP)
+    wxFLAGS_MEMBER(wxTE_WORDWRAP)
+
+wxEND_FLAGS( wxTextCtrlStyle )
 
 IMPLEMENT_DYNAMIC_CLASS_XTI(wxTextCtrl, wxControl,"wx/textctrl.h")
 
-WX_BEGIN_PROPERTIES_TABLE(wxTextCtrl)
-    WX_EVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent ) 
-    WX_EVENT_PROPERTY( TextEnter , wxEVT_COMMAND_TEXT_ENTER , wxCommandEvent )
+wxBEGIN_PROPERTIES_TABLE(wxTextCtrl)
+    wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent ) 
+    wxEVENT_PROPERTY( TextEnter , wxEVT_COMMAND_TEXT_ENTER , wxCommandEvent )
 
-    WX_PROPERTY( Font , wxFont , SetFont , GetFont  ,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
-       WX_PROPERTY( Value , wxString , SetValue, GetValue, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    WX_PROPERTY_FLAGS( WindowStyle , wxTextCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
-WX_END_PROPERTIES_TABLE()
+    wxPROPERTY( Font , wxFont , SetFont , GetFont  ,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
+       wxPROPERTY( Value , wxString , SetValue, GetValue, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
+    wxPROPERTY_FLAGS( WindowStyle , wxTextCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+wxEND_PROPERTIES_TABLE()
 
-WX_BEGIN_HANDLERS_TABLE(wxTextCtrl)
-WX_END_HANDLERS_TABLE()
+wxBEGIN_HANDLERS_TABLE(wxTextCtrl)
+wxEND_HANDLERS_TABLE()
 
-WX_CONSTRUCTOR_6( wxTextCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , Value , wxPoint , Position , wxSize , Size , long , WindowStyle)
+wxCONSTRUCTOR_6( wxTextCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , Value , wxPoint , Position , wxSize , Size , long , WindowStyle)
 #else
 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
 #endif
@@ -464,11 +454,12 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
         msStyle |= ES_AUTOHSCROLL;
     }
 
-    // styles which we add depending on the specified wxWindows styles
-    if ( style & wxHSCROLL )
+    // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz
+    // scrollbar, there is no wrapping -- which makes sense
+    if ( style & wxTE_DONTWRAP )
     {
         // automatically scroll the control horizontally as necessary
-        msStyle |= WS_HSCROLL;// | ES_AUTOHSCROLL;
+        msStyle |= WS_HSCROLL;
     }
 
     if ( style & wxTE_READONLY )
@@ -486,7 +477,7 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
     else if ( style & wxTE_RIGHT )
         msStyle |= ES_RIGHT;
     else
-        msStyle |= ES_LEFT; // ES_LEFT if 0 as well but for consistency...
+        msStyle |= ES_LEFT; // ES_LEFT is 0 as well but for consistency...
 
     return msStyle;
 }
@@ -536,6 +527,52 @@ wxString wxTextCtrl::GetRange(long from, long to) const
         int len = GetWindowTextLength(GetHwnd());
         if ( len > from )
         {
+            if ( to == -1 )
+                to = len;
+
+#if !wxUSE_UNICODE
+            // we must use EM_STREAMOUT if we don't want to lose all characters
+            // not representable in the current character set (EM_GETTEXTRANGE
+            // simply replaces them with question marks...)
+            if ( GetRichVersion() > 1 )
+            {
+                // we must have some encoding, otherwise any 8bit chars in the
+                // control are simply *lost* (replaced by '?')
+                wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
+
+                wxFont font = m_defaultStyle.GetFont();
+                if ( !font.Ok() )
+                    font = GetFont();
+
+                if ( font.Ok() )
+                {
+                   encoding = font.GetEncoding();
+                }
+
+                if ( encoding == wxFONTENCODING_SYSTEM )
+                {
+                    encoding = wxLocale::GetSystemEncoding();
+                }
+
+                if ( encoding == wxFONTENCODING_SYSTEM )
+                {
+                    encoding = wxFONTENCODING_ISO8859_1;
+                }
+
+                str = StreamOut(encoding);
+
+                if ( !str.empty() )
+                {
+                    // we have to manually extract the required part, luckily
+                    // this is easy in this case as EOL characters in str are
+                    // just LFs because we remove CRs in wxRichEditStreamOut
+                    str = str.Mid(from, to - from);
+                }
+            }
+
+            // StreamOut() wasn't used or failed, try to do it in normal way
+            if ( str.empty() )
+#endif // !wxUSE_UNICODE
             {
                 // alloc one extra WORD as needed by the control
                 wxStringBuffer tmp(str, ++len);
@@ -543,7 +580,7 @@ wxString wxTextCtrl::GetRange(long from, long to) const
 
                 TEXTRANGE textRange;
                 textRange.chrg.cpMin = from;
-                textRange.chrg.cpMax = to == -1 ? len : to;
+                textRange.chrg.cpMax = to;
                 textRange.lpstrText = p;
 
                 (void)SendMessage(GetHwnd(), EM_GETTEXTRANGE,
@@ -600,6 +637,9 @@ void wxTextCtrl::SetValue(const wxString& value)
     if ( (value.length() > 0x400) || (value != GetValue()) )
     {
         DoWriteText(value, FALSE /* not selection only */);
+        
+        // for compatibility, don't move the cursor when doing SetValue()
+        SetInsertionPoint(0);
     }
     else // same text
     {
@@ -612,19 +652,21 @@ void wxTextCtrl::SetValue(const wxString& value)
     // 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);
 }
 
 #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU)
 
-DWORD CALLBACK wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
+// TODO: using memcpy() would improve performance a lot for big amounts of text
+
+DWORD CALLBACK
+wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
 {
     *pcb = 0;
 
+    const wchar_t ** const ppws = (const wchar_t **)dwCookie;
+
     wchar_t *wbuf = (wchar_t *)buf;
-    const wchar_t *wpc = *(const wchar_t **)dwCookie;
+    const wchar_t *wpc = *ppws;
     while ( cb && *wpc )
     {
         *wbuf++ = *wpc++;
@@ -633,56 +675,77 @@ DWORD CALLBACK wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
         (*pcb) += sizeof(wchar_t);
     }
 
-    *(const wchar_t **)dwCookie = wpc;
+    *ppws = wpc;
 
     return 0;
 }
 
-// from utils.cpp
-extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding);
-
-#if wxUSE_UNICODE_MSLU
-bool wxTextCtrl::StreamIn(const wxString& value,
-                          wxFontEncoding WXUNUSED(encoding),
-                          bool selectionOnly)
+// helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut
+struct wxStreamOutData
 {
-    const wchar_t *wpc = value.c_str();
-#else // !wxUSE_UNICODE_MSLU
-bool wxTextCtrl::StreamIn(const wxString& value,
-                          wxFontEncoding encoding,
-                          bool selectionOnly)
+    wchar_t *wpc;
+    size_t len;
+};
+
+DWORD CALLBACK
+wxRichEditStreamOut(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
 {
-    // we have to use EM_STREAMIN to force richedit control 2.0+ to show any
-    // text in the non default charset -- otherwise it thinks it knows better
-    // than we do and always shows it in the default one
+    *pcb = 0;
+
+    wxStreamOutData *data = (wxStreamOutData *)dwCookie;
 
-    // first get the Windows code page for this encoding
-    long codepage = wxEncodingToCodepage(encoding);
-    if ( codepage == -1 )
+    const wchar_t *wbuf = (const wchar_t *)buf;
+    wchar_t *wpc = data->wpc;
+    while ( cb )
     {
-        // unknown encoding
-        return FALSE;
+        wchar_t wch = *wbuf++;
+
+        // turn "\r\n" into "\n" on the fly
+        if ( wch != L'\r' )
+            *wpc++ = wch;
+        else
+            data->len--;
+
+        cb -= sizeof(wchar_t);
+        (*pcb) += sizeof(wchar_t);
     }
 
-    // next translate to Unicode using this code page
-    int len = ::MultiByteToWideChar(codepage, 0, value, -1, NULL, 0);
+    data->wpc = wpc;
+
+    return 0;
+}
+
+
+#if wxUSE_UNICODE_MSLU
+    #define UNUSED_IF_MSLU(param)
+#else
+    #define UNUSED_IF_MSLU(param) param
+#endif
+
+bool
+wxTextCtrl::StreamIn(const wxString& value,
+                     wxFontEncoding UNUSED_IF_MSLU(encoding),
+                     bool selectionOnly)
+{
+#if wxUSE_UNICODE_MSLU
+    const wchar_t *wpc = value.c_str();
+#else // !wxUSE_UNICODE_MSLU
+    wxCSConv conv(encoding);
+
+    const size_t len = conv.MB2WC(NULL, value, value.length());
 
 #if wxUSE_WCHAR_T
     wxWCharBuffer wchBuf(len);
+    wchar_t *wpc = wchBuf.data();
 #else
     wchar_t *wchBuf = (wchar_t *)malloc((len + 1)*sizeof(wchar_t));
+    wchar_t *wpc = wchBuf;
 #endif
 
-    if ( !::MultiByteToWideChar(codepage, 0, value, -1,
-                                (wchar_t *)(const wchar_t *)wchBuf, len) )
-    {
-        wxLogLastError(_T("MultiByteToWideChar"));
-    }
-
-    // finally, stream it in the control
-    const wchar_t *wpc = wchBuf;
+    conv.MB2WC(wpc, value, value.length());
 #endif // wxUSE_UNICODE_MSLU
 
+    // finally, stream it in the control
     EDITSTREAM eds;
     wxZeroMemory(eds);
     eds.dwCookie = (DWORD)&wpc;
@@ -715,6 +778,69 @@ bool wxTextCtrl::StreamIn(const wxString& value,
     return TRUE;
 }
 
+#if !wxUSE_UNICODE_MSLU
+
+wxString
+wxTextCtrl::StreamOut(wxFontEncoding encoding, bool selectionOnly) const
+{
+    wxString out;
+
+    const int len = GetWindowTextLength(GetHwnd());
+
+#if wxUSE_WCHAR_T
+    wxWCharBuffer wchBuf(len);
+    wchar_t *wpc = wchBuf.data();
+#else
+    wchar_t *wchBuf = (wchar_t *)malloc((len + 1)*sizeof(wchar_t));
+    wchar_t *wpc = wchBuf;
+#endif
+
+    wxStreamOutData data;
+    data.wpc = wpc;
+    data.len = len;
+
+    EDITSTREAM eds;
+    wxZeroMemory(eds);
+    eds.dwCookie = (DWORD)&data;
+    eds.pfnCallback = wxRichEditStreamOut;
+
+    ::SendMessage
+      (
+        GetHwnd(),
+        EM_STREAMOUT,
+        SF_TEXT | SF_UNICODE | (selectionOnly ? SFF_SELECTION : 0),
+        (LPARAM)&eds
+      );
+
+    if ( eds.dwError )
+    {
+        wxLogLastError(_T("EM_STREAMOUT"));
+    }
+    else // streamed out ok
+    {
+        // NUL-terminate the string because its length could have been
+        // decreased by wxRichEditStreamOut
+        *(wchBuf.data() + data.len) = L'\0';
+
+        // now convert to the given encoding (this is a possibly lossful
+        // conversion but what else can we do)
+        wxCSConv conv(encoding);
+        size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0);
+        if ( lenNeeded++ )
+        {
+            conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded);
+        }
+    }
+
+#if !wxUSE_WCHAR_T
+    free(wchBuf);
+#endif // !wxUSE_WCHAR_T
+
+    return out;
+}
+
+#endif // !wxUSE_UNICODE_MSLU
+
 #endif // wxUSE_RICHEDIT
 
 void wxTextCtrl::WriteText(const wxString& value)
@@ -766,6 +892,10 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
                wxFontEncoding encoding = font.GetEncoding();
                if ( encoding != wxFONTENCODING_SYSTEM )
                {
+                   // we have to use EM_STREAMIN to force richedit control 2.0+
+                   // to show any text in the non default charset -- otherwise
+                   // it thinks it knows better than we do and always shows it
+                   // in the default one
                    done = StreamIn(valueDos, encoding, selectionOnly);
                }
             }
@@ -1135,13 +1265,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 */);
 
-    SendMessage(GetHwnd(), EM_REPLACESEL,
-#ifdef __WIN32__
-                TRUE,
-#else
-                FALSE,
-#endif
-                (LPARAM)value.c_str());
+    DoWriteText(value, TRUE /* selection only */);
 }
 
 void wxTextCtrl::Remove(long from, long to)
@@ -1167,7 +1291,11 @@ bool wxTextCtrl::IsModified() const
     return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
 }
 
-// Makes 'unmodified'
+void wxTextCtrl::MarkDirty()
+{
+    SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0L);
+}
+
 void wxTextCtrl::DiscardEdits()
 {
     SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
@@ -1291,6 +1419,13 @@ wxString wxTextCtrl::GetLineText(long lineNo) const
         }
 #endif // wxUSE_RICHEDIT
 
+        // remove the '\n' at the end, if any (this is how this function is
+        // supposed to work according to the docs)
+        if ( buf[len - 1] == _T('\n') )
+        {
+            len--;
+        }
+
         buf[len] = 0;
         tmp.SetLength(len);
     }