textctrl.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,131 行 · 第 1/5 页

CPP
2,131
字号
        // position didn't actually change!)
        MData().m_xCaret = -1;
    }

    ClearSelection();
}

void wxTextCtrl::InitInsertionPoint()
{
    // so far always put it in the beginning
    DoSetInsertionPoint(0);

    // this will also set the selection anchor correctly
    ClearSelection();
}

void wxTextCtrl::MoveInsertionPoint(wxTextPos pos)
{
    wxASSERT_MSG( pos >= 0 && pos <= GetLastPosition(),
                 _T("DoSetInsertionPoint() can only be called with valid pos") );

    m_curPos = pos;
    PositionToXY(m_curPos, &m_curCol, &m_curRow);
}

void wxTextCtrl::DoSetInsertionPoint(wxTextPos pos)
{
    MoveInsertionPoint(pos);

    ShowPosition(pos);
}

void wxTextCtrl::SetInsertionPointEnd()
{
    SetInsertionPoint(GetLastPosition());
}

wxTextPos wxTextCtrl::GetInsertionPoint() const
{
    return m_curPos;
}

wxTextPos wxTextCtrl::GetLastPosition() const
{
    wxTextPos pos;
    if ( IsSingleLine() )
    {
        pos = m_value.length();
    }
    else // multiline
    {
#ifdef WXDEBUG_TEXT
        pos = 0;
        size_t nLineCount = GetLineCount();
        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 += GetLines()[nLine].length() + 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--;
        }

        // more probable reason of this would be to forget to update m_posLast
        wxASSERT_MSG( pos == m_posLast, _T("bug in GetLastPosition()") );
#endif // WXDEBUG_TEXT

        pos = m_posLast;
    }

    return pos;
}

// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------

void wxTextCtrl::GetSelection(wxTextPos* from, wxTextPos* to) const
{
    if ( from )
        *from = m_selStart;
    if ( to )
        *to = m_selEnd;
}

wxString wxTextCtrl::GetSelectionText() const
{
    wxString sel;

    if ( HasSelection() )
    {
        if ( IsSingleLine() )
        {
            sel = m_value.Mid(m_selStart, m_selEnd - m_selStart);
        }
        else // multiline
        {
            wxTextCoord 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 = GetLines()[lineStart].Mid(colStart, colEnd - colStart);
            }
            else // sel on multiple lines
            {
                // take the end of the first line
                sel = GetLines()[lineStart].c_str() + colStart;
                sel += _T('\n');

                // all intermediate ones
                for ( wxTextCoord line = lineStart + 1; line < lineEnd; line++ )
                {
                    sel << GetLines()[line] << _T('\n');
                }

                // and the start of the last one
                sel += GetLines()[lineEnd].Left(colEnd);
            }
        }
    }

    return sel;
}

void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to)
{
    // selecting till -1 is the same as selecting to the end
    if ( to == -1 && from != -1 )
    {
        to = GetLastPosition();
    }

    if ( from == -1 || to == from )
    {
        ClearSelection();
    }
    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") );

        if ( from != m_selStart || to != m_selEnd )
        {
            // we need to use temp vars as RefreshTextRange() may call DoDraw()
            // directly and so m_selStart/End must be reset by then
            wxTextPos selStartOld = m_selStart,
                      selEndOld = m_selEnd;

            m_selStart = from;
            m_selEnd = to;

            wxLogTrace(_T("text"), _T("Selection range is %ld-%ld"),
                       m_selStart, m_selEnd);

            // refresh only the part of text which became (un)selected if
            // possible
            if ( selStartOld == m_selStart )
            {
                RefreshTextRange(selEndOld, m_selEnd);
            }
            else if ( selEndOld == m_selEnd )
            {
                RefreshTextRange(m_selStart, selStartOld);
            }
            else
            {
                // OPT: could check for other cases too but it is probably not
                //      worth it as the two above are the most common ones
                if ( selStartOld != -1 )
                    RefreshTextRange(selStartOld, selEndOld);
                if ( m_selStart != -1 )
                    RefreshTextRange(m_selStart, m_selEnd);
            }

            // we need to fully repaint the invalidated areas of the window
            // before scrolling it (from DoSetInsertionPoint which is typically
            // called after SetSelection()), otherwise they may stay unpainted
            m_targetWindow->Update();
        }
        //else: nothing to do

        // the insertion point is put at the location where the caret was moved
        DoSetInsertionPoint(toOrig);
    }
}

void wxTextCtrl::ClearSelection()
{
    if ( HasSelection() )
    {
        // we need to use temp vars as RefreshTextRange() may call DoDraw()
        // directly (see above as well)
        wxTextPos selStart = m_selStart,
                  selEnd = m_selEnd;

        // no selection any more
        m_selStart =
        m_selEnd = -1;

        // refresh the old selection
        RefreshTextRange(selStart, selEnd);
    }

    // the anchor should be moved even if there was no selection previously
    m_selAnchor = m_curPos;
}

