318 lines
8.0 KiB
C++
318 lines
8.0 KiB
C++
|
|
|
|
#include "private.h"
|
|
#include "TextLayout.h"
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
BOOL CTextLayout::Layout(HDC hdc, const WCHAR *psz, UINT nCnt)
|
|
{
|
|
Clear();
|
|
|
|
// Count Line
|
|
UINT i = 0;
|
|
BOOL bNewLine = TRUE;
|
|
_nLineCnt = 0;
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
switch (psz[i])
|
|
{
|
|
case 0x0d:
|
|
case 0x0a:
|
|
bNewLine = TRUE;
|
|
break;
|
|
default:
|
|
if (bNewLine)
|
|
_nLineCnt++;
|
|
bNewLine = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_prgLines = (LINEINFO *)LocalAlloc(LPTR, _nLineCnt * sizeof(LINEINFO));
|
|
if (!_prgLines)
|
|
return FALSE;
|
|
|
|
// Count character of each line.
|
|
bNewLine = TRUE;
|
|
int nCurrentLine = -1;
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
switch (psz[i])
|
|
{
|
|
case 0x0d:
|
|
case 0x0a:
|
|
bNewLine = TRUE;
|
|
break;
|
|
default:
|
|
if (bNewLine)
|
|
{
|
|
nCurrentLine++;
|
|
_prgLines[nCurrentLine].nPos = i;
|
|
_prgLines[nCurrentLine].nCnt = 1;
|
|
}
|
|
else
|
|
{
|
|
_prgLines[nCurrentLine].nCnt++;
|
|
}
|
|
bNewLine = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
TEXTMETRIC tm;
|
|
GetTextMetrics(hdc, &tm);
|
|
_nLineHeight = tm.tmHeight + tm.tmExternalLeading;
|
|
|
|
POINT ptCurrent;
|
|
ptCurrent.x = 0;
|
|
ptCurrent.y = 0;
|
|
|
|
// Get the rectangle of each characters.
|
|
for (i = 0; i < _nLineCnt; i++)
|
|
{
|
|
_prgLines[i].prgCharInfo = NULL;
|
|
|
|
if (_prgLines[i].nCnt)
|
|
{
|
|
_prgLines[i].prgCharInfo = (CHARINFO *)LocalAlloc(LPTR, _prgLines[i].nCnt * sizeof(CHARINFO));
|
|
if (!_prgLines[i].prgCharInfo)
|
|
return FALSE;
|
|
|
|
UINT j;
|
|
POINT ptPrev = ptCurrent;
|
|
for (j = 0; j < _prgLines[i].nCnt; j++)
|
|
{
|
|
SIZE size;
|
|
GetTextExtentPoint32(hdc, psz+_prgLines[i].nPos, j + 1, &size);
|
|
ptCurrent.x = size.cx;
|
|
_prgLines[i].prgCharInfo[j].rc.left = ptPrev.x;
|
|
_prgLines[i].prgCharInfo[j].rc.top = ptPrev.y;
|
|
_prgLines[i].prgCharInfo[j].rc.right = ptCurrent.x;
|
|
_prgLines[i].prgCharInfo[j].rc.bottom = ptPrev.y + _nLineHeight;
|
|
|
|
ptPrev = ptCurrent;
|
|
}
|
|
}
|
|
|
|
ptCurrent.x = 0;
|
|
ptCurrent.y += _nLineHeight;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
BOOL CTextLayout::Render(HDC hdc, const WCHAR *psz, UINT nCnt, UINT nSelStart, UINT nSelEnd)
|
|
{
|
|
POINT ptCurrent;
|
|
ptCurrent.x = 0;
|
|
ptCurrent.y = 0;
|
|
|
|
// Render lines
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
if (_prgLines[i].nCnt)
|
|
{
|
|
TextOut(hdc,
|
|
ptCurrent.x,
|
|
ptCurrent.y,
|
|
psz + _prgLines[i].nPos,
|
|
_prgLines[i].nCnt);
|
|
}
|
|
ptCurrent.x = 0;
|
|
ptCurrent.y += _nLineHeight;
|
|
}
|
|
|
|
_fCaret = FALSE;
|
|
|
|
// Render selection/caret
|
|
RECT rcSel;
|
|
if (_nLineCnt)
|
|
{
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
if ((nSelEnd >= _prgLines[i].nPos) &&
|
|
(nSelStart <= _prgLines[i].nPos + _prgLines[i].nCnt))
|
|
{
|
|
UINT nSelStartInLine = 0;
|
|
UINT nSelEndInLine = _prgLines[i].nCnt;
|
|
|
|
if (nSelStart > _prgLines[i].nPos)
|
|
nSelStartInLine = nSelStart - _prgLines[i].nPos;
|
|
|
|
if (nSelEnd < _prgLines[i].nPos + _prgLines[i].nCnt)
|
|
nSelEndInLine = nSelEnd - _prgLines[i].nPos;
|
|
|
|
if (nSelStartInLine != nSelEndInLine)
|
|
{
|
|
for (UINT j = nSelStartInLine; j < nSelEndInLine; j++)
|
|
{
|
|
InvertRect(hdc, &_prgLines[i].prgCharInfo[j].rc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nSelStartInLine == _prgLines[i].nCnt)
|
|
{
|
|
rcSel = _prgLines[i].prgCharInfo[nSelStartInLine - 1].rc;
|
|
rcSel.left = rcSel.right;
|
|
rcSel.right++;
|
|
}
|
|
else
|
|
{
|
|
rcSel = _prgLines[i].prgCharInfo[nSelStartInLine].rc;
|
|
rcSel.right = rcSel.left + 1;
|
|
}
|
|
InvertRect(hdc, &rcSel);
|
|
_fCaret = TRUE;
|
|
_rcCaret = rcSel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rcSel.left = 0;
|
|
rcSel.top = 0;
|
|
rcSel.right = 1;
|
|
rcSel.bottom = _nLineHeight;
|
|
InvertRect(hdc, &rcSel);
|
|
_fCaret = TRUE;
|
|
_rcCaret = rcSel;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
void CTextLayout::BlinkCaret(HDC hdc)
|
|
{
|
|
if (_fCaret)
|
|
InvertRect(hdc, &_rcCaret);
|
|
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
BOOL CTextLayout::RectFromCharPos(UINT nPos, RECT *prc)
|
|
{
|
|
memset(prc, 0, sizeof(*prc));
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
if (nPos < _prgLines[i].nPos)
|
|
continue;
|
|
|
|
if (nPos >= _prgLines[i].nPos + _prgLines[i].nCnt)
|
|
{
|
|
if (((nPos -_prgLines[i].nPos) > 0) && (nPos == _prgLines[i].nPos + _prgLines[i].nCnt))
|
|
{
|
|
*prc = _prgLines[i].prgCharInfo[nPos - _prgLines[i].nPos - 1].rc;
|
|
prc->left = prc->right;
|
|
return TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
*prc = _prgLines[i].prgCharInfo[nPos - _prgLines[i].nPos].rc;
|
|
return TRUE;
|
|
}
|
|
|
|
prc->top = _nLineCnt * _nLineHeight;
|
|
prc->bottom = prc->top + _nLineHeight;
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
UINT CTextLayout::CharPosFromPoint(POINT pt)
|
|
{
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
for (UINT j = 0; j < _prgLines[i].nCnt; j++)
|
|
{
|
|
if (PtInRect(&_prgLines[i].prgCharInfo[j].rc, pt))
|
|
{
|
|
int nWidth = _prgLines[i].prgCharInfo[j].GetWidth();
|
|
if (pt.x > _prgLines[i].prgCharInfo[j].rc.left + (nWidth * 3 / 4))
|
|
{
|
|
return _prgLines[i].nPos + j + 1;
|
|
}
|
|
return _prgLines[i].nPos + j;
|
|
}
|
|
}
|
|
}
|
|
return (UINT)(-1);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
UINT CTextLayout::FineFirstEndCharPosInLine(UINT uCurPos, BOOL bFirst)
|
|
{
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
if ((_prgLines[i].nPos <= uCurPos) &&
|
|
(_prgLines[i].nPos + _prgLines[i].nCnt >= uCurPos))
|
|
{
|
|
if (bFirst)
|
|
{
|
|
return _prgLines[i].nPos;
|
|
}
|
|
else
|
|
{
|
|
return _prgLines[i].nPos + _prgLines[i].nCnt;
|
|
}
|
|
}
|
|
}
|
|
return (UINT)(-1);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
void CTextLayout::Clear()
|
|
{
|
|
if (_prgLines)
|
|
{
|
|
for (UINT i = 0; i < _nLineCnt; i++)
|
|
{
|
|
if (_prgLines[i].prgCharInfo)
|
|
{
|
|
LocalFree(_prgLines[i].prgCharInfo);
|
|
}
|
|
}
|
|
LocalFree(_prgLines);
|
|
}
|
|
_nLineCnt = 0;
|
|
}
|