textctrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,131 行 · 第 1/5 页
CPP
2,131 行
return true;
}
else // multiline
{
wxTextPos posCur = 0;
size_t nLineCount = GetLineCount();
for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
{
// +1 is because the start the start of the next line is one
// position after the end of this one
wxTextPos posNew = posCur + GetLines()[nLine].length() + 1;
if ( posNew > pos )
{
// we've found the line, now just calc the column
if ( x )
*x = pos - posCur;
if ( y )
*y = nLine;
#ifdef WXDEBUG_TEXT
wxASSERT_MSG( XYToPosition(pos - posCur, nLine) == pos,
_T("XYToPosition() or PositionToXY() broken") );
#endif // WXDEBUG_TEXT
return true;
}
else // go further down
{
posCur = posNew;
}
}
// beyond the last line
return false;
}
}
wxTextCoord wxTextCtrl::GetRowsPerLine(wxTextCoord line) const
{
// a normal line has one row
wxTextCoord numRows = 1;
if ( WrapLines() )
{
// add the number of additional rows
numRows += WData().m_linesData[line].GetExtraRowCount();
}
return numRows;
}
wxTextCoord wxTextCtrl::GetRowCount() const
{
wxTextCoord count = GetLineCount();
if (count == 0)
return 0;
if ( WrapLines() )
{
count = GetFirstRowOfLine(count - 1) +
WData().m_linesData[count - 1].GetRowCount();
}
return count;
}
wxTextCoord wxTextCtrl::GetRowAfterLine(wxTextCoord line) const
{
if ( !WrapLines() )
return line + 1;
if ( !WData().IsValidLine(line) )
{
LayoutLines(line);
}
return WData().m_linesData[line].GetNextRow();
}
wxTextCoord wxTextCtrl::GetFirstRowOfLine(wxTextCoord line) const
{
if ( !WrapLines() )
return line;
if ( !WData().IsValidLine(line) )
{
LayoutLines(line);
}
return WData().m_linesData[line].GetFirstRow();
}
bool wxTextCtrl::PositionToLogicalXY(wxTextPos pos,
wxCoord *xOut,
wxCoord *yOut) const
{
wxTextCoord col, line;
// optimization for special (but common) case when we already have the col
// and line
if ( pos == m_curPos )
{
col = m_curCol;
line = m_curRow;
}
else // must really calculate col/line from pos
{
if ( !PositionToXY(pos, &col, &line) )
return false;
}
int hLine = GetLineHeight();
wxCoord x, y;
wxString textLine = GetLineText(line);
if ( IsSingleLine() || !WrapLines() )
{
x = GetTextWidth(textLine.Left(col));
y = line*hLine;
}
else // difficult case: multline control with line wrap
{
y = GetFirstRowOfLine(line);
wxTextCoord colRowStart;
y += GetRowInLine(line, col, &colRowStart);
y *= hLine;
// x is the width of the text before this position in this row
x = GetTextWidth(textLine.Mid(colRowStart, col - colRowStart));
}
if ( xOut )
*xOut = x;
if ( yOut )
*yOut = y;
return true;
}
bool wxTextCtrl::PositionToDeviceXY(wxTextPos pos,
wxCoord *xOut,
wxCoord *yOut) const
{
wxCoord x, y;
if ( !PositionToLogicalXY(pos, &x, &y) )
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;
}
wxPoint wxTextCtrl::GetCaretPosition() const
{
wxCoord xCaret, yCaret;
if ( !PositionToDeviceXY(m_curPos, &xCaret, &yCaret) )
{
wxFAIL_MSG( _T("Caret can't be beyond the text!") );
}
return wxPoint(xCaret, yCaret);
}
// pos may be -1 to show the current position
void wxTextCtrl::ShowPosition(wxTextPos pos)
{
bool showCaret = GetCaret() && GetCaret()->IsVisible();
if (showCaret)
HideCaret();
if ( IsSingleLine() )
{
ShowHorzPosition(GetTextWidth(m_value.Left(pos)));
}
else if ( MData().m_scrollRangeX || MData().m_scrollRangeY ) // multiline with scrollbars
{
int xStart, yStart;
GetViewStart(&xStart, &yStart);
if ( pos == -1 )
pos = m_curPos;
wxCoord x, y;
PositionToLogicalXY(pos, &x, &y);
wxRect rectText = GetRealTextArea();
// scroll the position vertically into view: if it is currently above
// it, make it the first one, otherwise the last one
if ( MData().m_scrollRangeY )
{
y /= GetLineHeight();
if ( y < yStart )
{
Scroll(0, y);
}
else // we are currently in or below the view area
{
// find the last row currently shown
wxTextCoord yEnd;
if ( WrapLines() )
{
// to find the last row we need to use the generic HitTest
wxTextCoord col;
// OPT this is a bit silly: we undo this in HitTest(), so
// it would be better to factor out the common
// functionality into a separate function (OTOH it
// won't probably save us that much)
wxPoint pt(0, rectText.height - 1);
pt += GetClientAreaOrigin();
pt += m_rectText.GetPosition();
HitTest(pt, &col, &yEnd);
// find the row inside the line
yEnd = GetFirstRowOfLine(yEnd) + GetRowInLine(yEnd, col);
}
else
{
// finding the last line is easy if each line has exactly
// one row
yEnd = yStart + rectText.height / GetLineHeight() - 1;
}
if ( yEnd < y )
{
// scroll down: the current item should appear at the
// bottom of the view
Scroll(0, y - (yEnd - yStart));
}
}
}
// scroll the position horizontally into view
//
// we follow what I believe to be Windows behaviour here, that is if
// the position is already entirely in the view we do nothing, but if
// we do have to scroll the window to bring it into view, we scroll it
// not just enough to show the position but slightly more so that this
// position is at 1/3 of the window width from the closest border to it
// (I'm not sure that Windows does exactly this but it looks like this)
if ( MData().m_scrollRangeX )
{
// unlike for the rows, xStart doesn't correspond to the starting
// column as they all have different widths, so we need to
// translate everything to pixels
// we want the text between x and x2 be entirely inside the view
// (i.e. the current character)
// make xStart the first visible pixel (and not position)
int wChar = GetAverageWidth();
xStart *= wChar;
if ( x < xStart )
{
// we want the position of this column be 1/3 to the right of
// the left edge
x -= rectText.width / 3;
if ( x < 0 )
x = 0;
Scroll(x / wChar, y);
}
else // maybe we're beyond the right border of the view?
{
wxTextCoord col, row;
if ( PositionToXY(pos, &col, &row) )
{
wxString lineText = GetLineText(row);
wxCoord x2 = x + GetTextWidth(lineText[(size_t)col]);
if ( x2 > xStart + rectText.width )
{
// we want the position of this column be 1/3 to the
// left of the right edge, i.e. 2/3 right of the left
// one
x2 -= (2*rectText.width)/3;
if ( x2 < 0 )
x2 = 0;
Scroll(x2 / wChar, row);
}
}
}
}
}
//else: multiline but no scrollbars, hence nothing to do
if (showCaret)
ShowCaret();
}
// ----------------------------------------------------------------------------
// word stuff
// ----------------------------------------------------------------------------
/*
TODO: we could have (easy to do) vi-like options for word movement, i.e.
distinguish between inlusive/exclusive words and between words and
WORDS (in vim sense) and also, finally, make the set of characters
which make up a word configurable - currently we use the exclusive
WORDS only (coincidentally, this is what Windows edit control does)
For future references, here is what vim help says:
A word consists of a sequence of letters, digits and underscores, or
a sequence of other non-blank characters, separated with white space
(spaces, tabs, <EOL>). This can be changed with the 'iskeyword'
option.
A WORD consists of a sequence of non-blank characters, separated with
white space. An empty line is also considered to be a word and a
WORD.
*/
static inline bool IsWordChar(wxChar ch)
{
return !wxIsspace(ch);
}
wxTextPos wxTextCtrl::GetWordStart() const
{
if ( m_curPos == -1 || m_curPos == 0 )
return 0;
if ( m_curCol == 0 )
{
// go to the end of the previous line
return m_curPos - 1;
}
// it shouldn't be possible to learn where the word starts in the password
// text entry zone
if ( IsPassword() )
return 0;
// start at the previous position
const wxChar *p0 = GetLineText(m_curRow).c_str();
const wxChar *p = p0 + m_curCol - 1;
// find the end of the previous word
while ( (p > p0) && !IsWordChar(*p) )
p--;
// now find the beginning of this word
while ( (p > p0) && IsWordChar(*p) )
p--;
// we might have gone too far
if ( !IsWordChar(*p) )
p++;
return (m_curPos - m_curCol) + p - p0;
}
wxTextPos wxTextCtrl::GetWordEnd() const
{
if ( m_curPos == -1 )
return 0;
wxString line = GetLineText(m_curRow);
if ( (size_t)m_curCol == line.length() )
{
// if we're on the last position in the line, go to the next one - if
// it exists
wxTextPos pos = m_curPos;
if ( pos < GetLastPosition() )
pos++;
return pos;
}
// it shouldn't be possible to learn where the word ends in the password
// text entry zone
if ( IsPassword() )
return GetLastPosition();
// start at the current position
const wxChar *p0 = line.c_str();
const wxChar *p = p0 + m_curCol;
// find the start of the next word
while ( *p && !IsWordChar(*p) )
p++;
// now find the end of it
while ( *p && IsWordChar(*p) )
p++;
// and find the start of the next word
while ( *p && !IsWordChar(*p) )
p++;
return (m_curPos - m_curCol) + p - p0;
}
// ----------------------------------------------------------------------------
// clipboard stuff
// ----------------------------------------------------------------------------
void wxTextCtrl::Copy()
{
#if wxUSE_CLIPBOARD
if ( HasSelection() )
{
wxClipboardLocker clipLock;
// wxTextFile::Translate() is needed to transform all '\n' into "\r\n"
wxString text = wxTextFile::Translate(GetTextToShow(GetSelectionText()));
wxTextDataObject *data = new wxTextDataObject(text);
wxTheClipboard->SetData(data);
}
#endif // wxUSE_CLIPBOARD
}
void wxTextCtrl::Cut()
{
(void)DoCut();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?