void wxTextCtrl::RemoveSelection()
{
    if ( !HasSelection() )
        return;

    Remove(m_selStart, m_selEnd);
}

bool wxTextCtrl::GetSelectedPartOfLine(wxTextCoord line,
                                       wxTextPos *start, wxTextPos *end) const
{
    if ( start )
        *start = -1;
    if ( end )
        *end = -1;

    if ( !HasSelection() )
    {
        // no selection at all, hence no selection in this line
        return false;
    }

    wxTextCoord lineStart, colStart;
    PositionToXY(m_selStart, &colStart, &lineStart);
    if ( lineStart > line )
    {
        // this line is entirely above the selection
        return false;
    }

    wxTextCoord lineEnd, colEnd;
    PositionToXY(m_selEnd, &colEnd, &lineEnd);
    if ( lineEnd < line )
    {
        // this line is entirely below the selection
        return false;
    }

    if ( line == lineStart )
    {
        if ( start )
            *start = colStart;
        if ( end )
            *end = lineEnd == lineStart ? colEnd : GetLineLength(line);
    }
    else if ( line == lineEnd )
    {
        if ( start )
            *start = lineEnd == lineStart ? colStart : 0;
        if ( end )
            *end = colEnd;
    }
    else // the line is entirely inside the selection
    {
        if ( start )
            *start = 0;
        if ( end )
            *end = GetLineLength(line);
    }

    return true;
}

// ----------------------------------------------------------------------------
// flags
// ----------------------------------------------------------------------------

bool wxTextCtrl::IsModified() const
{
    return m_isModified;
}

bool wxTextCtrl::IsEditable() const
{
    // disabled control can never be edited
    return m_isEditable && IsEnabled();
}

void wxTextCtrl::MarkDirty()
{
    m_isModified = true;
}

void wxTextCtrl::DiscardEdits()
{
    m_isModified = false;
}

void wxTextCtrl::SetEditable(bool editable)
{
    if ( editable != m_isEditable )
    {
        m_isEditable = editable;

        // the caret (dis)appears
        CreateCaret();

        // the appearance of the control might have changed
        Refresh();
    }
}

// ----------------------------------------------------------------------------
// col/lines <-> position correspondence
// ----------------------------------------------------------------------------

/*
    A few remarks about this stuff:

    o   The numbering of the text control columns/rows starts from 0.
    o   Start of first line is position 0, its last position is line.length()
    o   Start of the next line is the last position of the previous line + 1
 */

int wxTextCtrl::GetLineLength(wxTextCoord line) const
{
    if ( IsSingleLine() )
    {
        wxASSERT_MSG( line == 0, _T("invalid GetLineLength() parameter") );

        return m_value.length();
    }
    else // multiline
    {
        wxCHECK_MSG( (size_t)line < GetLineCount(), -1,
                     _T("line index out of range") );

        return GetLines()[line].length();
    }
}

wxString wxTextCtrl::GetLineText(wxTextCoord line) const
{
    if ( IsSingleLine() )
    {
        wxASSERT_MSG( line == 0, _T("invalid GetLineLength() parameter") );

        return m_value;
    }
    else // multiline
    {
        //this is called during DoGetBestSize
        if (line == 0 && GetLineCount() == 0) return wxEmptyString ;

        wxCHECK_MSG( (size_t)line < GetLineCount(), wxEmptyString,
                     _T("line index out of range") );

        return GetLines()[line];
    }
}

int wxTextCtrl::GetNumberOfLines() const
{
    // there is always 1 line, even if the text is empty
    return IsSingleLine() ? 1 : GetLineCount();
}

wxTextPos wxTextCtrl::XYToPosition(wxTextCoord x, wxTextCoord y) const
{
    // note that this method should accept any values of x and y and return -1
    // if they are out of range
    if ( IsSingleLine() )
    {
        return ( x > GetLastPosition() || y > 0 ) ? wxOutOfRangeTextCoord : x;
    }
    else // multiline
    {
        if ( (size_t)y >= GetLineCount() )
        {
            // this position is below the text
            return GetLastPosition();
        }

        wxTextPos 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 += GetLines()[nLine].length() + 1;
        }

        // take into account also the position in line
        if ( (size_t)x > GetLines()[y].length() )
        {
            // don't return position in the next line
            x = GetLines()[y].length();
        }

        return pos + x;
    }
}

bool wxTextCtrl::PositionToXY(wxTextPos pos,
                              wxTextCoord *x, wxTextCoord *y) const
{
    if ( IsSingleLine() )
    {
        if ( (size_t)pos > m_value.length() )
            return false;

        if ( x )
            *x = pos;
        if ( y )
            *y = 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?