📄 editor.c
字号:
case rtfQuadCenter:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_CENTER;
break;
case rtfTabPos:
ME_GetSelectionParaFormat(info->editor, &fmt);
if (!(fmt.dwMask & PFM_TABSTOPS))
{
fmt.dwMask |= PFM_TABSTOPS;
fmt.cTabCount = 0;
}
if (fmt.cTabCount < MAX_TAB_STOPS)
fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam;
break;
}
if (fmt.dwMask) {
RTFFlushOutputBuffer(info);
/* FIXME too slow ? how come ?*/
ME_SetSelectionParaFormat(info->editor, &fmt);
}
}
static void ME_RTFReadHook(RTF_Info *info) {
switch(info->rtfClass)
{
case rtfGroup:
switch(info->rtfMajor)
{
case rtfBeginGroup:
if (info->stackTop < maxStack) {
memcpy(&info->stack[info->stackTop].fmt, &info->style->fmt, sizeof(CHARFORMAT2W));
info->stack[info->stackTop].codePage = info->codePage;
info->stack[info->stackTop].unicodeLength = info->unicodeLength;
}
info->stackTop++;
info->styleChanged = FALSE;
break;
case rtfEndGroup:
{
ME_Style *s;
RTFFlushOutputBuffer(info);
if (info->stackTop<=1) {
info->rtfClass = rtfEOF;
return;
}
info->stackTop--;
assert(info->stackTop >= 0);
if (info->styleChanged)
{
/* FIXME too slow ? how come ? */
s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt);
ME_ReleaseStyle(info->style);
info->style = s;
info->codePage = info->stack[info->stackTop].codePage;
info->unicodeLength = info->stack[info->stackTop].unicodeLength;
}
break;
}
}
break;
case rtfControl:
switch(info->rtfMajor)
{
case rtfCharAttr:
ME_RTFCharAttrHook(info);
break;
case rtfParAttr:
ME_RTFParAttrHook(info);
break;
}
break;
}
}
void
ME_StreamInFill(ME_InStream *stream)
{
stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie,
(BYTE *)stream->buffer,
sizeof(stream->buffer),
(LONG *)&stream->dwSize);
stream->dwUsed = 0;
}
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
{
RTF_Info parser;
ME_Style *style;
int from, to, to2, nUndoMode;
ME_UndoItem *pUI;
int nEventMask = editor->nEventMask;
ME_InStream inStream;
TRACE("stream==%p hWnd==%p format==0x%X\n", stream, editor->hWnd, (UINT)format);
editor->nEventMask = 0;
ME_GetSelection(editor, &from, &to);
if (format & SFF_SELECTION) {
style = ME_GetSelectionInsertStyle(editor);
ME_InternalDeleteText(editor, from, to-from);
}
else {
style = editor->pBuffer->pDefaultStyle;
ME_AddRefStyle(style);
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
from = to = 0;
ME_ClearTempStyle(editor);
/* FIXME restore default paragraph formatting ! */
}
nUndoMode = editor->nUndoMode;
editor->nUndoMode = umIgnore;
inStream.editstream = stream;
inStream.editstream->dwError = 0;
inStream.dwSize = 0;
inStream.dwUsed = 0;
if (format & SF_RTF)
{
/* Check if it's really RTF, and if it is not, use plain text */
ME_StreamInFill(&inStream);
if (!inStream.editstream->dwError)
{
if (strncmp(inStream.buffer, "{\\rtf1", 6) && strncmp(inStream.buffer, "{\\urtf", 6))
{
format &= ~SF_RTF;
format |= SF_TEXT;
}
}
}
if (!inStream.editstream->dwError)
{
if (format & SF_RTF) {
/* setup the RTF parser */
memset(&parser, 0, sizeof parser);
RTFSetEditStream(&parser, &inStream);
parser.rtfFormat = format&(SF_TEXT|SF_RTF);
parser.hwndEdit = editor->hWnd;
parser.editor = editor;
parser.style = style;
WriterInit(&parser);
RTFInit(&parser);
RTFSetReadHook(&parser, ME_RTFReadHook);
BeginFile(&parser);
/* do the parsing */
RTFRead(&parser);
RTFFlushOutputBuffer(&parser);
RTFDestroy(&parser);
style = parser.style;
}
else if (format & SF_TEXT)
ME_StreamInText(editor, format, &inStream, style);
else
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
ME_GetSelection(editor, &to, &to2);
/* put the cursor at the top */
if (!(format & SFF_SELECTION))
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
else
{
/* FIXME where to put cursor now ? */
}
}
editor->nUndoMode = nUndoMode;
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
TRACE("from %d to %d\n", from, to);
if (pUI && from < to)
{
pUI->nStart = from;
pUI->nLen = to-from;
}
ME_CommitUndo(editor);
ME_ReleaseStyle(style);
editor->nEventMask = nEventMask;
if (editor->bRedraw)
{
InvalidateRect(editor->hWnd, NULL, TRUE);
ME_UpdateRepaint(editor);
}
if (!(format & SFF_SELECTION)) {
ME_ClearTempStyle(editor);
}
ME_MoveCaret(editor);
ME_SendSelChange(editor);
ME_SendRequestResize(editor, FALSE);
return 0;
}
ME_DisplayItem *
ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset)
{
ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset)
item = ME_FindItemFwd(item, diParagraph);
if (!item)
return item;
nOffset -= item->member.para.nCharOfs;
if (nItemType == diParagraph) {
if (nItemOffset)
*nItemOffset = nOffset;
return item;
}
do {
item = ME_FindItemFwd(item, diRun);
} while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset));
if (item) {
nOffset -= item->member.run.nCharOfs;
if (nItemOffset)
*nItemOffset = nOffset;
}
return item;
}
static int
ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, WCHAR *text, CHARRANGE *chrgText)
{
int nStart, nEnd;
int nLen = lstrlenW(text);
int nMin, nMax;
ME_DisplayItem *item;
ME_DisplayItem *para;
TRACE("flags==0x%08lx, chrg->cpMin==%ld, chrg->cpMax==%ld text==%s\n",
flags, chrg->cpMin, chrg->cpMax, debugstr_w(text));
if (!(flags & FR_MATCHCASE))
FIXME("Case-insensitive search not implemented\n");
if (flags & ~(FR_DOWN | FR_MATCHCASE))
FIXME("Flags 0x%08lx not implemented\n", flags & ~(FR_DOWN | FR_MATCHCASE));
if (chrg->cpMax == -1)
{
nMin = chrg->cpMin;
nMax = ME_GetTextLength(editor);
}
else
{
nMin = min(chrg->cpMin, chrg->cpMax);
nMax = max(chrg->cpMin, chrg->cpMax);
}
if (!nLen)
{
if (chrgText)
chrgText->cpMin = chrgText->cpMax = ((flags & FR_DOWN) ? nMin : nMax);
return chrgText->cpMin;
}
if (flags & FR_DOWN) /* Forward search */
{
nStart = nMin;
item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
if (!item)
return -1;
para = ME_GetParagraph(item);
while (item
&& para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen < nMax)
{
ME_DisplayItem *pCurItem = item;
int nCurStart = nStart;
int nMatched = 0;
while (pCurItem && pCurItem->member.run.strText->szData[nCurStart + nMatched] == text[nMatched])
{
nMatched++;
if (nMatched == nLen)
{
nStart += para->member.para.nCharOfs + item->member.run.nCharOfs;
if (chrgText)
{
chrgText->cpMin = nStart;
chrgText->cpMax = nStart + nLen;
}
TRACE("found at %d-%d\n", nStart, nStart + nLen);
return nStart;
}
if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText))
{
pCurItem = ME_FindItemFwd(pCurItem, diRun);
para = ME_GetParagraph(pCurItem);
nCurStart = -nMatched;
}
}
nStart++;
if (nStart == ME_StrLen(item->member.run.strText))
{
item = ME_FindItemFwd(item, diRun);
para = ME_GetParagraph(item);
nStart = 0;
}
}
}
else /* Backward search */
{
nEnd = nMax;
item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd);
if (!item)
return -1;
para = ME_GetParagraph(item);
while (item
&& para->member.para.nCharOfs + item->member.run.nCharOfs + nEnd - nLen >= nMin)
{
ME_DisplayItem *pCurItem = item;
int nCurEnd = nEnd;
int nMatched = 0;
while (pCurItem && pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1] == text[nLen - nMatched - 1])
{
nMatched++;
if (nMatched == nLen)
{
nStart = para->member.para.nCharOfs + item->member.run.nCharOfs + nCurEnd - nMatched;
if (chrgText)
{
chrgText->cpMin = nStart;
chrgText->cpMax = nStart + nLen;
}
TRACE("found at %d-%d\n", nStart, nStart + nLen);
return nStart;
}
if (nCurEnd - nMatched == 0)
{
pCurItem = ME_FindItemBack(pCurItem, diRun);
para = ME_GetParagraph(pCurItem);
nCurEnd = ME_StrLen(pCurItem->member.run.strText) + nMatched;
}
}
nEnd--;
if (nEnd < 0)
{
item = ME_FindItemBack(item, diRun);
para = ME_GetParagraph(item);
nEnd = ME_StrLen(item->member.run.strText);
}
}
}
TRACE("not found\n");
return -1;
}
ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
HDC hDC;
int i;
ed->hWnd = hWnd;
ed->bEmulateVersion10 = FALSE;
ed->pBuffer = ME_MakeText();
hDC = GetDC(hWnd);
ME_MakeFirstParagraph(hDC, ed->pBuffer);
ReleaseDC(hWnd, hDC);
ed->bCaretShown = FALSE;
ed->nCursors = 3;
ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors);
ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
ed->pCursors[0].nOffset = 0;
ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
ed->pCursors[1].nOffset = 0;
ed->nLastTotalLength = ed->nTotalLength = 0;
ed->nUDArrowX = -1;
ed->nSequence = 0;
ed->rgbBackColor = -1;
ed->hbrBackground = GetSysColorBrush(COLOR_WINDOW);
ed->bCaretAtEnd = FALSE;
ed->nEventMask = 0;
ed->nModifyStep = 0;
ed->pUndoStack = ed->pRedoStack = NULL;
ed->nUndoMode = umAddToUndo;
ed->nParagraphs = 1;
ed->nLastSelStart = ed->nLastSelEnd = 0;
ed->nScrollPosY = 0;
ed->nZoomNumerator = ed->nZoomDenominator = 0;
ed->bRedraw = TRUE;
GetClientRect(hWnd, &ed->rcFormat);
for (i=0; i<HFONT_CACHE_SIZE; i++)
{
ed->pFontCache[i].nRefs = 0;
ed->pFontCache[i].nAge = 0;
ed->pFontCache[i].hFont = NULL;
}
ME_CheckCharOffsets(ed);
return ed;
}
typedef struct tagME_GlobalDestStruct
{
HGLOBAL hData;
int nLength;
} ME_GlobalDestStruct;
static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int nMaxSize;
BYTE *pDest;
nMaxSize = GlobalSize(pData->hData);
if (pData->nLength+cb+1 >= cb)
{
/* round up to 2^17 */
int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000;
pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0);
}
pDest = (BYTE *)GlobalLock(pData->hData);
memcpy(pDest + pData->nLength, lpBuff, cb);
pData->nLength += cb;
pDest[pData->nLength] = '\0';
GlobalUnlock(pData->hData);
*pcb = cb;
return 0;
}
static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int i;
WORD *pSrc, *pDest;
cb = cb >> 1;
pDest = (WORD *)lpBuff;
pSrc = (WORD *)GlobalLock(pData->hData);
for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
pDest[i] = pSrc[pData->nLength+i];
}
pData->nLength += i;
*pcb = 2*i;
GlobalUnlock(pData->hData);
return 0;
}
static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -