many more methods implemented (though untested) for multline text ctrls

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8539 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-10-12 19:39:12 +00:00
parent b7cdbb0e4c
commit b16e3fb5e8
2 changed files with 254 additions and 110 deletions

View File

@@ -39,6 +39,8 @@
#include "wx/dcclient.h"
#include "wx/validate.h"
#include "wx/textctrl.h"
#include "wx/tokenzr.h"
#endif
#include "wx/clipbrd.h"
@@ -154,7 +156,7 @@ bool wxTextCtrl::SetFont(const wxFont& font)
void wxTextCtrl::SetValue(const wxString& value)
{
if ( IsSingleLine() && (m_value == value) )
if ( IsSingleLine() && (value == GetSLValue()) )
{
// nothing changed
return;
@@ -168,7 +170,7 @@ wxString wxTextCtrl::GetValue() const
wxString value;
if ( IsSingleLine() )
{
value = m_value;
value = GetSLValue();
}
else // multiline
{
@@ -219,6 +221,9 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
wxString lineFirstOrig = GetLineText(lineStart);
wxString lineFirst(lineFirstOrig, colStart);
// remember the start of the update region for later use
wxCoord startNewText = GetTextWidth(lineFirst);
// (2) add the text which replaces this part
if ( !lines.IsEmpty() )
{
@@ -233,24 +238,64 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
lineFirst += lineFirstOrig.c_str() + (size_t)colEnd;
}
// (4) modify the line and refresh the part of the window which changed
// (4) refresh the part of the line which changed
// we usually refresh till the end of line except of the most common case
// when some text is appended to the end of it in which case we refresh
// just the newly appended text
wxCoord widthNewText;
if ( (lineEnd == lineStart) &&
((size_t)colStart == lineFirstOrig.length()) )
{
// text appended, not replaced, so refresh only the new text
widthNewText = GetTextWidth(lines[0u]);
}
else
{
// refresh till the end of line as all its tail changed
// OPT: should only refresh the part occupied by the text, but OTOH
// the line won't be really repainted beyond it anyhow due to the
// checks in DoDrawTextInRect(), so is it really worth it?
widthNewText = 0;
}
RefreshPixelRange(lineStart, startNewText, widthNewText);
// (5) modify the line
if ( IsSingleLine() )
{
m_value = lineFirst;
SetSLValue(lineFirst);
// force m_colLastVisible update
m_colLastVisible = -1;
// consistency check: when replacing text in a single line control, we
// shouldn't have more than one line
wxASSERT_MSG(lines.GetCount() <= 1,
_T("can't have more than one line in this wxTextCtrl"));
// nothing more can happen to us
// update the current position
SetInsertionPoint(from + text.length());
// and the selection (do it after setting the cursor to have correct value
// for selection anchor)
ClearSelection();
// nothing more can happen to us, so bail out
return;
}
else // multiline
{
m_lines[lineStart] = lineFirst;
}
// now replace all intermediate lines entirely and refresh
// now replace all intermediate lines entirely
bool refreshAllBelow = FALSE;
// (1) modify all lines which are really repaced
size_t nReplaceLine = 1,
nReplaceCount = lines.GetCount();
for ( long line = lineStart + 1; line < lineEnd; line++ )
@@ -260,10 +305,11 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
// replace line
m_lines[line] = lines[nReplaceLine++];
}
else // no more replacement text - remove line
else // no more replacement text - remove line(s)
{
// optimization: remove not only this line but all the next ones as
// well
// (2) remove all lines for which there is no more replacement
// text (this is slightly more efficient than continuing to
// run the loop)
// adjust the index by the number of lines removed
lineEnd -= lineEnd - line;
@@ -273,17 +319,32 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
{
m_lines.RemoveAt(line++);
}
// the lines below will scroll up
refreshAllBelow = TRUE;
}
}
// if there are still lines left in the replacement text, insert them
// before modifying the last line
while ( nReplaceLine < nReplaceCount - 1 ) // OPT: insert all at once?
// (3) if there are still lines left in the replacement text, insert them
// before modifying the last line
if ( nReplaceLine < nReplaceCount - 1 )
{
// insert line and adjust for index change by incrementing lineEnd
m_lines.Insert(lines[nReplaceLine++], lineEnd++);
// the lines below will scroll down
refreshAllBelow = TRUE;
while ( nReplaceLine < nReplaceCount - 1 ) // OPT: insert all at once?
{
// insert line and adjust for index change by incrementing lineEnd
m_lines.Insert(lines[nReplaceLine++], lineEnd++);
}
}
// (4) refresh the lines: if we had replaced exactly the same number of
// lines that we had before, we can just refresh these lines,
// otherwise the lines below will change as well, so we have to
// refresh them too (by passing -1 as RefreshLineRange() argument)
RefreshLineRange(lineStart + 1, refreshAllBelow ? -1 : lineEnd - 1);
// now deal with the last line: (1) replace its beginning with the end of
// the replacement text
wxString lineLast;
@@ -301,56 +362,21 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
lineLast += lineLastOrig.c_str() + (size_t)colEnd;
}
// (3) always refresh the last line entirely if it hadn't been already
// refreshed above
if ( !refreshAllBelow )
{
RefreshPixelRange(lineEnd, 0, 0); // entire line
}
m_lines[lineEnd] = lineLast;
#if 0 // single line only
// replace the part of the text with the new value
wxString valueNew(m_value, (size_t)from);
// remember it for later use
wxCoord startNewText = GetTextWidth(valueNew);
valueNew += text;
if ( (size_t)to < m_value.length() )
{
valueNew += m_value.c_str() + (size_t)to;
}
// OPT: is the following really ok? not sure any more now at 2 am...
// we usually refresh till the end of line except of the most common case
// when some text is appended to the end of the string in which case we
// refresh just it
wxCoord widthNewText;
if ( (size_t)from < m_value.length() )
{
// refresh till the end of line
widthNewText = 0;
}
else // text appended, not replaced
{
// refresh only the new text
widthNewText = GetTextWidth(text);
}
m_value = valueNew;
// force m_colLastVisible update
m_colLastVisible = -1;
// update the current position
SetInsertionPoint(from + text.length());
SetInsertionPoint(to);
// and the selection (do it after setting the cursor to have correct value
// for selection anchor)
ClearSelection();
// repaint
RefreshPixelRange(0, startNewText, widthNewText);
// TODO: and the affected parts of the next line(s)
#endif // 0
}
void wxTextCtrl::Remove(long from, long to)
@@ -403,20 +429,8 @@ void wxTextCtrl::DoSetInsertionPoint(long pos)
HideCaret();
m_curPos = pos;
if ( IsSingleLine() )
{
m_curLine = 0;
m_curRow = m_curPos;
// the current position should always be shown, scroll the window
// for this if necessary
ShowHorzPosition(GetCaretPosition());
}
else // multi line
{
wxFAIL_MSG(_T("unimplemented for multi line"));
}
PositionToXY(m_curPos, &m_curRow, &m_curLine);
ShowPosition(m_curPos);
ShowCaret();
}
@@ -433,16 +447,31 @@ long wxTextCtrl::GetInsertionPoint() const
long wxTextCtrl::GetLastPosition() const
{
long pos;
if ( IsSingleLine() )
{
return m_value.length();
pos = GetSLValue().length();
}
else
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
pos = 0;
size_t nLineCount = m_lines.GetCount();
for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
{
// +1 is because the positions at the end of this line and of the
// start of the next one are different
pos += m_lines[nLine].length() + 1;
}
return -1;
if ( pos > 0 )
{
// the last position is at the end of the last line, not in the
// beginning of the next line after it
pos--;
}
}
return pos;
}
// ----------------------------------------------------------------------------
@@ -465,12 +494,36 @@ wxString wxTextCtrl::GetSelectionText() const
{
if ( IsSingleLine() )
{
sel = wxString(m_value.c_str() + m_selStart,
m_value.c_str() + m_selEnd);
sel = GetSLValue().Mid(m_selStart, m_selEnd - m_selStart);
}
else
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
long colStart, lineStart,
colEnd, lineEnd;
PositionToXY(m_selStart, &colStart, &lineStart);
PositionToXY(m_selEnd, &colEnd, &lineEnd);
// as always, we need to check for the special case when the start
// and end line are the same
if ( lineEnd == lineStart )
{
sel = m_lines[lineStart].Mid(colStart, colEnd - colStart);
}
else // sel on multiple lines
{
// take the end of the first line
sel = m_lines[lineStart].c_str() + colStart;
sel += _T('\n');
// all intermediate ones
for ( long line = lineStart + 1; line < lineEnd; line++ )
{
sel << m_lines[line] << _T('\n');
}
// and the start of the last one
sel += m_lines[lineEnd].Left(colEnd);
}
}
}
@@ -655,13 +708,14 @@ int wxTextCtrl::GetLineLength(long line) const
{
wxASSERT_MSG( line == 0, _T("invalid GetLineLength() parameter") );
return m_value.length();
return GetSLValue().length();
}
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
wxCHECK_MSG( (size_t)line < m_lines.GetCount(), -1,
_T("line index out of range") );
return 0;
return m_lines[line].length();
}
}
@@ -675,24 +729,18 @@ wxString wxTextCtrl::GetLineText(long line) const
}
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
wxCHECK_MSG( (size_t)line < m_lines.GetCount(), _T(""),
_T("line index out of range") );
return _T("");
return m_lines[line];
}
}
int wxTextCtrl::GetNumberOfLines() const
{
if ( IsSingleLine() )
{
return 1;
}
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
return 0;
}
// for single line controls there is always 1 line, even if the text is
// empty
return IsSingleLine() ? 1 : m_lines.GetCount();
}
long wxTextCtrl::XYToPosition(long x, long y) const
@@ -705,9 +753,23 @@ long wxTextCtrl::XYToPosition(long x, long y) const
}
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
long pos = 0;
for ( size_t nLine = 0; nLine < (size_t)y; nLine++ )
{
// +1 is because the positions at the end of this line and of the
// start of the next one are different
pos += m_lines[nLine].length() + 1;
}
return -1;
if ( pos > 0 )
{
// the last position is at the end of the last line, not in the
// beginning of the next line after it
pos--;
}
// take into account also the position in line
return pos + x;
}
}
@@ -715,7 +777,7 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
{
if ( IsSingleLine() )
{
if ( pos > GetLastPosition() )
if ( (size_t)pos > GetSLValue().length() )
return FALSE;
if ( x )
@@ -727,15 +789,42 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
}
else // multiline
{
wxFAIL_MSG(_T("unimplemented for multi line"));
size_t nLineCount = m_lines.GetCount();
for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
{
long posNew = pos - (m_lines[nLine].length() + 1);
if ( posNew < 0 )
{
// we've found the line, now just calc the column
if ( x )
*x = nLine;
if ( y )
*y = pos;
return TRUE;
}
else // go further down
{
pos = posNew;
}
}
// beyond the last line
return FALSE;
}
}
void wxTextCtrl::ShowPosition(long pos)
{
wxFAIL_MSG(_T("not implemented"));
if ( IsSingleLine() )
{
ShowHorzPosition(GetCaretPosition(pos));
}
else
{
wxFAIL_MSG(_T("not implemented for multiline"));
}
}
// ----------------------------------------------------------------------------
@@ -768,6 +857,9 @@ static inline bool IsWordChar(wxChar ch)
long wxTextCtrl::GetWordStart() const
{
// TODO
wxCHECK_MSG( IsSingleLine(), -1, _T("not implemented for multline") );
if ( m_curPos == -1 || m_curPos == 0 )
return 0;
@@ -797,6 +889,9 @@ long wxTextCtrl::GetWordStart() const
long wxTextCtrl::GetWordEnd() const
{
// TODO
wxCHECK_MSG( IsSingleLine(), -1, _T("not implemented for multline") );
if ( m_curPos == -1 )
return 0;
@@ -922,6 +1017,10 @@ void wxTextCtrl::UpdateTextRect()
void wxTextCtrl::UpdateLastVisible()
{
// this method is only used for horizontal "scrollbarless" scrolling which
// is used only with single line controls
wxASSERT_MSG( IsSingleLine(), _T("shouldn't be called for multiline") );
// OPT: estimate the correct value first, just adjust it later
wxString text;
@@ -1184,7 +1283,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos)
{
// scroll backwards
long col;
HitTestLine(GetValue(), pos, &col);
HitTestLine(GetSLValue(), pos, &col);
ScrollText(col);
}
else
@@ -1203,7 +1302,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos)
{
// scroll forward
long col;
HitTestLine(GetValue(), pos - width, &col);
HitTestLine(GetSLValue(), pos - width, &col);
ScrollText(col + 1);
}
}
@@ -1326,6 +1425,18 @@ void wxTextCtrl::DoPrepareDC(wxDC& dc)
// refresh
// ----------------------------------------------------------------------------
void wxTextCtrl::RefreshLineRange(long lineFirst, long lineLast)
{
wxRect rect;
// rect.x is already 0
rect.width = m_rectText.width;
wxCoord h = GetCharHeight();
rect.y = lineFirst*h;
rect.SetBottom(lineLast == -1 ? m_rectText.height : (lineLast + 1)*h);
RefreshTextRect(rect);
}
void wxTextCtrl::RefreshTextRange(long start, long end)
{
wxCHECK_RET( start != -1 && end != -1,
@@ -1369,11 +1480,11 @@ void wxTextCtrl::RefreshTextRange(long start, long end)
posCount = colEnd - posStart;
}
RefreshLineRange(line, posStart, posCount);
RefreshColRange(line, posStart, posCount);
}
}
void wxTextCtrl::RefreshLineRange(long line, long start, long count)
void wxTextCtrl::RefreshColRange(long line, long start, long count)
{
wxString text = GetLineText(line);
@@ -1386,7 +1497,7 @@ void wxTextCtrl::RefreshPixelRange(long line, wxCoord start, wxCoord width)
{
wxCoord h = GetCharHeight();
wxRect rect;
rect.x = start - m_ofsHorz;
rect.x = start;
rect.y = line*h;
if ( width == 0 )
@@ -1402,6 +1513,17 @@ void wxTextCtrl::RefreshPixelRange(long line, wxCoord start, wxCoord width)
rect.height = h;
RefreshTextRect(rect);
}
void wxTextCtrl::RefreshTextRect(wxRect& rect)
{
if ( IsSingleLine() )
{
// account for horz scrolling
rect.x -= m_ofsHorz;
}
// account for the text area offset
rect.Offset(m_rectText.GetPosition());
@@ -1568,7 +1690,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
// extract the part of line we need to redraw
wxString textLine = GetLineText(line);
wxString text = textLine.Mid(colStart, colEnd - colStart + 1);
wxString text = textLine.Mid(colStart, colEnd - colStart);
// now deal with the selection
int selStart, selEnd;
@@ -1673,9 +1795,10 @@ void wxTextCtrl::CreateCaret()
SetCaret(caret);
}
wxCoord wxTextCtrl::GetCaretPosition() const
wxCoord wxTextCtrl::GetCaretPosition(long pos = -1) const
{
wxString textBeforeCaret(GetLineText(m_curLine), (size_t)m_curRow);
wxString textBeforeCaret(GetLineText(m_curLine),
(size_t)(pos == -1 ? m_curRow : pos));
return GetTextWidth(textBeforeCaret);
}