X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5c519b6cf79f6a3036285f1c458fb6f61bad02cd..c08ebc627546d8f1a3c69c989d21d587c851f9a9:/src/msw/textctrl.cpp diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 36b2359fbe..9899b14348 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -39,6 +39,7 @@ #include "wx/log.h" #include "wx/app.h" #include "wx/menu.h" + #include "wx/math.h" #endif #include "wx/module.h" @@ -102,6 +103,36 @@ 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 // ---------------------------------------------------------------------------- @@ -218,17 +249,14 @@ void wxTextCtrl::Init() #endif // wxUSE_RICHEDIT m_privateContextMenu = NULL; - m_suppressNextUpdate = false; + m_updatesCount = -1; m_isNativeCaretShown = true; + m_isCaretAtEnd = true; } wxTextCtrl::~wxTextCtrl() { - if (m_privateContextMenu) - { - delete m_privateContextMenu; - m_privateContextMenu = NULL; - } + delete m_privateContextMenu; } bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, @@ -346,8 +374,6 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, if ( !MSWCreateControl(windowClass, msStyle, pos, size, valueWin) ) return false; - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - #if wxUSE_RICHEDIT if ( IsRich() ) { @@ -756,13 +782,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 | @@ -770,6 +791,8 @@ wxTextCtrl::StreamIn(const wxString& value, (selectionOnly ? SFF_SELECTION : 0), (LPARAM)&eds); + wxASSERT_MSG( ucf.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") ); + if ( eds.dwError ) { wxLogLastError(_T("EM_STREAMIN")); @@ -911,40 +934,22 @@ 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()); - // 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(); } } - - AdjustSpaceLimit(); } void wxTextCtrl::AppendText(const wxString& text) @@ -954,7 +959,8 @@ void wxTextCtrl::AppendText(const wxString& text) WriteText(text); #if wxUSE_RICHEDIT - if ( IsMultiLine() && GetRichVersion() > 1 ) + // don't do this if we're frozen, saves some time + if ( !IsFrozen() && IsMultiLine() && GetRichVersion() > 1 ) { // setting the caret to the end and showing it simply doesn't work for // RichEdit 2.0 -- force it to still do what we want @@ -1084,6 +1090,8 @@ void wxTextCtrl::SetEditable(bool editable) void wxTextCtrl::SetInsertionPoint(long pos) { DoSetSelection(pos, pos); + + m_isCaretAtEnd = pos == GetLastPosition(); } void wxTextCtrl::SetInsertionPointEnd() @@ -1093,8 +1101,11 @@ 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() ) + if ( m_isCaretAtEnd || GetInsertionPoint() == GetLastPosition() ) + { + m_isCaretAtEnd = true; return; + } long pos; @@ -1130,7 +1141,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); @@ -1212,7 +1223,7 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) ::SendMessage(hWnd, EM_SETSEL, (WPARAM)from, (LPARAM)to); } - if ( scrollCaret ) + if ( scrollCaret && !IsFrozen() ) { #if wxUSE_RICHEDIT // richedit 3.0 (i.e. the version living in riched20.dll distributed @@ -1473,6 +1484,9 @@ 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 @@ -1549,6 +1563,9 @@ void wxTextCtrl::Undo() if (CanUndo()) { ::SendMessage(GetHwnd(), EM_UNDO, 0, 0); + + // it's not necessarily at the end any more + m_isCaretAtEnd = false; } } @@ -1563,6 +1580,9 @@ 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; } } @@ -1793,18 +1813,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); } @@ -1848,38 +1879,12 @@ 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) { -#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::MSWControlColorSolid(hDC); } bool wxTextCtrl::AdjustSpaceLimit() @@ -2073,6 +2078,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 @@ -2440,10 +2462,13 @@ bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style) if ( !wxTextCtrlBase::SetDefaultStyle(style) ) return false; - // we have to do this or the style wouldn't apply for the text typed by the - // user - long posLast = GetLastPosition(); - SetStyle(posLast, posLast, m_defaultStyle); + if ( IsEditable() ) + { + // we have to do this or the style wouldn't apply for the text typed by + // the user + wxTextPos posLast = GetLastPosition(); + SetStyle(posLast, posLast, m_defaultStyle); + } return true; } @@ -2496,6 +2521,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) (void) ::SendMessage(GetHwnd(), EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf) ; + LOGFONT lf; lf.lfHeight = cf.yHeight; lf.lfWidth = 0; @@ -2503,17 +2529,32 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) lf.lfClipPrecision = 0; lf.lfEscapement = 0; 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 if (cf.dwEffects & CFE_ITALIC) lf.lfItalic = TRUE; + else + lf.lfItalic = FALSE; + lf.lfOrientation = 0; lf.lfPitchAndFamily = cf.bPitchAndFamily; lf.lfQuality = 0; + if (cf.dwEffects & CFE_STRIKEOUT) lf.lfStrikeOut = TRUE; + else + lf.lfStrikeOut = FALSE; + if (cf.dwEffects & CFE_UNDERLINE) lf.lfUnderline = TRUE; + else + lf.lfUnderline = FALSE; + if (cf.dwEffects & CFE_BOLD) lf.lfWeight = FW_BOLD; + else + lf.lfWeight = FW_NORMAL; wxFont font = wxCreateFontFromLogFont(& lf); if (font.Ok())