X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cf6e951cf203ace5f8cffb91ece08f18f23ccac2..f1872c18e613bb244c465f983ddb41563b15a297:/src/msw/textctrl.cpp?ds=sidebyside diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 6e285fabad..f21acdc2cc 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -38,6 +38,7 @@ #include "wx/intl.h" #include "wx/log.h" #include "wx/app.h" + #include "wx/menu.h" #endif #include "wx/module.h" @@ -149,17 +150,25 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) EVT_CHAR(wxTextCtrl::OnChar) EVT_DROP_FILES(wxTextCtrl::OnDropFiles) +#if wxUSE_RICHEDIT + EVT_RIGHT_UP(wxTextCtrl::OnRightClick) +#endif + EVT_MENU(wxID_CUT, wxTextCtrl::OnCut) EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy) EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste) EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo) EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo) + EVT_MENU(wxID_CLEAR, wxTextCtrl::OnDelete) + EVT_MENU(wxID_SELECTALL, wxTextCtrl::OnSelectAll) EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut) EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy) EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste) EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo) EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo) + EVT_UPDATE_UI(wxID_CLEAR, wxTextCtrl::OnUpdateDelete) + EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll) #ifdef __WIN16__ EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground) #endif @@ -177,9 +186,19 @@ void wxTextCtrl::Init() { #if wxUSE_RICHEDIT m_verRichEdit = 0; +#endif // wxUSE_RICHEDIT + m_privateContextMenu = NULL; m_suppressNextUpdate = FALSE; -#endif // wxUSE_RICHEDIT +} + +wxTextCtrl::~wxTextCtrl() +{ + if (m_privateContextMenu) + { + delete m_privateContextMenu; + m_privateContextMenu = NULL; + } } bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, @@ -362,6 +381,10 @@ void wxTextCtrl::AdoptAttributesFromHWND() m_windowStyle |= wxTE_READONLY; if (style & ES_WANTRETURN) m_windowStyle |= wxTE_PROCESS_ENTER; + if (style & ES_CENTER) + m_windowStyle |= wxTE_CENTRE; + if (style & ES_RIGHT) + m_windowStyle |= wxTE_RIGHT; } WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const @@ -410,11 +433,20 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const if ( style & wxTE_NOHIDESEL ) msStyle |= ES_NOHIDESEL; + if ( style & wxTE_CENTRE ) + msStyle |= ES_CENTER; + + if ( style & wxTE_RIGHT ) + msStyle |= ES_RIGHT; + return msStyle; } void wxTextCtrl::SetWindowStyleFlag(long style) { + if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT ) + style |= wxBORDER_SUNKEN; + #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 @@ -560,7 +592,7 @@ bool wxTextCtrl::StreamIn(const wxString& value, { return FALSE; } -#else +#else // !__WXWINE__ #if wxUSE_UNICODE_MSLU bool wxTextCtrl::StreamIn(const wxString& value, @@ -574,7 +606,7 @@ bool wxTextCtrl::StreamIn(const wxString& value, bool selectionOnly) { // 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 + // text in the non default charset -- otherwise it thinks it knows better // than we do and always shows it in the default one // first get the Windows code page for this encoding @@ -610,6 +642,14 @@ bool 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; + } + if ( !::SendMessage(GetHwnd(), EM_STREAMIN, SF_TEXT | SF_UNICODE | @@ -626,8 +666,7 @@ bool wxTextCtrl::StreamIn(const wxString& value, return TRUE; } -#endif - // __WXWINE__ +#endif // __WXWINE__/!__WXWINE__ #endif // wxUSE_RICHEDIT @@ -690,18 +729,38 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly) if ( !done ) #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 - // rich edit text control sends us 2 EN_CHANGE events when we send - // WM_SETTEXT to it, we have to suppress one of them to make wxTextCtrl - // behaviour consistent - if ( IsRich() ) + IsRich() || +#endif // wxUSE_RICHEDIT + (selectionOnly && HasSelection()) ) { m_suppressNextUpdate = TRUE; } -#endif // wxUSE_RICHEDIT ::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 + ) + { + // Windows already sends an update event for single-line + // controls. + if ( m_windowStyle & wxTE_MULTILINE ) + SendUpdateEvent(); + } } AdjustSpaceLimit(); @@ -712,6 +771,15 @@ void wxTextCtrl::AppendText(const wxString& text) SetInsertionPointEnd(); WriteText(text); + +#if wxUSE_RICHEDIT + if ( 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 + ::SendMessage(GetHwnd(), EM_LINESCROLL, 0, GetNumberOfLines()); + } +#endif // wxUSE_RICHEDIT } void wxTextCtrl::Clear() @@ -725,7 +793,11 @@ void wxTextCtrl::Clear() // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves // but the normal ones don't -- make Clear() behaviour consistent by // always sending this event - SendUpdateEvent(); + + // Windows already sends an update event for single-line + // controls. + if ( m_windowStyle & wxTE_MULTILINE ) + SendUpdateEvent(); } } @@ -776,14 +848,19 @@ void wxTextCtrl::Paste() } } -bool wxTextCtrl::CanCopy() const +bool wxTextCtrl::HasSelection() const { - // Can copy if there's a selection long from, to; GetSelection(&from, &to); return from != to; } +bool wxTextCtrl::CanCopy() const +{ + // Can copy if there's a selection + return HasSelection(); +} + bool wxTextCtrl::CanCut() const { return CanCopy() && IsEditable(); @@ -936,6 +1013,26 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) #if wxUSE_RICHEDIT if ( IsRich() ) { + // richedit 3.0 (i.e. the version living in riched20.dll distributed + // with Windows 2000 and beyond) doesn't honour EM_SCROLLCARET when + // emulating richedit 2.0 unless the control has focus or ECO_NOHIDESEL + // option is set (but it does work ok in richedit 1.0 mode...) + // + // so to make it work we either need to give focus to it here which + // will probably create many problems (dummy focus events; window + // containing the text control being brought to foreground + // unexpectedly; ...) or to temporarily set ECO_NOHIDESEL which may + // create other problems too -- or it might not, so let's try to do it + if ( GetRichVersion() > 1 ) + { + if ( !HasFlag(wxTE_NOHIDESEL) ) + { + ::SendMessage(GetHwnd(), EM_SETOPTIONS, + ECOOP_OR, ECO_NOHIDESEL); + } + //else: everything is already ok + } + CHARRANGE range; range.cpMin = from; range.cpMax = to; @@ -951,6 +1048,16 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) { SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0); } + +#if wxUSE_RICHEDIT + // restore ECO_NOHIDESEL if we changed it + if ( GetRichVersion() > 1 && !HasFlag(wxTE_NOHIDESEL) ) + { + ::SendMessage(GetHwnd(), EM_SETOPTIONS, + ECOOP_AND, ~ECO_NOHIDESEL); + } +#endif // wxUSE_RICHEDIT + #else // Win16 // WPARAM is 0: selection is scrolled into view SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(from, to)); @@ -1276,26 +1383,39 @@ long wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) if ( nMsg == WM_GETDLGCODE ) { - // we always want the chars and the arrows + // 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; - // we may have several different cases: - // 1. normal case: both TAB and ENTER are used for dialog 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 pass - // 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; + 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; + } } return lRc; @@ -1484,8 +1604,10 @@ bool wxTextCtrl::AdjustSpaceLimit() bool wxTextCtrl::AcceptsFocus() const { - // we don't want focus if we can't be edited - return IsEditable() && wxControl::AcceptsFocus(); + // we don't want focus if we can't be edited unless we're a multiline + // control because then it might be still nice to get focus from keyboard + // to be able to scroll it without mouse + return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); } wxSize wxTextCtrl::DoGetBestSize() const @@ -1534,6 +1656,19 @@ void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event)) Redo(); } +void wxTextCtrl::OnDelete(wxCommandEvent& event) +{ + long from, to; + GetSelection(& from, & to); + if (from != -1 && to != -1) + Remove(from, to); +} + +void wxTextCtrl::OnSelectAll(wxCommandEvent& event) +{ + SetSelection(-1, -1); +} + void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event) { event.Enable( CanCut() ); @@ -1559,6 +1694,44 @@ void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) event.Enable( CanRedo() ); } +void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event) +{ + long from, to; + GetSelection(& from, & to); + event.Enable(from != -1 && to != -1 && from != to && IsEditable()) ; +} + +void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event) +{ + event.Enable(GetLastPosition() > 0); +} + +void wxTextCtrl::OnRightClick(wxMouseEvent& event) +{ +#if wxUSE_RICHEDIT + if (IsRich()) + { + if (!m_privateContextMenu) + { + m_privateContextMenu = new wxMenu; + m_privateContextMenu->Append(wxID_UNDO, _("&Undo")); + m_privateContextMenu->Append(wxID_REDO, _("&Redo")); + m_privateContextMenu->AppendSeparator(); + m_privateContextMenu->Append(wxID_CUT, _("Cu&t")); + m_privateContextMenu->Append(wxID_COPY, _("&Copy")); + m_privateContextMenu->Append(wxID_PASTE, _("&Paste")); + m_privateContextMenu->Append(wxID_CLEAR, _("&Delete")); + m_privateContextMenu->AppendSeparator(); + m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All")); + } + PopupMenu(m_privateContextMenu, event.GetPosition()); + return; + } + else +#endif + event.Skip(); +} + // the rest of the file only deals with the rich edit controls #if wxUSE_RICHEDIT