#include #include #include "TextEditor.h" #include "../DebugLog.h" extern ITfThreadMgr *g_pThreadMgr; extern TfClientId g_TfClientId; //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::MoveSelection(UINT nSelStart, UINT nSelEnd) { UINT nTextLength = GetTextLength(); if (nSelStart >= nTextLength) nSelStart = nTextLength; if (nSelEnd >= nTextLength) nSelEnd = nTextLength; _nSelStart = nSelStart; _nSelEnd = nSelEnd; _layout.ResetCaretBlink(); _layout.EnsureCaretVisible(_nSelEnd); _pTextStore->OnSelectionChange(); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::MoveSelectionNext() { UINT nTextLength = GetTextLength(); if (_nSelEnd < nTextLength) _nSelEnd++; _nSelStart = _nSelEnd; _layout.ResetCaretBlink(); _pTextStore->OnSelectionChange(); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::MoveSelectionPrev() { if (_nSelStart > 0) _nSelStart--; _nSelEnd = _nSelStart; _layout.ResetCaretBlink(); _pTextStore->OnSelectionChange(); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::MoveSelectionAtPoint(POINT pt) { const UINT nSel = _layout.InsertionIndexFromPoint(pt); MoveSelection(nSel, nSel); return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::MoveSelectionUpDown(BOOL bUp) { RECT rc; if (!_layout.RectFromCharPos(_nSelStart, &rc)) return FALSE; POINT pt; pt.x = rc.left; if (bUp) { pt.y = rc.top - ((rc.bottom - rc.top) / 2); if (pt.y < 0) return FALSE; } else { pt.y = rc.bottom + ((rc.bottom - rc.top) / 2); } return MoveSelectionAtPoint(pt); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::MoveSelectionToLineFirstEnd(BOOL bFirst) { BOOL bRet = FALSE; UINT nSel; if (bFirst) { nSel = _layout.FineFirstEndCharPosInLine(_nSelStart, TRUE); } else { nSel = _layout.FineFirstEndCharPosInLine(_nSelEnd, FALSE); } if (nSel != (UINT)-1) { MoveSelection(nSel, nSel); bRet = TRUE; } return bRet; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::InsertAtSelection(LPCWSTR psz) { LONG lOldSelEnd = _nSelEnd; if (!RemoveText(_nSelStart, _nSelEnd - _nSelStart)) return FALSE; if (!InsertText(_nSelStart, psz, lstrlen(psz))) return FALSE; _nSelStart += lstrlen(psz); _nSelEnd = _nSelStart; _layout.ResetCaretBlink(); UpdateLayout(); _layout.EnsureCaretVisible(_nSelEnd); _pTextStore->OnTextChange(_nSelStart, lOldSelEnd, _nSelEnd); _pTextStore->OnSelectionChange(); return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::DeleteAtSelection(BOOL fBack) { // Check if we are in composition state if (_pTextStore->GetCurrentCompositionView() && GetTextLength() == 0) { TerminateCompositionString(); return TRUE; } if (!fBack && (_nSelEnd < GetTextLength())) { if (!RemoveText(_nSelEnd, 1)) return FALSE; _layout.ResetCaretBlink(); UpdateLayout(); _layout.EnsureCaretVisible(_nSelEnd); _pTextStore->OnTextChange(_nSelEnd, _nSelEnd + 1, _nSelEnd); } if (fBack && (_nSelStart > 0)) { if (!RemoveText(_nSelStart - 1, 1)) return FALSE; _nSelStart--; _nSelEnd = _nSelStart; _layout.ResetCaretBlink(); UpdateLayout(); _layout.EnsureCaretVisible(_nSelEnd); _pTextStore->OnTextChange(_nSelStart, _nSelStart + 1, _nSelStart); _pTextStore->OnSelectionChange(); } return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::DeleteSelection() { ULONG nSelOldEnd = _nSelEnd; RemoveText(_nSelStart, _nSelEnd - _nSelStart); _nSelEnd = _nSelStart; _layout.ResetCaretBlink(); UpdateLayout(); _layout.EnsureCaretVisible(_nSelEnd); _pTextStore->OnTextChange(_nSelStart, nSelOldEnd, _nSelStart); _pTextStore->OnSelectionChange(); return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::InitializeRenderResources(IDWriteFactory *pDWriteFactory) { return _layout.Initialize(pDWriteFactory); } void CTextEditor::SetFont(const LOGFONT *plf) { if (!plf) { return; } _lfCurrentFont = *plf; _fHasFont = TRUE; UpdateLayout(); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::Render(ID2D1HwndRenderTarget *pRenderTarget) { if (!_fHasFont) { return; } _layout.Render(pRenderTarget, GetTextBuffer(), GetTextLength(), _nSelStart, _nSelEnd, _pCompositionRenderInfo, _nCompositionRenderInfo); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::UpdateLayout() { if (!_hwnd || !_fHasFont) { return; } const FLOAT dpi = static_cast(GetDpiForWindow(_hwnd)); const LONG width = max(_rcHost.right - _rcHost.left, 1L); _layout.Layout(GetTextBuffer(), GetTextLength(), &_lfCurrentFont, static_cast(width), dpi, dpi, static_cast(_rcContentPadding.left), static_cast(_rcContentPadding.top), static_cast(_rcContentPadding.right), static_cast(_rcContentPadding.bottom), _singleLine); _layout.EnsureCaretVisible(_nSelEnd); } void CTextEditor::NotifyLayoutChange() { if (_pTextStore) { _pTextStore->OnLayoutChange(); } } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::InitTSF() { _pTextStore = new CTextStore(this); if (!_pTextStore) { return FALSE; } if (FAILED(g_pThreadMgr->CreateDocumentMgr(&_pDocumentMgr))) { return FALSE; } if (FAILED(_pDocumentMgr->CreateContext(g_TfClientId, 0, (ITextStoreACP *)_pTextStore, &_pInputContext, &_ecTextStore))) { return FALSE; } if (FAILED(_pDocumentMgr->Push(_pInputContext))) { return FALSE; } _pTextEditSink = new CTextEditSink(this); if (!_pTextEditSink) { return FALSE; } _pTextEditSink->_Advise(_pInputContext); return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::UninitTSF() { if (_pTextEditSink) { _pTextEditSink->_Unadvise(); _pTextEditSink->Release(); _pTextEditSink = NULL; } if (_pDocumentMgr) { _pDocumentMgr->Pop(TF_POPF_ALL); } if (_pInputContext) { _pInputContext->Release(); _pInputContext = NULL; } if (_pDocumentMgr) { _pDocumentMgr->Release(); _pDocumentMgr = NULL; } if (_pTextStore) { _pTextStore->Release(); _pTextStore = NULL; } return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::SetFocusDocumentMgr() { if (_pDocumentMgr) { const HRESULT hr = g_pThreadMgr->SetFocus(_pDocumentMgr); std::ostringstream oss; oss << "CTextEditor::SetFocusDocumentMgr editor=" << this << " docMgr=" << _pDocumentMgr << " hwnd=" << GetWnd() << " hr=0x" << std::hex << static_cast(hr); msimeui::DebugLog(oss.str()); } } void CTextEditor::ClearFocusDocumentMgr() { if (!_pDocumentMgr) { return; } const HRESULT hr = g_pThreadMgr->SetFocus(nullptr); std::ostringstream oss; oss << "CTextEditor::ClearFocusDocumentMgr editor=" << this << " docMgr=" << _pDocumentMgr << " hwnd=" << GetWnd() << " hr=0x" << std::hex << static_cast(hr); msimeui::DebugLog(oss.str()); } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::ClearCompositionRenderInfo() { if (_pCompositionRenderInfo) { LocalFree(_pCompositionRenderInfo); _pCompositionRenderInfo = NULL; _nCompositionRenderInfo = 0; } } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- BOOL CTextEditor::AddCompositionRenderInfo(int nStart, int nEnd, TF_DISPLAYATTRIBUTE *pda) { if (_pCompositionRenderInfo) { void *pvNew = LocalReAlloc(_pCompositionRenderInfo, (_nCompositionRenderInfo + 1) * sizeof(COMPOSITIONRENDERINFO), LMEM_MOVEABLE | LMEM_ZEROINIT); if (!pvNew) return FALSE; _pCompositionRenderInfo = (COMPOSITIONRENDERINFO *)pvNew; } else { _pCompositionRenderInfo = (COMPOSITIONRENDERINFO *)LocalAlloc(LPTR, (_nCompositionRenderInfo + 1) * sizeof(COMPOSITIONRENDERINFO)); if (!_pCompositionRenderInfo) return FALSE; } _pCompositionRenderInfo[_nCompositionRenderInfo].nStart = nStart; _pCompositionRenderInfo[_nCompositionRenderInfo].nEnd = nEnd; _pCompositionRenderInfo[_nCompositionRenderInfo].da = *pda; _nCompositionRenderInfo++; return TRUE; } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::TerminateCompositionString() { if (_pTextStore->GetCurrentCompositionView()) { ITfContextOwnerCompositionServices *pCompositionServices; if (_pInputContext->QueryInterface(IID_ITfContextOwnerCompositionServices, (void **)&pCompositionServices) == S_OK) { pCompositionServices->TerminateComposition(_pTextStore->GetCurrentCompositionView()); pCompositionServices->Release(); } // Clear composition render info ClearCompositionRenderInfo(); InvalidateRect(); } } //---------------------------------------------------------------- // // // //---------------------------------------------------------------- void CTextEditor::AleartMouseSink(POINT pt, DWORD dwBtnState, BOOL *pbEaten) { UINT nSel = _layout.ExactCharPosFromPoint(pt); if (nSel == (UINT)-1) { return; } RECT rc; if (!_layout.RectFromCharPos(nSel, &rc)) { return; } int nPos = (pt.x - rc.left) * 4 / (rc.right - rc.left) + 2; UINT uEdge = nSel + (nPos / 4); UINT uQuadrant = nPos % 4; _pTextStore->OnMouseEvent(uEdge, uQuadrant, dwBtnState, pbEaten); }