X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a290fa5a7deebe9d96c0c0089d18e27d4bd9b624..c2f7cc71ef2188967e6a4dc90106fd716aa23be9:/src/univ/textctrl.cpp diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index 84f5c7d78b..2edc5b0afe 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: univ/textctrl.cpp +// Name: src/univ/textctrl.cpp // Purpose: wxTextCtrl // Author: Vadim Zeitlin // Modified by: @@ -47,7 +47,7 @@ is true in which case a single LINE may correspond to multiple ROWs. A text position is an unsigned int (which for reasons of compatibility is - still a long) from 0 to GetLastPosition() inclusive. The positions + still a long as wxTextPos) from 0 to GetLastPosition() inclusive. The positions correspond to the gaps between the letters so the position 0 is just before the first character and the last position is the one beyond the last character. For an empty text control GetLastPosition() returns 0. @@ -117,10 +117,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "univtextctrl.h" -#endif - #include "wx/wxprec.h" #ifdef __BORLANDC__ @@ -129,16 +125,17 @@ #if wxUSE_TEXTCTRL -#include +#include "wx/textctrl.h" #ifndef WX_PRECOMP #include "wx/log.h" - #include "wx/dcclient.h" #include "wx/validate.h" - #include "wx/textctrl.h" + #include "wx/dataobj.h" #endif +#include + #include "wx/clipbrd.h" #include "wx/textfile.h" @@ -152,26 +149,46 @@ #include "wx/cmdproc.h" -#if wxUSE_CLIPBOARD -#include "wx/dataobj.h" -#endif - -// turn extra wxTextCtrl-specific debugging on/off -#define WXDEBUG_TEXT - -// turn wxTextCtrl::Replace() debugging on (slows down code a *lot*!) -#define WXDEBUG_TEXT_REPLACE +#if wxDEBUG_LEVEL >= 2 + // turn extra wxTextCtrl-specific debugging on/off + #define WXDEBUG_TEXT -#ifndef __WXDEBUG__ - #undef WXDEBUG_TEXT - #undef WXDEBUG_TEXT_REPLACE -#endif + // turn wxTextCtrl::Replace() debugging on (slows down code a *lot*!) + #define WXDEBUG_TEXT_REPLACE +#endif // wxDEBUG_LEVEL >= 2 // wxStringTokenize only needed for debug checks #ifdef WXDEBUG_TEXT_REPLACE #include "wx/tokenzr.h" #endif // WXDEBUG_TEXT_REPLACE +// ---------------------------------------------------------------------------- +// wxStdTextCtrlInputHandler: this control handles only the mouse/kbd actions +// common to Win32 and GTK, platform-specific things are implemented elsewhere +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxStdTextCtrlInputHandler : public wxStdInputHandler +{ +public: + wxStdTextCtrlInputHandler(wxInputHandler *inphand); + + virtual bool HandleKey(wxInputConsumer *consumer, + const wxKeyEvent& event, + bool pressed); + virtual bool HandleMouse(wxInputConsumer *consumer, + const wxMouseEvent& event); + virtual bool HandleMouseMove(wxInputConsumer *consumer, + const wxMouseEvent& event); + virtual bool HandleFocus(wxInputConsumer *consumer, const wxFocusEvent& event); + +protected: + // get the position of the mouse click + static wxTextPos HitTest(const wxTextCtrl *text, const wxPoint& pos); + + // capture data + wxTextCtrl *m_winCapture; +}; + // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -197,7 +214,7 @@ static inline void OrderPositions(wxTextPos& from, wxTextPos& to) // the value which is never used for text position, even not -1 which is // sometimes used for some special meaning -static const wxTextPos INVALID_POS_VALUE = -2; +static const wxTextPos INVALID_POS_VALUE = wxInvalidTextCoord; // overlap between pages (when using PageUp/Dn) in lines static const size_t PAGE_OVERLAP_IN_LINES = 1; @@ -207,7 +224,7 @@ static const size_t PAGE_OVERLAP_IN_LINES = 1; // ---------------------------------------------------------------------------- // the data only used by single line text controls -struct WXDLLEXPORT wxTextSingleLineData +struct wxTextSingleLineData { // the position of the first visible pixel and the first visible column wxCoord m_ofsHorz; @@ -231,7 +248,7 @@ struct WXDLLEXPORT wxTextSingleLineData }; // the data only used by multi line text controls -struct WXDLLEXPORT wxTextMultiLineData +struct wxTextMultiLineData { // the lines of text wxArrayString m_lines; @@ -280,7 +297,7 @@ struct WXDLLEXPORT wxTextMultiLineData }; // the data only used by multi line text controls in line wrap mode -class WXDLLEXPORT wxWrappedLineData +class wxWrappedLineData { // these functions set all our values, so give them access to them friend void wxTextCtrl::LayoutLine(wxTextCoord line, @@ -440,7 +457,7 @@ WX_DECLARE_OBJARRAY(wxWrappedLineData, wxArrayWrappedLinesData); #include "wx/arrimpl.cpp" WX_DEFINE_OBJARRAY(wxArrayWrappedLinesData); -struct WXDLLEXPORT wxTextWrappedData : public wxTextMultiLineData +struct wxTextWrappedData : public wxTextMultiLineData { // the width of the column to the right of the text rect used for the // indicator mark display for the wrapped lines @@ -610,13 +627,13 @@ private: // implementation // ============================================================================ -BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) +BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) EVT_CHAR(wxTextCtrl::OnChar) EVT_SIZE(wxTextCtrl::OnSize) END_EVENT_TABLE() -IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase) // ---------------------------------------------------------------------------- // creation @@ -630,6 +647,7 @@ void wxTextCtrl::Init() m_isModified = false; m_isEditable = true; + m_wrapLines = false; m_posLast = m_curPos = @@ -639,9 +657,6 @@ void wxTextCtrl::Init() m_heightLine = m_widthAvg = -1; - // init wxScrollHelper - SetWindow(this); - // init the undo manager m_cmdProcessor = new wxTextCtrlCommandProcessor(this); @@ -669,23 +684,27 @@ bool wxTextCtrl::Create(wxWindow *parent, style |= wxALWAYS_SHOW_SB; } - // wxTE_WORDWRAP is 0 for now so we don't need the code below -#if 0 - if ( style & wxTE_WORDWRAP ) - { - // wrapping words means wrapping, hence no horz scrollbar - style &= ~wxHSCROLL; - } -#endif // 0 + // wrapping style: wxTE_DONTWRAP == wxHSCROLL so if it's _not_ given, + // we won't have horizontal scrollbar automatically, no need to do + // anything // TODO: support wxTE_NO_VSCROLL (?) // create data object for normal multiline or for controls with line // wrap as needed if ( style & wxHSCROLL ) + { m_data.mdata = new wxTextMultiLineData; - else + } + else // we must wrap lines if we don't have horizontal scrollbar + { + // NB: we can't rely on HasFlag(wxHSCROLL) as the flags can change + // later and even wxWindow::Create() itself temporarily resets + // wxHSCROLL in wxUniv, so remember that we have a wrapped data + // and not just a multi line data in a separate variable + m_wrapLines = true; m_data.wdata = new wxTextWrappedData; + } } else { @@ -695,7 +714,7 @@ bool wxTextCtrl::Create(wxWindow *parent, // create data object for single line controls m_data.sdata = new wxTextSingleLineData; } - + #if wxUSE_TWO_WINDOWS if ((style & wxBORDER_MASK) == 0) style |= wxBORDER_SUNKEN; @@ -728,7 +747,7 @@ bool wxTextCtrl::Create(wxWindow *parent, RecalcFontMetrics(); SetValue(value); - SetBestSize(size); + SetInitialSize(size); m_isEditable = !(style & wxTE_READONLY); @@ -766,22 +785,25 @@ wxTextCtrl::~wxTextCtrl() // set/get the value // ---------------------------------------------------------------------------- -void wxTextCtrl::SetValue(const wxString& value) +void wxTextCtrl::DoSetValue(const wxString& value, int flags) { - if ( IsSingleLine() && (value == GetValue()) ) + if ( value != GetValue() ) { - // nothing changed - return; - } + EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent)); - Replace(0, GetLastPosition(), value); + Replace(0, GetLastPosition(), value); - if ( IsSingleLine() ) + if ( IsSingleLine() ) + { + SetInsertionPoint(0); + } + } + else // nothing changed { - SetInsertionPoint(0); + // still send event for consistency + if ( flags & SetValue_SendEvent ) + SendTextUpdatedEvent(); } - - // TODO: should we generate the event or not, finally? } const wxArrayString& wxTextCtrl::GetLines() const @@ -794,7 +816,7 @@ size_t wxTextCtrl::GetLineCount() const return MData().m_lines.GetCount(); } -wxString wxTextCtrl::GetValue() const +wxString wxTextCtrl::DoGetValue() const { // for multiline controls we don't always store the total value but only // recompute it when asked - and to invalidate it we just empty it in @@ -821,7 +843,7 @@ wxString wxTextCtrl::GetValue() const void wxTextCtrl::Clear() { - SetValue(_T("")); + SetValue(wxEmptyString); } bool wxTextCtrl::ReplaceLine(wxTextCoord line, @@ -1241,6 +1263,9 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) // now call it to do the rest (not related to refreshing) ClearSelection(); + + if ( EventsAllowed() ) + SendTextUpdatedEvent(); } void wxTextCtrl::Remove(wxTextPos from, wxTextPos to) @@ -1249,7 +1274,7 @@ void wxTextCtrl::Remove(wxTextPos from, wxTextPos to) // if necessary OrderPositions(from, to); - Replace(from, to, _T("")); + Replace(from, to, wxEmptyString); } void wxTextCtrl::WriteText(const wxString& text) @@ -1421,8 +1446,12 @@ wxString wxTextCtrl::GetSelectionText() const void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to) { // selecting till -1 is the same as selecting to the end - if ( to == -1 && from != -1 ) + if ( to == -1 ) { + // and selecting (-1, -1) range is the same as selecting everything, by + // convention + if ( from == -1 ) + from = 0; to = GetLastPosition(); } @@ -1650,8 +1679,8 @@ wxString wxTextCtrl::GetLineText(wxTextCoord line) const { //this is called during DoGetBestSize if (line == 0 && GetLineCount() == 0) return wxEmptyString ; - - wxCHECK_MSG( (size_t)line < GetLineCount(), _T(""), + + wxCHECK_MSG( (size_t)line < GetLineCount(), wxEmptyString, _T("line index out of range") ); return GetLines()[line]; @@ -1670,7 +1699,7 @@ wxTextPos wxTextCtrl::XYToPosition(wxTextCoord x, wxTextCoord y) const // if they are out of range if ( IsSingleLine() ) { - return x > GetLastPosition() || y > 0 ? wxDefaultCoord : x; + return ( x > GetLastPosition() || y > 0 ) ? wxOutOfRangeTextCoord : x; } else // multiline { @@ -1938,7 +1967,7 @@ void wxTextCtrl::ShowPosition(wxTextPos pos) { // finding the last line is easy if each line has exactly // one row - yEnd = yStart + rectText.height / GetLineHeight() - 1; + yEnd = yStart + rectText.height / GetLineHeight(); } if ( yEnd < y ) @@ -2360,7 +2389,7 @@ wxSize wxTextCtrl::DoGetBestClientSize() const void wxTextCtrl::UpdateTextRect() { - wxRect rectTotal(wxPoint(0, 0), GetClientSize()); + wxRect rectTotal(GetClientSize()); wxCoord *extraSpace = WrapLines() ? &WData().m_widthMark : NULL; m_rectText = GetRenderer()->GetTextClientArea(this, rectTotal, extraSpace); @@ -2391,7 +2420,7 @@ void wxTextCtrl::UpdateTextRect() WData().m_rowFirstInvalid = 0; // increase timestamp: this means that the lines which had been - // laid out before will be relayd out the next time LayoutLines() + // laid out before will be relaid out the next time LayoutLines() // is called because their timestamp will be smaller than the // current one WData().m_timestamp++; @@ -2415,9 +2444,12 @@ void wxTextCtrl::UpdateLastVisible() { case wxTE_HT_BEYOND: // everything is visible + SData().m_ofsHorz = 0; + + SData().m_colStart = 0; SData().m_colLastVisible = text.length(); - // calc it below + // calculate it below SData().m_posLastVisible = -1; break; @@ -2695,7 +2727,7 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, //else: we can just see it // wrap at any character or only at words boundaries? - if ( !(GetWindowStyle() & wxTE_LINEWRAP) ) + if ( !(GetWindowStyle() & wxTE_CHARWRAP) ) { // find the (last) not word char before this word wxTextCoord colWordStart; @@ -3235,7 +3267,7 @@ bool wxTextCtrl::GetLineAndRow(wxTextCoord row, fine for vertical scrolling as all lines have the same height but is rather ugly for horizontal scrolling if proportional font is used. This is why we manually update and use SData().m_ofsHorz which contains the length of the string - which is hidden beyond the left borde. An important property of text + which is hidden beyond the left border. An important property of text controls using this kind of scrolling is that an entire number of characters is always shown and that parts of characters never appear on display - neither in the leftmost nor rightmost positions. @@ -3250,7 +3282,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos) // pos is the logical position to show - // SData().m_ofsHorz is the fisrt logical position shown + // SData().m_ofsHorz is the first logical position shown if ( pos < SData().m_ofsHorz ) { // scroll backwards @@ -3585,8 +3617,12 @@ void wxTextCtrl::UpdateScrollbars() if ( scrollRangeXOld ) { - x *= scrollRangeX - m_rectText.width / charWidth; - x /= scrollRangeXOld - m_rectText.width / charWidth; + const int w = m_rectText.width / charWidth; + if ( w != scrollRangeXOld ) + { + x *= scrollRangeX - w; + x /= scrollRangeXOld - w; + } Scroll(x, y); } @@ -3719,7 +3755,7 @@ void wxTextCtrl::RefreshTextRange(wxTextPos start, wxTextPos end) { // intermediate line or the last one but we need to refresh it // until the end anyhow - do it - posCount = wxSTRING_MAXLEN; + posCount = wxString::npos; } else // last line { @@ -4146,7 +4182,7 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer) // the update region is in window coords and text area is in the client // ones, so it must be shifted before computing intersection wxRegion rgnUpdate = GetUpdateRegion(); - + wxRect rectTextArea = GetRealTextArea(); wxPoint pt = GetClientAreaOrigin(); wxRect rectTextAreaAdjusted = rectTextArea; @@ -4163,6 +4199,7 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer) // FIXME: is this really a bug in wxMSW? rectTextArea.width--; #endif // __WXMSW__ + dc.DestroyClippingRegion(); dc.SetClippingRegion(rectTextArea); // adjust for scrolling @@ -4270,14 +4307,11 @@ void wxTextCtrl::CreateCaret() { // FIXME use renderer caret = new wxCaret(this, 1, GetLineHeight()); -#ifndef __WXMSW__ - caret->SetBlinkTime(0); -#endif // __WXMSW__ } else { // read only controls don't have the caret - caret = (wxCaret *)NULL; + caret = NULL; } // SetCaret() will delete the old caret if any @@ -4396,7 +4430,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, // the command this action corresponds to or NULL if this action doesn't // change text at all or can't be undone - wxTextCtrlCommand *command = (wxTextCtrlCommand *)NULL; + wxTextCtrlCommand *command = NULL; wxString action; bool del = false, @@ -4680,7 +4714,6 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); InitCommandEvent(event); - event.SetString(GetValue()); GetEventHandler()->ProcessEvent(event); // as the text changed... @@ -4696,6 +4729,9 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) if ( !event.HasModifiers() ) { int keycode = event.GetKeyCode(); +#if wxUSE_UNICODE + wxChar unicode = event.GetUnicodeKey(); +#endif if ( keycode == WXK_RETURN ) { if ( IsSingleLine() || (GetWindowStyle() & wxTE_PROCESS_ENTER) ) @@ -4717,16 +4753,32 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) // skip event.Skip() below return; } +#if wxUSE_UNICODE + else if (unicode > 0) + { + PerformAction(wxACTION_TEXT_INSERT, -1, unicode); + + return; + } +#endif } -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL >= 2 // Ctrl-R refreshes the control in debug mode else if ( event.ControlDown() && event.GetKeyCode() == 'r' ) Refresh(); -#endif // __WXDEBUG__ +#endif // wxDEBUG_LEVEL >= 2 event.Skip(); } +/* static */ +wxInputHandler *wxTextCtrl::GetStdInputHandler(wxInputHandler *handlerDef) +{ + static wxStdTextCtrlInputHandler s_handler(handlerDef); + + return &s_handler; +} + // ---------------------------------------------------------------------------- // wxStdTextCtrlInputHandler // ---------------------------------------------------------------------------- @@ -4734,7 +4786,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) wxStdTextCtrlInputHandler::wxStdTextCtrlInputHandler(wxInputHandler *inphand) : wxStdInputHandler(inphand) { - m_winCapture = (wxTextCtrl *)NULL; + m_winCapture = NULL; } /* static */ @@ -4816,14 +4868,12 @@ bool wxStdTextCtrlInputHandler::HandleKey(wxInputConsumer *consumer, break; case WXK_PAGEDOWN: - case WXK_NEXT: // we don't map Ctrl-PgUp/Dn to anything special - what should it // to? for now, it's the same as without control action << wxACTION_TEXT_PAGE_DOWN; break; case WXK_PAGEUP: - case WXK_PRIOR: action << wxACTION_TEXT_PAGE_UP; break; @@ -4913,7 +4963,7 @@ bool wxStdTextCtrlInputHandler::HandleMouse(wxInputConsumer *consumer, m_winCapture->ShowCaret(); m_winCapture->ReleaseMouse(); - m_winCapture = (wxTextCtrl *)NULL; + m_winCapture = NULL; } }