textctrl.cpp

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

CPP
2,166
字号
{
    if ( wxTextCtrlBase::LoadFile(file) )
    {
        // update the size limit if needed
        AdjustSpaceLimit();

        return true;
    }

    return false;
}

// ----------------------------------------------------------------------------
// Editing
// ----------------------------------------------------------------------------

void wxTextCtrl::Replace(long from, long to, const wxString& value)
{
    // Set selection and remove it
    DoSetSelection(from, to, false /* don't scroll caret into view */);

    DoWriteText(value, true /* selection only */);
}

void wxTextCtrl::Remove(long from, long to)
{
    Replace(from, to, wxEmptyString);
}

bool wxTextCtrl::IsModified() const
{
    return ::SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
}

void wxTextCtrl::MarkDirty()
{
    ::SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0L);
}

void wxTextCtrl::DiscardEdits()
{
    ::SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
}

int wxTextCtrl::GetNumberOfLines() const
{
    return (int)::SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
}

// ----------------------------------------------------------------------------
// Positions <-> coords
// ----------------------------------------------------------------------------

long wxTextCtrl::XYToPosition(long x, long y) const
{
    // This gets the char index for the _beginning_ of this line
    long charIndex = ::SendMessage(GetHwnd(), EM_LINEINDEX, (WPARAM)y, (LPARAM)0);

    return charIndex + x;
}

bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
{
    HWND hWnd = GetHwnd();

    // This gets the line number containing the character
    long lineNo;
#if wxUSE_RICHEDIT
    if ( IsRich() )
    {
        lineNo = ::SendMessage(hWnd, EM_EXLINEFROMCHAR, 0, (LPARAM)pos);
    }
    else
#endif // wxUSE_RICHEDIT
    {
        lineNo = ::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, 0);
    }

    if ( lineNo == -1 )
    {
        // no such line
        return false;
    }

    // This gets the char index for the _beginning_ of this line
    long charIndex = ::SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
    if ( charIndex == -1 )
    {
        return false;
    }

    // The X position must therefore be the different between pos and charIndex
    if ( x )
        *x = pos - charIndex;
    if ( y )
        *y = lineNo;

    return true;
}

wxTextCtrlHitTestResult
wxTextCtrl::HitTest(const wxPoint& pt, long *posOut) const
{
    // first get the position from Windows
    LPARAM lParam;

#if wxUSE_RICHEDIT
    POINTL ptl;
    if ( IsRich() )
    {
        // for rich edit controls the position is passed iva the struct fields
        ptl.x = pt.x;
        ptl.y = pt.y;
        lParam = (LPARAM)&ptl;
    }
    else
#endif // wxUSE_RICHEDIT
    {
        // for the plain ones, we are limited to 16 bit positions which are
        // combined in a single 32 bit value
        lParam = MAKELPARAM(pt.x, pt.y);
    }

    LRESULT pos = ::SendMessage(GetHwnd(), EM_CHARFROMPOS, 0, lParam);

    if ( pos == -1 )
    {
        // this seems to indicate an error...
        return wxTE_HT_UNKNOWN;
    }

#if wxUSE_RICHEDIT
    if ( !IsRich() )
#endif // wxUSE_RICHEDIT
    {
        // for plain EDIT controls the higher word contains something else
        pos = LOWORD(pos);
    }


    // next determine where it is relatively to our point: EM_CHARFROMPOS
    // always returns the closest character but we need to be more precise, so
    // double check that we really are where it pretends
    POINTL ptReal;

#if wxUSE_RICHEDIT
    // FIXME: we need to distinguish between richedit 2 and 3 here somehow but
    //        we don't know how to do it
    if ( IsRich() )
    {
        ::SendMessage(GetHwnd(), EM_POSFROMCHAR, (WPARAM)&ptReal, pos);
    }
    else
#endif // wxUSE_RICHEDIT
    {
        LRESULT lRc = ::SendMessage(GetHwnd(), EM_POSFROMCHAR, pos, 0);

        if ( lRc == -1 )
        {
            // this is apparently returned when pos corresponds to the last
            // position
            ptReal.x =
            ptReal.y = 0;
        }
        else
        {
            ptReal.x = LOWORD(lRc);
            ptReal.y = HIWORD(lRc);
        }
    }

    wxTextCtrlHitTestResult rc;

    if ( pt.y > ptReal.y + GetCharHeight() )
        rc = wxTE_HT_BELOW;
    else if ( pt.x > ptReal.x + GetCharWidth() )
        rc = wxTE_HT_BEYOND;
    else
        rc = wxTE_HT_ON_TEXT;

    if ( posOut )
        *posOut = pos;

    return rc;
}

// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------

void wxTextCtrl::ShowPosition(long pos)
{
    HWND hWnd = GetHwnd();

    // To scroll to a position, we pass the number of lines and characters
    // to scroll *by*. This means that we need to:
    // (1) Find the line position of the current line.
    // (2) Find the line position of pos.
    // (3) Scroll by (pos - current).
    // For now, ignore the horizontal scrolling.

    // Is this where scrolling is relative to - the line containing the caret?
    // Or is the first visible line??? Try first visible line.
//    int currentLineLineNo1 = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L);

    int currentLineLineNo = (int)::SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, (WPARAM)0, (LPARAM)0L);

    int specifiedLineLineNo = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);

    int linesToScroll = specifiedLineLineNo - currentLineLineNo;

    if (linesToScroll != 0)
      (void)::SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
}

