X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e6feb95a79834836e88143b15d9f424ebe79621..a0b48f2651beaccb480cc0a6e5ba8e8b3cfa0346:/src/univ/textctrl.cpp diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index 98b53bda8a..1c2fa3c814 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: univ/textctrl.cpp +// Name: src/univ/textctrl.cpp // Purpose: wxTextCtrl // Author: Vadim Zeitlin // Modified by: // Created: 15.09.00 // RCS-ID: $Id$ -// Copyright: (c) 2000 Vadim Zeitlin -// Licence: wxWindows license +// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// /* @@ -44,10 +44,10 @@ Everywhere in this file LINE refers to a logical line of text, and ROW to a physical line of text on the display. They are the same unless WrapLines() - is TRUE in which case a single LINE may correspond to multiple ROWs. + 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 // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "univtextctrl.h" -#endif - #include "wx/wxprec.h" #ifdef __BORLANDC__ @@ -129,15 +125,19 @@ #if wxUSE_TEXTCTRL +#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" #include "wx/caret.h" @@ -149,22 +149,46 @@ #include "wx/cmdproc.h" -// 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 // ---------------------------------------------------------------------------- @@ -185,12 +209,12 @@ static inline void OrderPositions(wxTextPos& from, wxTextPos& to) // ---------------------------------------------------------------------------- // names of text ctrl commands -#define wxTEXT_COMMAND_INSERT _T("insert") -#define wxTEXT_COMMAND_REMOVE _T("remove") +#define wxTEXT_COMMAND_INSERT wxT("insert") +#define wxTEXT_COMMAND_REMOVE wxT("remove") // 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; @@ -200,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; @@ -224,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; @@ -263,7 +287,7 @@ struct WXDLLEXPORT wxTextMultiLineData m_scrollRangeY = 0; m_updateScrollbarX = - m_updateScrollbarY = FALSE; + m_updateScrollbarY = false; m_widthMax = -1; m_lineLongest = 0; @@ -273,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, @@ -291,7 +315,7 @@ public: // for the first one) wxTextCoord GetRowStart(wxTextCoord row) const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return row ? m_rowsStart[row - 1] : 0; } @@ -301,7 +325,7 @@ public: // be given to us) wxTextCoord GetRowLength(wxTextCoord row, wxTextCoord lenLine) const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); // note that m_rowsStart[row] is the same as GetRowStart(row + 1) (but // slightly more efficient) and lenLine is the same as the start of the @@ -313,7 +337,7 @@ public: // return the width of the row in pixels wxCoord GetRowWidth(wxTextCoord row) const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowsWidth[row]; } @@ -321,7 +345,7 @@ public: // return the number of rows size_t GetRowCount() const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowsStart.GetCount() + 1; } @@ -329,7 +353,7 @@ public: // return the number of additional (i.e. after the first one) rows size_t GetExtraRowCount() const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowsStart.GetCount(); } @@ -337,7 +361,7 @@ public: // return the first row of this line wxTextCoord GetFirstRow() const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowFirst; } @@ -345,7 +369,7 @@ public: // return the first row of the next line wxTextCoord GetNextRow() const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowFirst + m_rowsStart.GetCount() + 1; } @@ -353,21 +377,21 @@ public: // this just provides direct access to m_rowsStart aerray for efficiency wxTextCoord GetExtraRowStart(wxTextCoord row) const { - wxASSERT_MSG( IsValid(), _T("this line hadn't been laid out") ); + wxASSERT_MSG( IsValid(), wxT("this line hadn't been laid out") ); return m_rowsStart[row]; } // this code is unused any longer #if 0 - // return TRUE if the column is in the start of the last row (hence the row + // return true if the column is in the start of the last row (hence the row // it is in is not wrapped) bool IsLastRow(wxTextCoord colRowStart) const { return colRowStart == GetRowStart(m_rowsStart.GetCount()); } - // return TRUE if the column is the last column of the row starting in + // return true if the column is the last column of the row starting in // colRowStart bool IsLastColInRow(wxTextCoord colRowStart, wxTextCoord colRowEnd, @@ -384,16 +408,16 @@ public: : GetRowStart(n + 1); wxASSERT_MSG( colRowEnd < colNextRowStart, - _T("this column is not in this row at all!") ); + wxT("this column is not in this row at all!") ); return colRowEnd == colNextRowStart - 1; } } // caller got it wrong - wxFAIL_MSG( _T("this column is not in the start of the row!") ); + wxFAIL_MSG( wxT("this column is not in the start of the row!") ); - return FALSE; + return false; } #endif // 0 @@ -433,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 @@ -480,7 +504,7 @@ struct WXDLLEXPORT wxTextWrappedData : public wxTextMultiLineData // ---------------------------------------------------------------------------- /* - We use custom versions of wxWindows command processor to implement undo/redo + We use custom versions of wxWidgets command processor to implement undo/redo as we want to avoid storing the backpointer to wxTextCtrl in wxCommand itself: this is a waste of memory as all commands in the given command processor always have the same associated wxTextCtrl and so it makes sense @@ -494,12 +518,12 @@ struct WXDLLEXPORT wxTextWrappedData : public wxTextMultiLineData class wxTextCtrlCommand : public wxCommand { public: - wxTextCtrlCommand(const wxString& name) : wxCommand(TRUE, name) { } + wxTextCtrlCommand(const wxString& name) : wxCommand(true, name) { } // we don't use these methods as they don't make sense for us as we need a // wxTextCtrl to be applied - virtual bool Do() { wxFAIL_MSG(_T("shouldn't be called")); return FALSE; } - virtual bool Undo() { wxFAIL_MSG(_T("shouldn't be called")); return FALSE; } + virtual bool Do() { wxFAIL_MSG(wxT("shouldn't be called")); return false; } + virtual bool Undo() { wxFAIL_MSG(wxT("shouldn't be called")); return false; } // instead, our command processor uses these methods virtual bool Do(wxTextCtrl *text) = 0; @@ -521,6 +545,8 @@ public: virtual bool CanUndo() const; virtual bool Do(wxTextCtrl *text); + virtual bool Do() { return wxTextCtrlCommand::Do(); } + virtual bool Undo() { return wxTextCtrlCommand::Undo(); } virtual bool Undo(wxTextCtrl *text); private: @@ -544,6 +570,8 @@ public: virtual bool CanUndo() const; virtual bool Do(wxTextCtrl *text); + virtual bool Do() { return wxTextCtrlCommand::Do(); } + virtual bool Undo() { return wxTextCtrlCommand::Undo(); } virtual bool Undo(wxTextCtrl *text); private: @@ -561,7 +589,7 @@ class wxTextCtrlCommandProcessor : public wxCommandProcessor public: wxTextCtrlCommandProcessor(wxTextCtrl *text) { - m_compressInserts = FALSE; + m_compressInserts = false; m_text = text; } @@ -570,7 +598,7 @@ public: virtual void Store(wxCommand *command); // stop compressing insert commands when this is called - void StopCompressing() { m_compressInserts = FALSE; } + void StopCompressing() { m_compressInserts = false; } // accessors wxTextCtrl *GetTextCtrl() const { return m_text; } @@ -590,7 +618,7 @@ private: // the control we're associated with wxTextCtrl *m_text; - // if the flag is TRUE we're compressing subsequent insert commands into + // if the flag is true we're compressing subsequent insert commands into // one so that the entire typing could be undone in one call to Undo() bool m_compressInserts; }; @@ -599,15 +627,13 @@ private: // implementation // ============================================================================ -BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) +BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) EVT_CHAR(wxTextCtrl::OnChar) EVT_SIZE(wxTextCtrl::OnSize) - - EVT_IDLE(wxTextCtrl::OnIdle) END_EVENT_TABLE() -IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase) // ---------------------------------------------------------------------------- // creation @@ -619,8 +645,9 @@ void wxTextCtrl::Init() m_selStart = m_selEnd = -1; - m_isModified = FALSE; - m_isEditable = TRUE; + m_isModified = false; + m_isEditable = true; + m_wrapLines = false; m_posLast = m_curPos = @@ -630,9 +657,6 @@ void wxTextCtrl::Init() m_heightLine = m_widthAvg = -1; - // init wxScrollHelper - SetWindow(this); - // init the undo manager m_cmdProcessor = new wxTextCtrlCommandProcessor(this); @@ -660,20 +684,27 @@ bool wxTextCtrl::Create(wxWindow *parent, style |= wxALWAYS_SHOW_SB; } - if ( style & wxTE_WORDWRAP ) - { - // wrapping words means wrapping, hence no horz scrollbar - style &= ~wxHSCROLL; - } + // 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 { @@ -684,10 +715,15 @@ bool wxTextCtrl::Create(wxWindow *parent, m_data.sdata = new wxTextSingleLineData; } +#if wxUSE_TWO_WINDOWS + if ((style & wxBORDER_MASK) == 0) + style |= wxBORDER_SUNKEN; +#endif + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) { - return FALSE; + return false; } SetCursor(wxCURSOR_IBEAM); @@ -706,12 +742,12 @@ bool wxTextCtrl::Create(wxWindow *parent, // we might support it but it's quite useless and other ports don't // support it anyhow wxASSERT_MSG( !(style & wxTE_PASSWORD), - _T("wxTE_PASSWORD can't be used with multiline ctrls") ); + wxT("wxTE_PASSWORD can't be used with multiline ctrls") ); } RecalcFontMetrics(); SetValue(value); - SetBestSize(size); + SetInitialSize(size); m_isEditable = !(style & wxTE_READONLY); @@ -720,11 +756,14 @@ bool wxTextCtrl::Create(wxWindow *parent, // we can't show caret right now as we're not shown yet and so it would // result in garbage on the screen - we'll do it after first OnPaint() - m_hasCaret = FALSE; + m_hasCaret = false; CreateInputHandler(wxINP_HANDLER_TEXTCTRL); - return TRUE; + wxSizeEvent sizeEvent(GetSize(), GetId()); + GetEventHandler()->ProcessEvent(sizeEvent); + + return true; } wxTextCtrl::~wxTextCtrl() @@ -746,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 @@ -774,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 @@ -792,7 +834,7 @@ wxString wxTextCtrl::GetValue() const size_t count = lines.GetCount(); for ( size_t n = 1; n < count; n++ ) { - self->m_value << _T('\n') << lines[n]; + self->m_value << wxT('\n') << lines[n]; } } @@ -801,7 +843,7 @@ wxString wxTextCtrl::GetValue() const void wxTextCtrl::Clear() { - SetValue(_T("")); + SetValue(wxEmptyString); } bool wxTextCtrl::ReplaceLine(wxTextCoord line, @@ -857,7 +899,7 @@ bool wxTextCtrl::ReplaceLine(wxTextCoord line, } // the number of rows changed - return TRUE; + return true; } } else // no line wrap @@ -866,7 +908,7 @@ bool wxTextCtrl::ReplaceLine(wxTextCoord line, } // the number of rows didn't change - return FALSE; + return false; } void wxTextCtrl::RemoveLine(wxTextCoord line) @@ -907,7 +949,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) !PositionToXY(from, &colStart, &lineStart) || !PositionToXY(to, &colEnd, &lineEnd) ) { - wxFAIL_MSG(_T("invalid range in wxTextCtrl::Replace")); + wxFAIL_MSG(wxT("invalid range in wxTextCtrl::Replace")); return; } @@ -983,7 +1025,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) // as if it does we need to refresh everything below the changed // text (it will be shifted...) and we can avoid it if there is no // row relayout - bool rowsNumberChanged = FALSE; + bool rowsNumberChanged = false; // (1) join lines const wxArrayString& linesOld = GetLines(); @@ -994,7 +1036,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) if ( line > lineStart ) { // from the previous line - textOrig += _T('\n'); + textOrig += wxT('\n'); } textOrig += linesOld[line]; @@ -1015,7 +1057,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) if ( (size_t)colStart == linesOld[lineStart].length() ) { // text appended, refresh just enough to show the new text - widthNewText = GetTextWidth(text.BeforeFirst(_T('\n'))); + widthNewText = GetTextWidth(text.BeforeFirst(wxT('\n'))); } else // text inserted, refresh till the end of line { @@ -1041,7 +1083,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) for ( const wxChar *p = textNew.c_str(); ; p++ ) { // end of line/text? - if ( !*p || *p == _T('\n') ) + if ( !*p || *p == wxT('\n') ) { lines.Add(wxString(curLineStart, p)); if ( !*p ) @@ -1054,7 +1096,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) #ifdef WXDEBUG_TEXT_REPLACE // (3a) all empty tokens should be counted as replacing with "foo" and // with "foo\n" should have different effects - wxArrayString lines2 = wxStringTokenize(textNew, _T("\n"), + wxArrayString lines2 = wxStringTokenize(textNew, wxT("\n"), wxTOKEN_RET_EMPTY_ALL); if ( lines2.IsEmpty() ) @@ -1063,10 +1105,10 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) } wxASSERT_MSG( lines.GetCount() == lines2.GetCount(), - _T("Replace() broken") ); + wxT("Replace() broken") ); for ( size_t n = 0; n < lines.GetCount(); n++ ) { - wxASSERT_MSG( lines[n] == lines2[n], _T("Replace() broken") ); + wxASSERT_MSG( lines[n] == lines2[n], wxT("Replace() broken") ); } #endif // WXDEBUG_TEXT_REPLACE @@ -1091,7 +1133,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) // we have the replacement line for this one if ( ReplaceLine(line, lines[nReplaceLine]) ) { - rowsNumberChanged = TRUE; + rowsNumberChanged = true; } UpdateMaxWidth(line); @@ -1100,13 +1142,13 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) { // (4b) delete all extra lines (note that we need to delete // them backwards because indices shift while we do it) - bool deletedLongestLine = FALSE; + bool deletedLongestLine = false; for ( wxTextCoord lineDel = lineEnd; lineDel >= line; lineDel-- ) { if ( lineDel == MData().m_lineLongest ) { // we will need to recalc the max line width - deletedLongestLine = TRUE; + deletedLongestLine = true; } RemoveLine(lineDel); @@ -1118,7 +1160,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) } // even the line number changed - rowsNumberChanged = TRUE; + rowsNumberChanged = true; // update line to exit the loop line = lineEnd + 1; @@ -1129,7 +1171,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) if ( nReplaceLine < nReplaceCount ) { // even the line number changed - rowsNumberChanged = TRUE; + rowsNumberChanged = true; do { @@ -1187,7 +1229,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) RefreshLineRange(lineEnd + 1, 0); // the vert scrollbar might [dis]appear - MData().m_updateScrollbarY = TRUE; + MData().m_updateScrollbarY = true; } // must recalculate it - will do later @@ -1197,7 +1239,7 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) #ifdef WXDEBUG_TEXT_REPLACE // optimized code above should give the same result as straightforward // computation in the beginning - wxASSERT_MSG( GetValue() == textTotalNew, _T("error in Replace()") ); + wxASSERT_MSG( GetValue() == textTotalNew, wxT("error in Replace()") ); #endif // WXDEBUG_TEXT_REPLACE // update the current position: note that we always put the cursor at the @@ -1221,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) @@ -1229,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) @@ -1253,7 +1298,7 @@ void wxTextCtrl::AppendText(const wxString& text) void wxTextCtrl::SetInsertionPoint(wxTextPos pos) { wxCHECK_RET( pos >= 0 && pos <= GetLastPosition(), - _T("insertion point position out of range") ); + wxT("insertion point position out of range") ); // don't do anything if it didn't change if ( pos != m_curPos ) @@ -1283,7 +1328,7 @@ void wxTextCtrl::InitInsertionPoint() void wxTextCtrl::MoveInsertionPoint(wxTextPos pos) { wxASSERT_MSG( pos >= 0 && pos <= GetLastPosition(), - _T("DoSetInsertionPoint() can only be called with valid pos") ); + wxT("DoSetInsertionPoint() can only be called with valid pos") ); m_curPos = pos; PositionToXY(m_curPos, &m_curCol, &m_curRow); @@ -1333,7 +1378,7 @@ wxTextPos wxTextCtrl::GetLastPosition() const } // more probable reason of this would be to forget to update m_posLast - wxASSERT_MSG( pos == m_posLast, _T("bug in GetLastPosition()") ); + wxASSERT_MSG( pos == m_posLast, wxT("bug in GetLastPosition()") ); #endif // WXDEBUG_TEXT pos = m_posLast; @@ -1381,12 +1426,12 @@ wxString wxTextCtrl::GetSelectionText() const { // take the end of the first line sel = GetLines()[lineStart].c_str() + colStart; - sel += _T('\n'); + sel += wxT('\n'); // all intermediate ones for ( wxTextCoord line = lineStart + 1; line < lineEnd; line++ ) { - sel << GetLines()[line] << _T('\n'); + sel << GetLines()[line] << wxT('\n'); } // and the start of the last one @@ -1401,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(); } @@ -1412,10 +1461,14 @@ void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to) } else // valid sel range { + // remember the 'to' position as the current position, used to move the + // caret there later + wxTextPos toOrig = to; + OrderPositions(from, to); wxCHECK_RET( to <= GetLastPosition(), - _T("invalid range in wxTextCtrl::SetSelection") ); + wxT("invalid range in wxTextCtrl::SetSelection") ); if ( from != m_selStart || to != m_selEnd ) { @@ -1427,7 +1480,7 @@ void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to) m_selStart = from; m_selEnd = to; - wxLogTrace(_T("text"), _T("Selection range is %ld-%ld"), + wxLogTrace(wxT("text"), wxT("Selection range is %ld-%ld"), m_selStart, m_selEnd); // refresh only the part of text which became (un)selected if @@ -1457,8 +1510,8 @@ void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to) } //else: nothing to do - // the insertion point is put at the end of selection - DoSetInsertionPoint(to); + // the insertion point is put at the location where the caret was moved + DoSetInsertionPoint(toOrig); } } @@ -1502,7 +1555,7 @@ bool wxTextCtrl::GetSelectedPartOfLine(wxTextCoord line, if ( !HasSelection() ) { // no selection at all, hence no selection in this line - return FALSE; + return false; } wxTextCoord lineStart, colStart; @@ -1510,7 +1563,7 @@ bool wxTextCtrl::GetSelectedPartOfLine(wxTextCoord line, if ( lineStart > line ) { // this line is entirely above the selection - return FALSE; + return false; } wxTextCoord lineEnd, colEnd; @@ -1518,7 +1571,7 @@ bool wxTextCtrl::GetSelectedPartOfLine(wxTextCoord line, if ( lineEnd < line ) { // this line is entirely below the selection - return FALSE; + return false; } if ( line == lineStart ) @@ -1543,7 +1596,7 @@ bool wxTextCtrl::GetSelectedPartOfLine(wxTextCoord line, *end = GetLineLength(line); } - return TRUE; + return true; } // ---------------------------------------------------------------------------- @@ -1561,9 +1614,14 @@ bool wxTextCtrl::IsEditable() const return m_isEditable && IsEnabled(); } +void wxTextCtrl::MarkDirty() +{ + m_isModified = true; +} + void wxTextCtrl::DiscardEdits() { - m_isModified = FALSE; + m_isModified = false; } void wxTextCtrl::SetEditable(bool editable) @@ -1596,14 +1654,14 @@ int wxTextCtrl::GetLineLength(wxTextCoord line) const { if ( IsSingleLine() ) { - wxASSERT_MSG( line == 0, _T("invalid GetLineLength() parameter") ); + wxASSERT_MSG( line == 0, wxT("invalid GetLineLength() parameter") ); return m_value.length(); } else // multiline { wxCHECK_MSG( (size_t)line < GetLineCount(), -1, - _T("line index out of range") ); + wxT("line index out of range") ); return GetLines()[line].length(); } @@ -1613,14 +1671,17 @@ wxString wxTextCtrl::GetLineText(wxTextCoord line) const { if ( IsSingleLine() ) { - wxASSERT_MSG( line == 0, _T("invalid GetLineLength() parameter") ); + wxASSERT_MSG( line == 0, wxT("invalid GetLineLength() parameter") ); return m_value; } else // multiline { - wxCHECK_MSG( (size_t)line < GetLineCount(), _T(""), - _T("line index out of range") ); + //this is called during DoGetBestSize + if (line == 0 && GetLineCount() == 0) return wxEmptyString ; + + wxCHECK_MSG( (size_t)line < GetLineCount(), wxEmptyString, + wxT("line index out of range") ); return GetLines()[line]; } @@ -1638,7 +1699,7 @@ wxTextPos wxTextCtrl::XYToPosition(wxTextCoord x, wxTextCoord y) const // if they are out of range if ( IsSingleLine() ) { - return x > GetLastPosition() || y > 0 ? -1 : x; + return ( x > GetLastPosition() || y > 0 ) ? wxOutOfRangeTextCoord : x; } else // multiline { @@ -1673,14 +1734,14 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos, if ( IsSingleLine() ) { if ( (size_t)pos > m_value.length() ) - return FALSE; + return false; if ( x ) *x = pos; if ( y ) *y = 0; - return TRUE; + return true; } else // multiline { @@ -1702,10 +1763,10 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos, #ifdef WXDEBUG_TEXT wxASSERT_MSG( XYToPosition(pos - posCur, nLine) == pos, - _T("XYToPosition() or PositionToXY() broken") ); + wxT("XYToPosition() or PositionToXY() broken") ); #endif // WXDEBUG_TEXT - return TRUE; + return true; } else // go further down { @@ -1714,7 +1775,7 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos, } // beyond the last line - return FALSE; + return false; } } @@ -1735,6 +1796,8 @@ wxTextCoord wxTextCtrl::GetRowsPerLine(wxTextCoord line) const wxTextCoord wxTextCtrl::GetRowCount() const { wxTextCoord count = GetLineCount(); + if (count == 0) + return 0; if ( WrapLines() ) { count = GetFirstRowOfLine(count - 1) + @@ -1786,7 +1849,7 @@ bool wxTextCtrl::PositionToLogicalXY(wxTextPos pos, else // must really calculate col/line from pos { if ( !PositionToXY(pos, &col, &line) ) - return FALSE; + return false; } int hLine = GetLineHeight(); @@ -1815,7 +1878,7 @@ bool wxTextCtrl::PositionToLogicalXY(wxTextPos pos, if ( yOut ) *yOut = y; - return TRUE; + return true; } bool wxTextCtrl::PositionToDeviceXY(wxTextPos pos, @@ -1824,13 +1887,13 @@ bool wxTextCtrl::PositionToDeviceXY(wxTextPos pos, { wxCoord x, y; if ( !PositionToLogicalXY(pos, &x, &y) ) - return FALSE; + return false; // finally translate the logical text rect coords into physical client // coords CalcScrolledPosition(m_rectText.x + x, m_rectText.y + y, xOut, yOut); - return TRUE; + return true; } wxPoint wxTextCtrl::GetCaretPosition() const @@ -1838,7 +1901,7 @@ wxPoint wxTextCtrl::GetCaretPosition() const wxCoord xCaret, yCaret; if ( !PositionToDeviceXY(m_curPos, &xCaret, &yCaret) ) { - wxFAIL_MSG( _T("Caret can't be beyond the text!") ); + wxFAIL_MSG( wxT("Caret can't be beyond the text!") ); } return wxPoint(xCaret, yCaret); @@ -1847,7 +1910,9 @@ wxPoint wxTextCtrl::GetCaretPosition() const // pos may be -1 to show the current position void wxTextCtrl::ShowPosition(wxTextPos pos) { - HideCaret(); + bool showCaret = GetCaret() && GetCaret()->IsVisible(); + if (showCaret) + HideCaret(); if ( IsSingleLine() ) { @@ -1902,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 ) @@ -1967,7 +2032,8 @@ void wxTextCtrl::ShowPosition(wxTextPos pos) } //else: multiline but no scrollbars, hence nothing to do - ShowCaret(); + if (showCaret) + ShowCaret(); } // ---------------------------------------------------------------------------- @@ -2101,13 +2167,13 @@ void wxTextCtrl::Cut() bool wxTextCtrl::DoCut() { if ( !HasSelection() ) - return FALSE; + return false; Copy(); RemoveSelection(); - return TRUE; + return true; } void wxTextCtrl::Paste() @@ -2131,12 +2197,12 @@ bool wxTextCtrl::DoPaste() { WriteText(text); - return TRUE; + return true; } } #endif // wxUSE_CLIPBOARD - return FALSE; + return false; } // ---------------------------------------------------------------------------- @@ -2176,7 +2242,7 @@ void wxTextCtrlCommandProcessor::Store(wxCommand *command) } // append the following insert commands to this one - m_compressInserts = TRUE; + m_compressInserts = true; // let the base class version will do the job normally } @@ -2211,17 +2277,17 @@ bool wxTextCtrlInsertCommand::Do(wxTextCtrl *text) // and now do insert it text->WriteText(m_text); - return TRUE; + return true; } bool wxTextCtrlInsertCommand::Undo(wxTextCtrl *text) { - wxCHECK_MSG( CanUndo(), FALSE, _T("impossible to undo insert cmd") ); + wxCHECK_MSG( CanUndo(), false, wxT("impossible to undo insert cmd") ); // remove the text from where we inserted it text->Remove(m_from, m_from + m_text.length()); - return TRUE; + return true; } bool wxTextCtrlRemoveCommand::CanUndo() const @@ -2236,7 +2302,7 @@ bool wxTextCtrlRemoveCommand::Do(wxTextCtrl *text) m_textDeleted = text->GetSelectionText(); text->RemoveSelection(); - return TRUE; + return true; } bool wxTextCtrlRemoveCommand::Undo(wxTextCtrl *text) @@ -2247,13 +2313,13 @@ bool wxTextCtrlRemoveCommand::Undo(wxTextCtrl *text) text->SetInsertionPoint(m_from > posLast ? posLast : m_from); text->WriteText(m_textDeleted); - return TRUE; + return true; } void wxTextCtrl::Undo() { // the caller must check it - wxASSERT_MSG( CanUndo(), _T("can't call Undo() if !CanUndo()") ); + wxASSERT_MSG( CanUndo(), wxT("can't call Undo() if !CanUndo()") ); m_cmdProcessor->Undo(); } @@ -2261,7 +2327,7 @@ void wxTextCtrl::Undo() void wxTextCtrl::Redo() { // the caller must check it - wxASSERT_MSG( CanRedo(), _T("can't call Undo() if !CanUndo()") ); + wxASSERT_MSG( CanRedo(), wxT("can't call Undo() if !CanUndo()") ); m_cmdProcessor->Redo(); } @@ -2311,7 +2377,7 @@ wxSize wxTextCtrl::DoGetBestClientSize() const lines = 5; else if ( lines > 10 ) lines = 10; - h *= 10; + h *= lines; } wxRect rectText; @@ -2323,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); @@ -2354,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++; @@ -2378,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; @@ -2389,7 +2458,7 @@ void wxTextCtrl::UpdateLastVisible() case wxTE_HT_BELOW: */ default: - wxFAIL_MSG(_T("unexpected HitTestLine() return value")); + wxFAIL_MSG(wxT("unexpected HitTestLine() return value")); // fall through case wxTE_HT_ON_TEXT: @@ -2425,8 +2494,8 @@ void wxTextCtrl::UpdateLastVisible() // SData().m_colStart, we need an absolute offset into string SData().m_colLastVisible += SData().m_colStart; - wxLogTrace(_T("text"), _T("Last visible column/position is %d/%ld"), - SData().m_colLastVisible, SData().m_posLastVisible); + wxLogTrace(wxT("text"), wxT("Last visible column/position is %d/%ld"), + (int) SData().m_colLastVisible, (long) SData().m_posLastVisible); } void wxTextCtrl::OnSize(wxSizeEvent& event) @@ -2444,7 +2513,7 @@ void wxTextCtrl::OnSize(wxSizeEvent& event) #endif // 0 MData().m_updateScrollbarX = - MData().m_updateScrollbarY = TRUE; + MData().m_updateScrollbarY = true; } event.Skip(); @@ -2497,7 +2566,7 @@ wxTextCoord wxTextCtrl::GetRowInLine(wxTextCoord line, wxTextCoord col, wxTextCoord *colRowStart) const { - wxASSERT_MSG( WrapLines(), _T("shouldn't be called") ); + wxASSERT_MSG( WrapLines(), wxT("shouldn't be called") ); const wxWrappedLineData& lineData = WData().m_linesData[line]; @@ -2525,7 +2594,7 @@ wxTextCoord wxTextCtrl::GetRowInLine(wxTextCoord line, *colRowStart = lineData.GetRowStart(row); // this can't happen, of course - wxASSERT_MSG( *colRowStart <= col, _T("GetRowInLine() is broken") ); + wxASSERT_MSG( *colRowStart <= col, wxT("GetRowInLine() is broken") ); } return row; @@ -2566,12 +2635,12 @@ void wxTextCtrl::LayoutLine(wxTextCoord line, wxWrappedLineData& lineData) const void wxTextCtrl::LayoutLines(wxTextCoord lineLast) const { - wxASSERT_MSG( WrapLines(), _T("should only be used for line wrapping") ); + wxASSERT_MSG( WrapLines(), wxT("should only be used for line wrapping") ); // if we were called, some line was dirty and if it was dirty we must have // had m_rowFirstInvalid set to something too wxTextCoord lineFirst = WData().m_rowFirstInvalid; - wxASSERT_MSG( lineFirst != -1, _T("nothing to layout?") ); + wxASSERT_MSG( lineFirst != -1, wxT("nothing to layout?") ); wxTextCoord rowFirst, rowCur; if ( lineFirst ) @@ -2624,11 +2693,11 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, wxCoord *widthReal) const { // this function is slow, it shouldn't be called unless really needed - wxASSERT_MSG( WrapLines(), _T("shouldn't be called") ); + wxASSERT_MSG( WrapLines(), wxT("shouldn't be called") ); wxString s(text); wxTextCoord col; - wxCoord wReal = -1; + wxCoord wReal = wxDefaultCoord; switch ( HitTestLine(s, m_rectText.width, &col) ) { /* @@ -2636,7 +2705,7 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, case wxTE_HT_BELOW: */ default: - wxFAIL_MSG(_T("unexpected HitTestLine() return value")); + wxFAIL_MSG(wxT("unexpected HitTestLine() return value")); // fall through case wxTE_HT_ON_TEXT: @@ -2653,12 +2722,12 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, col--; // recalc the width - wReal = -1; + wReal = wxDefaultCoord; } //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; @@ -2672,7 +2741,7 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, if ( colWordStart != col ) { // will have to recalc the real width - wReal = -1; + wReal = wxDefaultCoord; col = colWordStart; } @@ -2695,7 +2764,7 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, if ( widthReal ) { - if ( wReal == -1 ) + if ( wReal == wxDefaultCoord ) { // calc it if not done yet wReal = GetTextWidth(s.Truncate(col)); @@ -2876,7 +2945,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, } // this is not supposed to happen - wxASSERT_MSG( matchDir, _T("logic error in wxTextCtrl::HitTest") ); + wxASSERT_MSG( matchDir, wxT("logic error in wxTextCtrl::HitTest") ); if ( matchDir == Match_Right ) col++; @@ -2900,11 +2969,11 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, dc.GetTextExtent(text, &width2, NULL); wxASSERT_MSG( (width1 <= x) && (x < width2), - _T("incorrect HitTestLine() result") ); + wxT("incorrect HitTestLine() result") ); } else // we return last char { - wxASSERT_MSG( x >= width1, _T("incorrect HitTestLine() result") ); + wxASSERT_MSG( x >= width1, wxT("incorrect HitTestLine() result") ); } } #endif // WXDEBUG_TEXT @@ -2915,6 +2984,18 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, return res; } +wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pt, long *pos) const +{ + wxTextCoord x, y; + wxTextCtrlHitTestResult rc = HitTest(pt, &x, &y); + if ( rc != wxTE_HT_UNKNOWN && pos ) + { + *pos = XYToPosition(x, y); + } + + return rc; +} + wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos, wxTextCoord *colOut, wxTextCoord *rowOut) const @@ -2926,7 +3007,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLogical(const wxPoint& pos, wxTextCoord *colOut, wxTextCoord *rowOut) const { - return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, FALSE); + return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, false); } wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0, @@ -3130,7 +3211,7 @@ bool wxTextCtrl::GetLineAndRow(wxTextCoord row, rowInLine = 0; if ( row < 0 ) - return FALSE; + return false; int nLines = GetNumberOfLines(); if ( WrapLines() ) @@ -3153,13 +3234,13 @@ bool wxTextCtrl::GetLineAndRow(wxTextCoord row, if ( line == nLines ) { // the row is out of range - return FALSE; + return false; } } else // no line wrapping, everything is easy { if ( row >= nLines ) - return FALSE; + return false; line = row; } @@ -3169,7 +3250,7 @@ bool wxTextCtrl::GetLineAndRow(wxTextCoord row, if ( rowInLineOut ) *rowInLineOut = rowInLine; - return TRUE; + return true; } // ---------------------------------------------------------------------------- @@ -3186,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. @@ -3197,11 +3278,11 @@ bool wxTextCtrl::GetLineAndRow(wxTextCoord row, void wxTextCtrl::ShowHorzPosition(wxCoord pos) { - wxASSERT_MSG( IsSingleLine(), _T("doesn't work for multiline") ); + wxASSERT_MSG( IsSingleLine(), wxT("doesn't work for multiline") ); // 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 @@ -3236,7 +3317,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos) void wxTextCtrl::ScrollText(wxTextCoord col) { wxASSERT_MSG( IsSingleLine(), - _T("ScrollText() is for single line controls only") ); + wxT("ScrollText() is for single line controls only") ); // never scroll beyond the left border if ( col < 0 ) @@ -3314,7 +3395,7 @@ void wxTextCtrl::ScrollText(wxTextCoord col) if ( dx > 0 ) { // refresh the uncovered part on the left - Refresh(TRUE, &rect); + Refresh(true, &rect); // and now the area on the right rect.x = m_rectText.x + posLastVisible; @@ -3327,7 +3408,7 @@ void wxTextCtrl::ScrollText(wxTextCoord col) rect.width += m_rectText.width - posLastVisible; } - Refresh(TRUE, &rect); + Refresh(true, &rect); // I don't know exactly why is this needed here but without it we may // scroll the window again (from the same method) before the previously @@ -3431,7 +3512,7 @@ void wxTextCtrl::RecalcFontMetrics() void wxTextCtrl::RecalcMaxWidth() { - wxASSERT_MSG( !IsSingleLine(), _T("only used for multiline") ); + wxASSERT_MSG( !IsSingleLine(), wxT("only used for multiline") ); MData().m_widthMax = -1; (void)GetMaxWidth(); @@ -3465,14 +3546,14 @@ wxCoord wxTextCtrl::GetMaxWidth() const } } - wxASSERT_MSG( MData().m_widthMax != -1, _T("should have at least 1 line") ); + wxASSERT_MSG( MData().m_widthMax != -1, wxT("should have at least 1 line") ); return MData().m_widthMax; } void wxTextCtrl::UpdateScrollbars() { - wxASSERT_MSG( !IsSingleLine(), _T("only used for multiline") ); + wxASSERT_MSG( !IsSingleLine(), wxT("only used for multiline") ); wxSize size = GetRealTextArea().GetSize(); @@ -3495,7 +3576,7 @@ void wxTextCtrl::UpdateScrollbars() // just to suppress compiler warnings about using uninit vars below charWidth = maxWidth = 0; - showScrollbarX = FALSE; + showScrollbarX = false; } // calc the scrollbars ranges @@ -3532,12 +3613,16 @@ void wxTextCtrl::UpdateScrollbars() SetScrollbars(charWidth, lineHeight, scrollRangeX, scrollRangeY, x, y, - TRUE /* no refresh */); + true /* no refresh */); 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); } @@ -3549,10 +3634,10 @@ void wxTextCtrl::UpdateScrollbars() } MData().m_updateScrollbarX = - MData().m_updateScrollbarY = FALSE; + MData().m_updateScrollbarY = false; } -void wxTextCtrl::OnIdle(wxIdleEvent& event) +void wxTextCtrl::OnInternalIdle() { // notice that single line text control never has scrollbars if ( !IsSingleLine() && @@ -3560,8 +3645,7 @@ void wxTextCtrl::OnIdle(wxIdleEvent& event) { UpdateScrollbars(); } - - event.Skip(); + wxControl::OnInternalIdle(); } bool wxTextCtrl::SendAutoScrollEvents(wxScrollWinEvent& event) const @@ -3592,7 +3676,7 @@ void wxTextCtrl::RefreshSelection() void wxTextCtrl::RefreshLineRange(wxTextCoord lineFirst, wxTextCoord lineLast) { wxASSERT_MSG( lineFirst <= lineLast || !lineLast, - _T("no lines to refresh") ); + wxT("no lines to refresh") ); wxRect rect; // rect.x is already 0 @@ -3609,7 +3693,7 @@ void wxTextCtrl::RefreshLineRange(wxTextCoord lineFirst, wxTextCoord lineLast) // lineFirst may be beyond the last line only if we refresh till // the end, otherwise it's illegal wxASSERT_MSG( lineFirst == GetNumberOfLines() && !lineLast, - _T("invalid line range") ); + wxT("invalid line range") ); rowFirst = GetRowAfterLine(lineFirst - 1); } @@ -3635,7 +3719,7 @@ void wxTextCtrl::RefreshLineRange(wxTextCoord lineFirst, wxTextCoord lineLast) void wxTextCtrl::RefreshTextRange(wxTextPos start, wxTextPos end) { wxCHECK_RET( start != -1 && end != -1, - _T("invalid RefreshTextRange() arguments") ); + wxT("invalid RefreshTextRange() arguments") ); // accept arguments in any order as it is more conenient for the caller OrderPositions(start, end); @@ -3671,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 { @@ -3691,7 +3775,7 @@ void wxTextCtrl::RefreshColRange(wxTextCoord line, wxString text = GetLineText(line); wxASSERT_MSG( (size_t)start <= text.length() && count, - _T("invalid RefreshColRange() parameter") ); + wxT("invalid RefreshColRange() parameter") ); RefreshPixelRange(line, GetTextWidth(text.Left((size_t)start)), @@ -3789,7 +3873,7 @@ void wxTextCtrl::RefreshTextRect(const wxRect& rectClient, bool textOnly) rect.Offset(m_rectText.GetPosition()); // don't refresh beyond the text area unless we're refreshing the line wrap - // marks in which case textOnly is FALSE + // marks in which case textOnly is false if ( textOnly ) { if ( rect.GetRight() > m_rectText.GetRight() ) @@ -3823,10 +3907,10 @@ void wxTextCtrl::RefreshTextRect(const wxRect& rectClient, bool textOnly) if ( rect.y < m_rectText.y ) rect.y = m_rectText.y; - wxLogTrace(_T("text"), _T("Refreshing (%d, %d)-(%d, %d)"), + wxLogTrace(wxT("text"), wxT("Refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); - Refresh(TRUE, &rect); + Refresh(true, &rect); } void wxTextCtrl::RefreshLineWrapMarks(wxTextCoord rowFirst, @@ -3840,7 +3924,7 @@ void wxTextCtrl::RefreshLineWrapMarks(wxTextCoord rowFirst, rectMarks.y = rowFirst*GetLineHeight(); rectMarks.height = (rowLast - rowFirst)*GetLineHeight(); - RefreshTextRect(rectMarks, FALSE /* don't limit to text area */); + RefreshTextRect(rectMarks, false /* don't limit to text area */); } } @@ -3873,7 +3957,7 @@ wxString wxTextCtrl::GetTextToShow(const wxString& text) const { wxString textShown; if ( IsPassword() ) - textShown = wxString(_T('*'), text.length()); + textShown = wxString(wxT('*'), text.length()); else textShown = text; @@ -3952,7 +4036,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) if ( (ht == wxTE_HT_BEYOND) || (ht == wxTE_HT_BELOW) ) { - wxASSERT_MSG( line <= lineEnd, _T("how did we get that far?") ); + wxASSERT_MSG( line <= lineEnd, wxT("how did we get that far?") ); if ( line == lineEnd ) { @@ -4033,7 +4117,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) } // calculate the text coords on screen - wxASSERT_MSG( colStart >= colRowStart, _T("invalid string part") ); + wxASSERT_MSG( colStart >= colRowStart, wxT("invalid string part") ); wxCoord ofsStart = GetTextWidth( textLine.Mid(colRowStart, colStart - colRowStart)); @@ -4043,7 +4127,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) // do draw the text renderer->DrawTextLine(dc, text, rectText, selStart, selEnd, GetStateFlags()); - wxLogTrace(_T("text"), _T("Line %ld: positions %ld-%ld redrawn."), + wxLogTrace(wxT("text"), wxT("Line %ld: positions %ld-%ld redrawn."), line, colStart, colEnd); } } @@ -4051,7 +4135,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) void wxTextCtrl::DoDrawLineWrapMarks(wxDC& dc, const wxRect& rectUpdate) { wxASSERT_MSG( WrapLines() && WData().m_widthMark, - _T("shouldn't be called at all") ); + wxT("shouldn't be called at all") ); wxRenderer *renderer = GetRenderer(); @@ -4098,6 +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; @@ -4114,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 @@ -4162,11 +4248,11 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer) // show caret first time only: we must show it after drawing the text or // the display can be corrupted when it's hidden - if ( !m_hasCaret && GetCaret() ) + if ( !m_hasCaret && GetCaret() && (FindFocus() == this) ) { ShowCaret(); - m_hasCaret = TRUE; + m_hasCaret = true; } } @@ -4177,7 +4263,7 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer) bool wxTextCtrl::SetFont(const wxFont& font) { if ( !wxControl::SetFont(font) ) - return FALSE; + return false; // and refresh everything, of course InitInsertionPoint(); @@ -4197,17 +4283,20 @@ bool wxTextCtrl::SetFont(const wxFont& font) Refresh(); - return TRUE; + return true; } bool wxTextCtrl::Enable(bool enable) { if ( !wxTextCtrlBase::Enable(enable) ) - return FALSE; + return false; - ShowCaret(enable); + if (FindFocus() == this && GetCaret() && + ((enable && !GetCaret()->IsVisible()) || + (!enable && GetCaret()->IsVisible()))) + ShowCaret(enable); - return TRUE; + return true; } void wxTextCtrl::CreateCaret() @@ -4218,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 @@ -4241,7 +4327,9 @@ void wxTextCtrl::ShowCaret(bool show) caret->Move(GetCaretPosition()); // and show it there - caret->Show(show); + if ((show && !caret->IsVisible()) || + (!show && caret->IsVisible())) + caret->Show(show); } } @@ -4260,7 +4348,7 @@ size_t wxTextCtrl::GetLinesPerPage() const wxTextPos wxTextCtrl::GetPositionAbove() { wxCHECK_MSG( !IsSingleLine(), INVALID_POS_VALUE, - _T("can't move cursor vertically in a single line control") ); + wxT("can't move cursor vertically in a single line control") ); // move the cursor up by one ROW not by one LINE: this means that // we should really use HitTest() and not just go to the same @@ -4293,7 +4381,7 @@ wxTextPos wxTextCtrl::GetPositionAbove() wxTextPos wxTextCtrl::GetPositionBelow() { wxCHECK_MSG( !IsSingleLine(), INVALID_POS_VALUE, - _T("can't move cursor vertically in a single line control") ); + wxT("can't move cursor vertically in a single line control") ); // see comments for wxACTION_TEXT_UP wxPoint pt = GetCaretPosition() - m_rectText.GetPosition(); @@ -4333,28 +4421,28 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, const wxString& strArg) { // has the text changed as result of this action? - bool textChanged = FALSE; + bool textChanged = false; // the remembered cursor abscissa for multiline text controls is usually // reset after each user action but for ones which do use it (UP and DOWN // for example) we shouldn't do it - as indicated by this flag - bool rememberAbscissa = FALSE; + bool rememberAbscissa = false; // 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, - sel = FALSE; + bool del = false, + sel = false; if ( actionOrig.StartsWith(wxACTION_TEXT_PREFIX_DEL, &action) ) { if ( IsEditable() ) - del = TRUE; + del = true; } else if ( actionOrig.StartsWith(wxACTION_TEXT_PREFIX_SEL, &action) ) { - sel = TRUE; + sel = true; } else // not selection nor delete action { @@ -4394,7 +4482,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, if ( newPos != INVALID_POS_VALUE ) { // remember where the cursor original had been - rememberAbscissa = TRUE; + rememberAbscissa = true; } } } @@ -4407,7 +4495,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, if ( newPos != INVALID_POS_VALUE ) { // remember where the cursor original had been - rememberAbscissa = TRUE; + rememberAbscissa = true; } } } @@ -4434,7 +4522,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, // inserting text can be undone command = new wxTextCtrlInsertCommand(strArg); - textChanged = TRUE; + textChanged = true; } } else if ( (action == wxACTION_TEXT_PAGE_UP) || @@ -4451,7 +4539,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, } // remember where the cursor original had been - rememberAbscissa = TRUE; + rememberAbscissa = true; bool goUp = action == wxACTION_TEXT_PAGE_UP; for ( size_t line = 0; line < count; line++ ) @@ -4498,7 +4586,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, } // scroll vertically only - Scroll(-1, y); + Scroll(wxDefaultCoord, y); } } else if ( action == wxACTION_TEXT_SEL_WORD ) @@ -4613,7 +4701,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, m_cmdProcessor->Submit(command); // undoable commands always change text - textChanged = TRUE; + textChanged = true; } else // no undoable command { @@ -4622,18 +4710,17 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, if ( textChanged ) { - wxASSERT_MSG( IsEditable(), _T("non editable control changed?") ); + wxASSERT_MSG( IsEditable(), wxT("non editable control changed?") ); wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); InitCommandEvent(event); - event.SetString(GetValue()); GetEventHandler()->ProcessEvent(event); // as the text changed... - m_isModified = TRUE; + m_isModified = true; } - return TRUE; + return true; } void wxTextCtrl::OnChar(wxKeyEvent& event) @@ -4642,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) ) @@ -4653,7 +4743,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) } else // interpret normally: insert new line { - PerformAction(wxACTION_TEXT_INSERT, -1, _T('\n')); + PerformAction(wxACTION_TEXT_INSERT, -1, wxT('\n')); } } else if ( keycode < 255 && isprint(keycode) ) @@ -4663,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 // ---------------------------------------------------------------------------- @@ -4680,7 +4786,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) wxStdTextCtrlInputHandler::wxStdTextCtrlInputHandler(wxInputHandler *inphand) : wxStdInputHandler(inphand) { - m_winCapture = (wxTextCtrl *)NULL; + m_winCapture = NULL; } /* static */ @@ -4702,13 +4808,13 @@ wxTextPos wxStdTextCtrlInputHandler::HitTest(const wxTextCtrl *text, return pos; } -bool wxStdTextCtrlInputHandler::HandleKey(wxControl *control, +bool wxStdTextCtrlInputHandler::HandleKey(wxInputConsumer *consumer, const wxKeyEvent& event, bool pressed) { // we're only interested in key presses if ( !pressed ) - return FALSE; + return false; int keycode = event.GetKeyCode(); @@ -4762,14 +4868,12 @@ bool wxStdTextCtrlInputHandler::HandleKey(wxControl *control, 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; @@ -4819,22 +4923,22 @@ bool wxStdTextCtrlInputHandler::HandleKey(wxControl *control, if ( (action != wxACTION_NONE) && (action != wxACTION_TEXT_PREFIX_SEL) ) { - control->PerformAction(action, -1, str); + consumer->PerformAction(action, -1, str); - return TRUE; + return true; } - return wxStdInputHandler::HandleKey(control, event, pressed); + return wxStdInputHandler::HandleKey(consumer, event, pressed); } -bool wxStdTextCtrlInputHandler::HandleMouse(wxControl *control, +bool wxStdTextCtrlInputHandler::HandleMouse(wxInputConsumer *consumer, const wxMouseEvent& event) { if ( event.LeftDown() ) { - wxASSERT_MSG( !m_winCapture, _T("left button going down twice?") ); + wxASSERT_MSG( !m_winCapture, wxT("left button going down twice?") ); - wxTextCtrl *text = wxStaticCast(control, wxTextCtrl); + wxTextCtrl *text = wxStaticCast(consumer->GetInputWindow(), wxTextCtrl); m_winCapture = text; m_winCapture->CaptureMouse(); @@ -4850,7 +4954,7 @@ bool wxStdTextCtrlInputHandler::HandleMouse(wxControl *control, else if ( event.LeftDClick() ) { // select the word the cursor is on - control->PerformAction(wxACTION_TEXT_SEL_WORD); + consumer->PerformAction(wxACTION_TEXT_SEL_WORD); } else if ( event.LeftUp() ) { @@ -4859,14 +4963,14 @@ bool wxStdTextCtrlInputHandler::HandleMouse(wxControl *control, m_winCapture->ShowCaret(); m_winCapture->ReleaseMouse(); - m_winCapture = (wxTextCtrl *)NULL; + m_winCapture = NULL; } } - return wxStdInputHandler::HandleMouse(control, event); + return wxStdInputHandler::HandleMouse(consumer, event); } -bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control, +bool wxStdTextCtrlInputHandler::HandleMouseMove(wxInputConsumer *consumer, const wxMouseEvent& event) { if ( m_winCapture ) @@ -4880,19 +4984,31 @@ bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control, } } - return wxStdInputHandler::HandleMouseMove(control, event); + return wxStdInputHandler::HandleMouseMove(consumer, event); } -bool wxStdTextCtrlInputHandler::HandleFocus(wxControl *control, - const wxFocusEvent& event) +bool +wxStdTextCtrlInputHandler::HandleFocus(wxInputConsumer *consumer, + const wxFocusEvent& event) { - wxTextCtrl *text = wxStaticCast(control, wxTextCtrl); + wxTextCtrl *text = wxStaticCast(consumer->GetInputWindow(), wxTextCtrl); // the selection appearance changes depending on whether we have the focus text->RefreshSelection(); + if (event.GetEventType() == wxEVT_SET_FOCUS) + { + if (text->GetCaret() && !text->GetCaret()->IsVisible()) + text->ShowCaret(); + } + else + { + if (text->GetCaret() && text->GetCaret()->IsVisible()) + text->HideCaret(); + } + // never refresh entirely - return FALSE; + return false; } #endif // wxUSE_TEXTCTRL