X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/caea50acee8595b34709530475544cf6a1ef6444..b5b0a35d6b648aead1aa353dfe9c03775496981f:/src/msw/textctrl.cpp?ds=sidebyside diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 113994facc..d893afe8d5 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: msw/textctrl.cpp +// Name: src/msw/textctrl.cpp // Purpose: wxTextCtrl // Author: Julian Smart // Modified by: @@ -13,10 +13,6 @@ // declarations // ============================================================================ -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "textctrl.h" -#endif - // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- @@ -39,9 +35,11 @@ #include "wx/log.h" #include "wx/app.h" #include "wx/menu.h" + #include "wx/math.h" #endif #include "wx/module.h" +#include "wx/sysopt.h" #if wxUSE_CLIPBOARD #include "wx/clipbrd.h" @@ -63,6 +61,10 @@ #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__) @@ -83,25 +85,78 @@ class wxRichEditModule : public wxModule { public: + enum Version + { + Version_1, // riched32.dll + Version_2or3, // both use riched20.dll + Version_41, // msftedit.dll (XP SP1 and Windows 2003) + Version_Max + }; + virtual bool OnInit(); virtual void OnExit(); - // load the richedit DLL of at least of required version - static bool Load(int version = 1); + // 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[2]; + 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[2] = { NULL, NULL }; +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 +// a small class used to set m_updatesCount to 0 (to filter duplicate events if +// necessary) and to reset it back to -1 afterwards +class UpdatesCountFilter +{ +public: + UpdatesCountFilter(int& count) + : m_count(count) + { + wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") ); + + m_count = 0; + } + + ~UpdatesCountFilter() + { + m_count = -1; + } + + // return true if an event has been received + bool GotUpdate() const + { + return m_count == 1; + } + +private: + int& m_count; + + DECLARE_NO_COPY_CLASS(UpdatesCountFilter) +}; + // ---------------------------------------------------------------------------- // event tables and other macros // ---------------------------------------------------------------------------- @@ -151,7 +206,7 @@ wxBEGIN_FLAGS( wxTextCtrlStyle ) 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 ) @@ -181,7 +236,7 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) EVT_DROP_FILES(wxTextCtrl::OnDropFiles) #if wxUSE_RICHEDIT - EVT_RIGHT_UP(wxTextCtrl::OnRightClick) + EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu) #endif EVT_MENU(wxID_CUT, wxTextCtrl::OnCut) @@ -203,10 +258,49 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) 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 // ---------------------------------------------------------------------------- @@ -217,10 +311,13 @@ void wxTextCtrl::Init() m_verRichEdit = 0; #endif // wxUSE_RICHEDIT +#if wxUSE_INKEDIT && wxUSE_RICHEDIT + m_isInkEdit = 0; +#endif + m_privateContextMenu = NULL; - m_suppressNextUpdate = false; + m_updatesCount = -1; m_isNativeCaretShown = true; - m_isCaretAtEnd = true; } wxTextCtrl::~wxTextCtrl() @@ -251,6 +348,12 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, // do create the control - either an EDIT or RICHEDIT wxString windowClass = wxT("EDIT"); +#if defined(__POCKETPC__) || defined(__SMARTPHONE__) + // A control that capitalizes the first letter + if (style & wxTE_CAPITALIZE) + windowClass = wxT("CAPEDIT"); +#endif + #if wxUSE_RICHEDIT if ( m_windowStyle & wxTE_AUTO_URL ) { @@ -267,65 +370,90 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, // we need to load the richedit DLL before creating the rich edit control if ( m_windowStyle & wxTE_RICH ) { - static bool s_errorGiven = false;// MT-FIXME - - // Which version do we need? Use 1.0 by default because it is much more - // like the the standard EDIT or 2.0 if explicitly requested, but use - // only 2.0 in Unicode mode as 1.0 doesn't support Unicode at all + // versions 2.0, 3.0 and 4.1 of rich edit are mostly compatible with + // each other but not with version 1.0, so we have separate flags for + // the version 1.0 and the others (and so m_verRichEdit may be 0 (plain + // EDIT control), 1 for version 1.0 or 2 for any higher version) // - // TODO: RichEdit 3.0 is apparently capable of emulating RichEdit 1.0 - // (and thus EDIT) much better than RichEdit 2.0 so we probably - // should use 3.0 if available as it is the best of both worlds - - // but as I can't test it right now I don't do it (VZ) + // notice that 1.0 has no Unicode support at all so in Unicode build we + // must use another version + #if wxUSE_UNICODE - const int verRichEdit = 2; + m_verRichEdit = 2; #else // !wxUSE_UNICODE - int verRichEdit = m_windowStyle & wxTE_RICH2 ? 2 : 1; + m_verRichEdit = m_windowStyle & wxTE_RICH2 ? 2 : 1; #endif // wxUSE_UNICODE/!wxUSE_UNICODE - // only give the error msg once if the DLL can't be loaded - if ( !s_errorGiven ) +#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)) { - // try to load the RichEdit DLL (will do nothing if already done) - if ( !wxRichEditModule::Load(verRichEdit) ) + if (wxRichEditModule::LoadInkEdit()) { -#if !wxUSE_UNICODE - // try another version? - verRichEdit = 3 - verRichEdit; // 1 <-> 2 + windowClass = INKEDIT_CLASS; - if ( !wxRichEditModule::Load(verRichEdit) ) -#endif // wxUSE_UNICODE - { - wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll")); +#if wxUSE_INKEDIT && wxUSE_RICHEDIT + m_isInkEdit = 1; +#endif - s_errorGiven = true; - } + // Fake rich text version for other calls + m_verRichEdit = 2; } } +#endif - // have we managed to load any richedit version? - if ( !s_errorGiven ) + if (!IsInkEdit()) { - m_verRichEdit = verRichEdit; - if ( m_verRichEdit == 1 ) + if ( m_verRichEdit == 2 ) { - windowClass = wxT("RICHEDIT"); - } - else - { -#ifndef RICHEDIT_CLASS - wxString RICHEDIT_CLASS; - RICHEDIT_CLASS.Printf(_T("RichEdit%d0"), m_verRichEdit); + 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 - RICHEDIT_CLASS += _T('W'); + _T("W"); #else // ANSI - RICHEDIT_CLASS += _T('A'); + _T("A"); #endif // Unicode/ANSI -#endif // !RICHEDIT_CLASS + } + 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 + { + // 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; + } - windowClass = RICHEDIT_CLASS; + m_verRichEdit = 0; + } } - } + } // !useInkEdit } #endif // wxUSE_RICHEDIT @@ -344,17 +472,40 @@ 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 mask |= ENM_MOUSEEVENTS; + + // we also need to force the appearance of the vertical scrollbar + // initially as otherwise the control doesn't refresh correctly + // after resize: but once the vertical scrollbar had been shown + // (even if it's subsequently hidden) it does + // + // this is clearly a bug and for now it has been only noticed under + // 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); } else if ( m_windowStyle & wxTE_AUTO_URL ) { @@ -367,6 +518,9 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, } #endif // wxUSE_RICHEDIT + gs_wndprocEdit = wxSetWindowProc((HWND)GetHwnd(), + wxTextCtrlWndProc); + return true; } @@ -637,20 +791,24 @@ void wxTextCtrl::SetValue(const wxString& value) { 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) @@ -751,13 +909,8 @@ wxTextCtrl::StreamIn(const wxString& value, // the cast below is needed for broken (very) old mingw32 headers eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn; - // we're going to receive 2 EN_CHANGE notifications if we got any selection - // (same problem as in DoWriteText()) - if ( selectionOnly && HasSelection() ) - { - // so suppress one of them - m_suppressNextUpdate = true; - } + // same problem as in DoWriteText(): we can get multiple events here + UpdatesCountFilter ucf(m_updatesCount); ::SendMessage(GetHwnd(), EM_STREAMIN, SF_TEXT | @@ -765,6 +918,11 @@ wxTextCtrl::StreamIn(const wxString& value, (selectionOnly ? SFF_SELECTION : 0), (LPARAM)&eds); + // 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 ) { wxLogLastError(_T("EM_STREAMIN")); @@ -906,36 +1064,21 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly) #endif // wxUSE_RICHEDIT { // in some cases we get 2 EN_CHANGE notifications after the SendMessage - // call below which is confusing for the client code and so should be - // avoided - // - // these cases are: (a) plain EDIT controls if EM_REPLACESEL is used - // and there is a non empty selection currently and (b) rich text - // controls in any case - if ( -#if wxUSE_RICHEDIT - IsRich() || -#endif // wxUSE_RICHEDIT - (selectionOnly && HasSelection()) ) - { - m_suppressNextUpdate = true; - } + // call (this happens for plain EDITs with EM_REPLACESEL and under some + // -- undetermined -- conditions with rich edit) and sometimes we don't + // get any events at all (plain EDIT with WM_SETTEXT), so ensure that + // 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 + 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()); - // OTOH, non rich text controls don't generate any events at all when - // we use WM_SETTEXT -- have to emulate them here - if ( !selectionOnly -#if wxUSE_RICHEDIT - && !IsRich() -#endif // wxUSE_RICHEDIT - ) + if ( !ucf.GotUpdate() ) { - // Windows already sends an update event for single-line - // controls. - if ( m_windowStyle & wxTE_MULTILINE ) - SendUpdateEvent(); + SendUpdateEvent(); } } } @@ -1078,8 +1221,6 @@ void wxTextCtrl::SetEditable(bool editable) void wxTextCtrl::SetInsertionPoint(long pos) { DoSetSelection(pos, pos); - - m_isCaretAtEnd = pos == GetLastPosition(); } void wxTextCtrl::SetInsertionPointEnd() @@ -1089,9 +1230,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 ( m_isCaretAtEnd || GetInsertionPoint() == GetLastPosition() ) + if ( GetInsertionPoint() == GetLastPosition() ) { - m_isCaretAtEnd = true; return; } @@ -1129,7 +1269,7 @@ long wxTextCtrl::GetInsertionPoint() const return Pos & 0xFFFF; } -long wxTextCtrl::GetLastPosition() const +wxTextPos wxTextCtrl::GetLastPosition() const { int numLines = GetNumberOfLines(); long posStartLastLine = XYToPosition(0, numLines - 1); @@ -1230,10 +1370,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); } @@ -1249,6 +1393,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 } @@ -1472,9 +1618,6 @@ void wxTextCtrl::ShowPosition(long pos) if (linesToScroll != 0) (void)::SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll); - - // be pessimistic - m_isCaretAtEnd = false; } long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const @@ -1535,11 +1678,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); + } } // ---------------------------------------------------------------------------- @@ -1551,9 +1705,6 @@ void wxTextCtrl::Undo() if (CanUndo()) { ::SendMessage(GetHwnd(), EM_UNDO, 0, 0); - - // it's not necessarily at the end any more - m_isCaretAtEnd = false; } } @@ -1568,9 +1719,6 @@ void wxTextCtrl::Redo() #endif // Same as Undo, since Undo undoes the undo, i.e. a redo. ::SendMessage(GetHwnd(), EM_UNDO, 0, 0); - - // it's not necessarily at the end any more - m_isCaretAtEnd = false; } } @@ -1698,16 +1846,15 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) 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: @@ -1743,6 +1890,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; } @@ -1801,18 +1949,29 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara bool wxTextCtrl::SendUpdateEvent() { - // is event reporting suspended? - if ( m_suppressNextUpdate ) + switch ( m_updatesCount ) { - // do process the next one - m_suppressNextUpdate = false; + case 0: + // remember that we've got an update + m_updatesCount++; + break; - return false; + case 1: + // we had already sent one event since the last control modification + return false; + + default: + wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") ); + // fall through + + case -1: + // we hadn't updated the control ourselves, this event comes from + // the user, don't need to ignore it nor update the count + break; } wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); InitCommandEvent(event); - event.SetString(GetValue()); return ProcessCommand(event); } @@ -1856,82 +2015,44 @@ bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) return true; } -WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND WXUNUSED(pWnd), WXUINT WXUNUSED(nCtlColor), -#if wxUSE_CTL3D - WXUINT message, - WXWPARAM wParam, - WXLPARAM lParam -#else - WXUINT WXUNUSED(message), - WXWPARAM WXUNUSED(wParam), - WXLPARAM WXUNUSED(lParam) -#endif - ) +WXHBRUSH wxTextCtrl::MSWControlColor(WXHDC hDC, WXHWND hWnd) { -#if wxUSE_CTL3D - if ( m_useCtl3D ) - { - HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam); - return (WXHBRUSH) hbrush; - } -#endif // wxUSE_CTL3D - - HDC hdc = (HDC)pDC; - wxColour colBack = GetBackgroundColour(); - - if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0) - colBack = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); - - ::SetBkColor(hdc, wxColourToRGB(colBack)); - ::SetTextColor(hdc, wxColourToRGB(GetForegroundColour())); + if ( !IsEnabled() && !HasFlag(wxTE_MULTILINE) ) + return MSWControlColorDisabled(hDC); - wxBrush *brush = wxTheBrushList->FindOrCreateBrush(colBack, wxSOLID); - - return (WXHBRUSH)brush->GetResourceHandle(); + 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 @@ -1956,7 +2077,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 @@ -2046,7 +2167,7 @@ void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event) event.Enable(GetLastPosition() > 0); } -void wxTextCtrl::OnRightClick(wxMouseEvent& event) +void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event) { #if wxUSE_RICHEDIT if (IsRich()) @@ -2064,7 +2185,7 @@ void wxTextCtrl::OnRightClick(wxMouseEvent& event) m_privateContextMenu->AppendSeparator(); m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All")); } - PopupMenu(m_privateContextMenu, event.GetPosition()); + PopupMenu(m_privateContextMenu); return; } else @@ -2081,6 +2202,23 @@ void wxTextCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event)) } } +// ---------------------------------------------------------------------------- +// Default colors for MSW text control +// +// Set default background color to the native white instead of +// the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour). +// ---------------------------------------------------------------------------- + +wxVisualAttributes wxTextCtrl::GetDefaultAttributes() const +{ + wxVisualAttributes attrs; + attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //white + + return attrs; +} + // the rest of the file only deals with the rich edit controls #if wxUSE_RICHEDIT @@ -2184,23 +2322,6 @@ bool wxTextCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) return wxTextCtrlBase::MSWOnNotify(idCtrl, lParam, result); } -// ---------------------------------------------------------------------------- -// Default colors for MSW text control -// -// Set default background color to the native white instead of -// the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour). -// ---------------------------------------------------------------------------- - -wxVisualAttributes wxTextCtrl::GetDefaultAttributes() const -{ - wxVisualAttributes attrs; - attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //white - - return attrs; -} - // ---------------------------------------------------------------------------- // colour setting for the rich edit controls // ---------------------------------------------------------------------------- @@ -2469,7 +2590,7 @@ bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style) { // we have to do this or the style wouldn't apply for the text typed by // the user - long posLast = GetLastPosition(); + wxTextPos posLast = GetLastPosition(); SetStyle(posLast, posLast, m_defaultStyle); } @@ -2517,7 +2638,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 @@ -2534,7 +2655,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) wxStrcpy(lf.lfFaceName, cf.szFaceName); //NOTE: we _MUST_ set each of these values to _something_ since we - //do not call wxZeroMemory on the LOGFONT lf + //do not call wxZeroMemory on the LOGFONT lf if (cf.dwEffects & CFE_ITALIC) lf.lfItalic = TRUE; else @@ -2629,6 +2750,8 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) // wxRichEditModule // ---------------------------------------------------------------------------- +static const HINSTANCE INVALID_HINSTANCE = (HINSTANCE)-1; + bool wxRichEditModule::OnInit() { // don't do anything - we will load it when needed @@ -2639,26 +2762,22 @@ void wxRichEditModule::OnExit() { for ( size_t i = 0; i < WXSIZEOF(ms_hRichEdit); i++ ) { - if ( ms_hRichEdit[i] ) + if ( ms_hRichEdit[i] && ms_hRichEdit[i] != INVALID_HINSTANCE ) { ::FreeLibrary(ms_hRichEdit[i]); ms_hRichEdit[i] = NULL; } } +#if wxUSE_INKEDIT + if (ms_inkEditLib.IsLoaded()) + ms_inkEditLib.Unload(); +#endif } /* static */ -bool wxRichEditModule::Load(int version) +bool wxRichEditModule::Load(Version version) { - // we don't support loading richedit 3.0 as I don't know how to distinguish - // it from 2.0 anyhow - wxCHECK_MSG( version == 1 || version == 2, false, - _T("incorrect richedit control version requested") ); - - // make it the index in the array - version--; - - if ( ms_hRichEdit[version] == (HINSTANCE)-1 ) + if ( ms_hRichEdit[version] == INVALID_HINSTANCE ) { // we had already tried to load it and failed return false; @@ -2670,16 +2789,21 @@ bool wxRichEditModule::Load(int version) return true; } - wxString dllname = version ? _T("riched20") : _T("riched32"); - dllname += _T(".dll"); + static const wxChar *dllnames[] = + { + _T("riched32"), + _T("riched20"), + _T("msftedit"), + }; + + wxCOMPILE_TIME_ASSERT( WXSIZEOF(dllnames) == Version_Max, + RichEditDllNamesVersionsMismatch ); - ms_hRichEdit[version] = ::LoadLibrary(dllname); + ms_hRichEdit[version] = ::LoadLibrary(dllnames[version]); if ( !ms_hRichEdit[version] ) { - wxLogSysError(_("Could not load Rich Edit DLL '%s'"), dllname.c_str()); - - ms_hRichEdit[version] = (HINSTANCE)-1; + ms_hRichEdit[version] = INVALID_HINSTANCE; return false; } @@ -2687,6 +2811,23 @@ bool wxRichEditModule::Load(int 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__)