long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
{
    return ::SendMessage(GetHwnd(), EM_LINELENGTH, (WPARAM)pos, 0);
}

int wxTextCtrl::GetLineLength(long lineNo) const
{
    long pos = XYToPosition(0, lineNo);

    return GetLengthOfLineContainingPos(pos);
}

wxString wxTextCtrl::GetLineText(long lineNo) const
{
    size_t len = (size_t)GetLineLength(lineNo) + 1;

    // there must be at least enough place for the length WORD in the
    // buffer
    len += sizeof(WORD);

    wxString str;
    {
        wxStringBufferLength tmp(str, len);
        wxChar *buf = tmp;

        *(WORD *)buf = (WORD)len;
        len = (size_t)::SendMessage(GetHwnd(), EM_GETLINE, lineNo, (LPARAM)buf);

#if wxUSE_RICHEDIT
        if ( IsRich() )
        {
            // remove the '\r' returned by the rich edit control, the user code
            // should never see it
            if ( buf[len - 2] == _T('\r') && buf[len - 1] == _T('\n') )
            {
                buf[len - 2] = _T('\n');
                len--;
            }
        }
#endif // wxUSE_RICHEDIT

        // remove the '\n' at the end, if any (this is how this function is
        // supposed to work according to the docs)
        if ( buf[len - 1] == _T('\n') )
        {
            len--;
        }

        buf[len] = 0;
        tmp.SetLength(len);
    }

    return str;
}

void wxTextCtrl::SetMaxLength(unsigned long len)
{
#if wxUSE_RICHEDIT
    if ( IsRich() )
    {
        ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, len ? len : 0x7fffffff);
    }
    else
#endif // wxUSE_RICHEDIT
    {
        if ( len >= 0xffff )
        {
            // this will set it to a platform-dependent maximum (much more
            // than 64Kb under NT)
            len = 0;
        }

        ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
    }
}

// ----------------------------------------------------------------------------
// Undo/redo
// ----------------------------------------------------------------------------

void wxTextCtrl::Undo()
{
    if (CanUndo())
    {
        ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
    }
}

void wxTextCtrl::Redo()
{
    if (CanRedo())
    {
#if wxUSE_RICHEDIT
        if (GetRichVersion() > 1)
            ::SendMessage(GetHwnd(), EM_REDO, 0, 0);
        else
#endif
        // Same as Undo, since Undo undoes the undo, i.e. a redo.
        ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
    }
}

bool wxTextCtrl::CanUndo() const
{
    return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
}

bool wxTextCtrl::CanRedo() const
{
#if wxUSE_RICHEDIT
    if (GetRichVersion() > 1)
        return ::SendMessage(GetHwnd(), EM_CANREDO, 0, 0) != 0;
    else
#endif
    return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
}

// ----------------------------------------------------------------------------
// caret handling (Windows only)
// ----------------------------------------------------------------------------

bool wxTextCtrl::ShowNativeCaret(bool show)
{
    if ( show != m_isNativeCaretShown )
    {
        if ( !(show ? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) )
        {
            // not an error, may simply indicate that it's not shown/hidden
            // yet (i.e. it had been hidden/showh 2 times before)
            return false;
        }

        m_isNativeCaretShown = show;
    }

    return true;
}

// ----------------------------------------------------------------------------
// implemenation details
// ----------------------------------------------------------------------------

void wxTextCtrl::Command(wxCommandEvent & event)
{
    SetValue(event.GetString());
    ProcessCommand (event);
}

void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
{
    // By default, load the first file into the text window.
    if (event.GetNumberOfFiles() > 0)
    {
        LoadFile(event.GetFiles()[0]);
    }
}

// ----------------------------------------------------------------------------
// kbd input processing
// ----------------------------------------------------------------------------

bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* pMsg)
{
    MSG *msg = (MSG *)pMsg;

    // check for our special keys here: if we don't do it and the parent frame
    // uses them as accelerators, they wouldn't work at all, so we disable
    // usual preprocessing for them
    if ( msg->message == WM_KEYDOWN )
    {
        WORD vkey = (WORD) msg->wParam;
        if ( (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
        {
            if ( vkey == VK_BACK )
                return false;
        }
        else // no Alt
        {
            // we want to process some Ctrl-foo and Shift-bar but no key
            // combinations without either Ctrl or Shift nor with both of them
            // pressed
            const int ctrl = wxIsCtrlDown(),
                      shift = wxIsShiftDown();
            switch ( ctrl + shift )
            {
                default:
                    wxFAIL_MSG( _T("how many modifiers have we got?") );
                    // fall through

                case 0:
                case 2:
                    break;

                case 1:
                    // either Ctrl or Shift pressed
                    if ( ctrl )
                    {
                        switch ( vkey )
                        {
                            case 'C':
                            case 'V':
                            case 'X':
                            case VK_INSERT:
                            case VK_DELETE:
                            case VK_HOME:
                            case VK_END:
                                return false;
                        }
                    }
                    else // Shift is pressed
                    {
                        if ( vkey == VK_INSERT || vkey == VK_DELETE )
                            return false;
                    }
            }
        }
    }

    return wxControl::MSWShouldPreProcessMessage(pMsg);

⌨️ 快捷键说明

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