X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0efe5ba76e45711cad627222905a55c7e04adf9a..170cbe33dc9fa4255ed19b3d0b321e3daf204416:/src/msw/textctrl.cpp diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 55e3e77492..794d146e78 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -33,11 +33,12 @@ #include "wx/settings.h" #include "wx/brush.h" #include "wx/utils.h" + #include "wx/intl.h" #include "wx/log.h" + #include "wx/app.h" #endif #if wxUSE_CLIPBOARD - #include "wx/app.h" #include "wx/clipbrd.h" #endif @@ -57,11 +58,45 @@ # include #endif -#if wxUSE_RICHEDIT && !defined(__GNUWIN32__) +#if wxUSE_RICHEDIT && (!defined(__GNUWIN32__) || defined(wxUSE_NORLANDER_HEADERS)) #include #endif -#if !USE_SHARED_LIBRARY +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +#if wxUSE_RICHEDIT + +// this module initializes RichEdit DLL if needed +class wxRichEditModule : public wxModule +{ +public: + virtual bool OnInit(); + virtual void OnExit(); + + // get the version currently loaded, -1 if none + static int GetLoadedVersion() { return ms_verRichEdit; } + + // load the richedit DLL of at least of required version + static bool Load(int version = 1); + +private: + // the handle to richedit DLL and the version of the DLL loaded + static HINSTANCE ms_hRichEdit; + + // the DLL version loaded or -1 if none + static int ms_verRichEdit; + + DECLARE_DYNAMIC_CLASS(wxRichEditModule) +}; + +HINSTANCE wxRichEditModule::ms_hRichEdit = (HINSTANCE)NULL; +int wxRichEditModule::ms_verRichEdit = -1; + +IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule) + +#endif // wxUSE_RICHEDIT // ---------------------------------------------------------------------------- // event tables and other macros @@ -86,7 +121,6 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo) END_EVENT_TABLE() -#endif // USE_SHARED_LIBRARY // ============================================================================ // implementation @@ -112,31 +146,32 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, const wxString& name) { // base initialization - if ( !CreateBase(parent, id, pos, size, style, name) ) + if ( !CreateBase(parent, id, pos, size, style, validator, name) ) return FALSE; - SetValidator(validator); if ( parent ) parent->AddChild(this); - // set colours - SetupColours(); - // translate wxWin style flags to MSW ones, checking for consistency while // doing it long msStyle = ES_LEFT | WS_VISIBLE | WS_CHILD | WS_TABSTOP; if ( m_windowStyle & wxTE_MULTILINE ) { wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER), - _T("wxTE_PROCESS_ENTER style is ignored for multiline " - "text controls (they always process it)") ); + wxT("wxTE_PROCESS_ENTER style is ignored for multiline " + "text controls (they always process it)") ); - msStyle |= ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL; + msStyle |= ES_MULTILINE | ES_WANTRETURN; + if ((m_windowStyle & wxTE_NO_VSCROLL) == 0) + msStyle |= WS_VSCROLL; m_windowStyle |= wxTE_PROCESS_ENTER; } else msStyle |= ES_AUTOHSCROLL; + if (m_windowStyle & wxHSCROLL) + msStyle |= (WS_HSCROLL | ES_AUTOHSCROLL); + if (m_windowStyle & wxTE_READONLY) msStyle |= ES_READONLY; @@ -161,21 +196,61 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, m_lDlgCode |= DLGC_WANTTAB; // do create the control - either an EDIT or RICHEDIT - const wxChar *windowClass = _T("EDIT"); + wxString windowClass = wxT("EDIT"); #if wxUSE_RICHEDIT - // multiline edit controls are RICHEDITs except for those which have a - // simple border (VZ: why??) - if ( (m_windowStyle & wxTE_MULTILINE) && - !(m_windowStyle & wxSIMPLE_BORDER) ) + if ( m_windowStyle & wxTE_RICH ) { - msStyle |= ES_AUTOVSCROLL; - m_isRich = TRUE; - windowClass = _T("RICHEDIT"); + static bool s_errorGiven = FALSE; // MT-FIXME + + // only give the error msg once if the DLL can't be loaded + if ( !s_errorGiven ) + { + // first try to load the RichEdit DLL (will do nothing if already + // done) + if ( !wxRichEditModule::Load() ) + { + wxLogError(_("Impossible to create a rich edit control, " + "using simple text control instead. Please " + "reinstall riched32.dll")); + + s_errorGiven = TRUE; + } + } + + if ( s_errorGiven ) + { + m_isRich = FALSE; + } + else + { + msStyle |= ES_AUTOVSCROLL; + m_isRich = TRUE; + + int ver = wxRichEditModule::GetLoadedVersion(); + if ( ver == 1 ) + { + windowClass = wxT("RICHEDIT"); + } + else + { +#ifndef RICHEDIT_CLASS + wxString RICHEDIT_CLASS; + RICHEDIT_CLASS.Printf(_T("RichEdit%d0"), ver); +#ifdef wxUSE_UNICODE + RICHEDIT_CLASS += _T('W'); +#else // ANSI + RICHEDIT_CLASS += _T('A'); +#endif // Unicode/ANSI +#endif // !RICHEDIT_CLASS + + windowClass = RICHEDIT_CLASS; + } + } } else m_isRich = FALSE; -#endif +#endif // wxUSE_RICHEDIT bool want3D; WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D); @@ -198,7 +273,7 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, wxGetInstance(), NULL); - wxCHECK_MSG( m_hWnd, FALSE, _T("Failed to create text ctrl") ); + wxCHECK_MSG( m_hWnd, FALSE, wxT("Failed to create text ctrl") ); #if wxUSE_CTL3D if ( want3D ) @@ -238,6 +313,9 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, } #endif + // set colours + SetupColours(); + SetSize(pos.x, pos.y, size.x, size.y); return TRUE; @@ -257,7 +335,7 @@ void wxTextCtrl::AdoptAttributesFromHWND() GetClassName(hWnd, buf, WXSIZEOF(buf)); - if ( wxStricmp(buf, _T("EDIT")) == 0 ) + if ( wxStricmp(buf, wxT("EDIT")) == 0 ) m_isRich = FALSE; else m_isRich = TRUE; @@ -275,8 +353,13 @@ void wxTextCtrl::AdoptAttributesFromHWND() void wxTextCtrl::SetupColours() { - // FIXME why is bg colour not inherited from parent? - SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + wxColour bkgndColour; + if (IsEditable() || (m_windowStyle & wxTE_MULTILINE)) + bkgndColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW); + else + bkgndColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE); + + SetBackgroundColour(bkgndColour); SetForegroundColour(GetParent()->GetForegroundColour()); } @@ -286,16 +369,60 @@ void wxTextCtrl::SetupColours() wxString wxTextCtrl::GetValue() const { - return wxGetWindowText(GetHWND()); + // we can't use wxGetWindowText() (i.e. WM_GETTEXT internally) for + // retrieving more than 64Kb under Win9x +#if wxUSE_RICHEDIT + if ( m_isRich ) + { + wxString str; + + int len = GetWindowTextLength(GetHwnd()) + 1; + wxChar *p = str.GetWriteBuf(len); + + TEXTRANGE textRange; + textRange.chrg.cpMin = 0; + textRange.chrg.cpMax = -1; + textRange.lpstrText = p; + + (void)SendMessage(GetHwnd(), EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + + // believe it or not, but EM_GETTEXTRANGE uses just CR ('\r') for the + // newlines which is neither Unix nor Windows style (Win95 with + // riched20.dll shows this behaviour) - convert it to something + // reasonable + for ( ; *p; p++ ) + { + if ( *p == _T('\r') ) + *p = _T('\n'); + } + + str.UngetWriteBuf(); + + return str; + } +#endif // wxUSE_RICHEDIT + + // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the + // same one as above for consitency + wxString str = wxGetWindowText(GetHWND()); + + return wxTextFile::Translate(str, wxTextFileType_Unix); } void wxTextCtrl::SetValue(const wxString& value) { - wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos); + // 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 + // anyhow, this comparison is there to avoid flicker for small single-line + // edit controls mostly) + if ( (value.length() > 0x400) || (value != GetValue()) ) + { + wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos); - SetWindowText(GetHwnd(), valueDos); + SetWindowText(GetHwnd(), valueDos); - AdjustSpaceLimit(); + AdjustSpaceLimit(); + } } void wxTextCtrl::WriteText(const wxString& value) @@ -315,7 +442,7 @@ void wxTextCtrl::AppendText(const wxString& text) void wxTextCtrl::Clear() { - SetWindowText(GetHwnd(), _T("")); + SetWindowText(GetHwnd(), wxT("")); } // ---------------------------------------------------------------------------- @@ -394,8 +521,16 @@ bool wxTextCtrl::CanPaste() const void wxTextCtrl::SetEditable(bool editable) { + bool isEditable = IsEditable(); + HWND hWnd = GetHwnd(); SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L); + + if (editable != isEditable) + { + SetupColours(); + Refresh(); + } } void wxTextCtrl::SetInsertionPoint(long pos) @@ -737,30 +872,6 @@ void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event) } } -WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, - WXUINT message, WXWPARAM wParam, - WXLPARAM lParam) -{ -#if wxUSE_CTL3D - if ( m_useCtl3D ) - { - HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam); - return (WXHBRUSH) hbrush; - } -#endif - - HDC hdc = (HDC)pDC; - SetBkMode(hdc, GetParent()->GetTransparentBackground() ? TRANSPARENT - : OPAQUE); - - ::SetBkColor(hdc, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); - ::SetTextColor(hdc, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); - - wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); - - return (WXHBRUSH) backgroundBrush->GetResourceHandle(); -} - void wxTextCtrl::OnChar(wxKeyEvent& event) { switch ( event.KeyCode() ) @@ -782,30 +893,19 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) // ourselves the fact that we got here means that the user code // decided to skip processing of this TAB - probably to let it // do its default job. - // - // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is - // handled by Windows { wxNavigationKeyEvent eventNav; eventNav.SetDirection(!event.ShiftDown()); - eventNav.SetWindowChange(FALSE); + eventNav.SetWindowChange(event.ControlDown()); eventNav.SetEventObject(this); - if ( GetEventHandler()->ProcessEvent(eventNav) ) + if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) return; } break; - - default: - event.Skip(); - return; } - // don't just call event.Skip() because this will cause TABs and ENTERs - // be passed upwards and we don't always want this - instead process it - // right here - - // FIXME + // no, we didn't process it event.Skip(); } @@ -835,14 +935,14 @@ bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) } break; - case EN_ERRSPACE: + case EN_MAXTEXT: // the text size limit has been hit - increase it AdjustSpaceLimit(); break; // the other notification messages are not processed case EN_UPDATE: - case EN_MAXTEXT: + case EN_ERRSPACE: case EN_HSCROLL: case EN_VSCROLL: default: @@ -858,20 +958,30 @@ void wxTextCtrl::AdjustSpaceLimit() #ifndef __WIN16__ unsigned int len = ::GetWindowTextLength(GetHwnd()), limit = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0); - if ( len > limit ) + if ( len >= limit ) { limit = len + 0x8000; // 32Kb #if wxUSE_RICHEDIT - if ( m_isRich || limit > 0xffff ) -#else - if ( limit > 0xffff ) -#endif - ::SendMessage(GetHwnd(), EM_LIMITTEXT, 0, limit); + if ( m_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); + } } -#endif +#endif // !Win16 } bool wxTextCtrl::AcceptsFocus() const @@ -880,7 +990,7 @@ bool wxTextCtrl::AcceptsFocus() const return IsEditable() && wxControl::AcceptsFocus(); } -wxSize wxTextCtrl::DoGetBestSize() +wxSize wxTextCtrl::DoGetBestSize() const { int cx, cy; wxGetCharSize(GetHWND(), &cx, &cy, &GetFont()); @@ -951,3 +1061,68 @@ void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) event.Enable( CanRedo() ); } +// ---------------------------------------------------------------------------- +// wxRichEditModule +// ---------------------------------------------------------------------------- + +#if wxUSE_RICHEDIT + +bool wxRichEditModule::OnInit() +{ + // don't do anything - we will load it when needed + return TRUE; +} + +void wxRichEditModule::OnExit() +{ + if ( ms_hRichEdit ) + { + FreeLibrary(ms_hRichEdit); + } +} + +/* static */ +bool wxRichEditModule::Load(int version) +{ + wxCHECK_MSG( version >= 1 && version <= 3, FALSE, + _T("incorrect richedit control version requested") ); + + if ( version <= ms_verRichEdit ) + { + // we've already got this or better + return TRUE; + } + + if ( ms_hRichEdit ) + { + ::FreeLibrary(ms_hRichEdit); + } + + // always try load riched20.dll first - like this we won't have to reload + // it later if we're first asked for RE 1 and then for RE 2 or 3 + wxString dllname = _T("riched20.dll"); + ms_hRichEdit = ::LoadLibrary(dllname); + ms_verRichEdit = 2; // no way to tell if it's 2 or 3, assume 2 + + if ( !ms_hRichEdit && (version == 1) ) + { + // fall back to RE 1 + dllname = _T("riched32.dll"); + ms_hRichEdit = ::LoadLibrary(dllname); + ms_verRichEdit = 1; + } + + if ( !ms_hRichEdit ) + { + wxLogSysError(_("Could not load Rich Edit DLL '%s'"), dllname.c_str()); + + ms_verRichEdit = -1; + + return FALSE; + } + + return TRUE; +} + +#endif // wxUSE_RICHEDIT +