X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3306aec1240b38347abda1ad776df32b6687ad01..d2a931c9f745c69b8e9ccf72648b426fe064ff78:/src/msw/textctrl.cpp diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 5db4094a34..02f25eabc3 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -27,7 +27,6 @@ #if wxUSE_TEXTCTRL && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) #ifndef WX_PRECOMP - #include "wx/msw/missing.h" #include "wx/textctrl.h" #include "wx/settings.h" #include "wx/brush.h" @@ -52,6 +51,7 @@ #include "wx/msw/private.h" #include "wx/msw/winundef.h" +#include "wx/msw/mslu.h" #include #include @@ -74,6 +74,8 @@ #endif // wxUSE_RICHEDIT +#include "wx/msw/missing.h" + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -134,9 +136,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() @@ -257,50 +263,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) -{ - switch ( message ) - { - case WM_CUT: - case WM_COPY: - case WM_PASTE: - { - wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); - if( win->HandleClipboardEvent( message ) ) - return 0; - break; - } - } - return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam); -} - // ---------------------------------------------------------------------------- // creation // ---------------------------------------------------------------------------- @@ -325,7 +291,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 +309,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 +327,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 +482,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,9 +495,6 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, } #endif // wxUSE_RICHEDIT - gs_wndprocEdit = wxSetWindowProc((HWND)GetHwnd(), - wxTextCtrlWndProc); - return true; } @@ -573,9 +547,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) ) { @@ -637,6 +608,60 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const void wxTextCtrl::SetWindowStyleFlag(long style) { + // changing the alignment of the control dynamically only works under XP + // (but not older Windows version) 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_XP ) + { + 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 @@ -658,6 +683,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 @@ -781,7 +815,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 @@ -789,7 +823,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 @@ -807,7 +841,8 @@ void wxTextCtrl::SetValue(const wxString& value) DiscardEdits(); // still send an event for consistency - SendUpdateEvent(); + if (flags & SetValue_SendEvent) + SendUpdateEvent(); } } @@ -1005,8 +1040,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); @@ -1070,13 +1106,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()); - if ( !ucf.GotUpdate() ) + if ( !ucf.GotUpdate() && (flags & SetValue_SendEvent) ) { SendUpdateEvent(); } @@ -1427,7 +1466,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) @@ -1906,41 +1945,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 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 +2022,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());