📄 editor.c
字号:
{
ME_DisplayItem *para;
RTFFlushOutputBuffer(info);
para = ME_GetParagraph(info->editor->pCursors[0].pRun);
assert(para->member.para.pCells);
para->member.para.bTable = TRUE;
return;
}
case rtfFirstIndent:
ME_GetSelectionParaFormat(info->editor, &fmt);
fmt.dwMask = PFM_STARTINDENT | PFM_OFFSET;
fmt.dxStartIndent += info->rtfParam + fmt.dxOffset;
fmt.dxOffset = -info->rtfParam;
break;
case rtfLeftIndent:
ME_GetSelectionParaFormat(info->editor, &fmt);
fmt.dwMask = PFM_STARTINDENT;
fmt.dxStartIndent = -fmt.dxOffset + info->rtfParam;
break;
case rtfRightIndent:
fmt.dwMask = PFM_RIGHTINDENT;
fmt.dxRightIndent = info->rtfParam;
break;
case rtfQuadLeft:
case rtfQuadJust:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_LEFT;
break;
case rtfQuadRight:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_RIGHT;
break;
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_RTFTblAttrHook(RTF_Info *info)
{
ME_DisplayItem *para;
switch (info->rtfMinor)
{
case rtfRowDef:
RTFFlushOutputBuffer(info);
para = ME_GetParagraph(info->editor->pCursors[0].pRun);
/* Release possibly inherited cell definitions */
ME_DestroyTableCellList(para);
para->member.para.pCells = ALLOC_OBJ(ME_TableCell);
para->member.para.pCells->nRightBoundary = 0;
para->member.para.pCells->next = NULL;
para->member.para.pLastCell = para->member.para.pCells;
break;
case rtfCellPos:
RTFFlushOutputBuffer(info);
para = ME_GetParagraph(info->editor->pCursors[0].pRun);
if (para->member.para.pLastCell->nRightBoundary)
{
ME_TableCell *pCell = ALLOC_OBJ(ME_TableCell);
pCell->next = NULL;
para->member.para.pLastCell->next = pCell;
para->member.para.pLastCell = pCell;
}
para->member.para.pLastCell->nRightBoundary = info->rtfParam;
break;
}
}
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;
case rtfTblAttr:
ME_RTFTblAttrHook(info);
break;
case rtfSpecialChar:
if (info->rtfMinor == rtfCell)
{
RTFFlushOutputBuffer(info);
ME_InsertTableCellFromCursor(info->editor, 0);
}
}
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;
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) && (editor->mode & TM_RICHTEXT)) {
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 ! */
}
/* Back up undo mode to a local variable */
nUndoMode = editor->nUndoMode;
/* Only create an undo if SFF_SELECTION is set */
if (!(format & SFF_SELECTION))
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, "{\\rtf", 5) && 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);
}
/* Restore saved undo mode */
editor->nUndoMode = nUndoMode;
/* even if we didn't add an undo, we need to commit anything on the stack */
ME_CommitUndo(editor);
/* If SFF_SELECTION isn't set, delete any undos from before we started too */
if (!(format & SFF_SELECTION))
ME_EmptyUndoStack(editor);
ME_ReleaseStyle(style);
editor->nEventMask = nEventMask;
if (editor->bRedraw)
{
ME_UpdateRepaint(editor);
}
if (!(format & SFF_SELECTION)) {
ME_ClearTempStyle(editor);
}
ME_MoveCaret(editor);
ME_SendSelChange(editor);
ME_SendRequestResize(editor, FALSE);
return 0;
}
typedef struct tagME_RTFStringStreamStruct
{
char *string;
int pos;
int length;
} ME_RTFStringStreamStruct;
static DWORD CALLBACK ME_ReadFromRTFString(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_RTFStringStreamStruct *pStruct = (ME_RTFStringStreamStruct *)dwCookie;
int count;
count = min(cb, pStruct->length - pStruct->pos);
memmove(lpBuff, pStruct->string + pStruct->pos, count);
pStruct->pos += count;
*pcb = count;
return 0;
}
static void
ME_StreamInRTFString(ME_TextEditor *editor, BOOL selection, char *string)
{
EDITSTREAM es;
ME_RTFStringStreamStruct data;
data.string = string;
data.length = strlen(string);
data.pos = 0;
es.dwCookie = (DWORD)&data;
es.pfnCallback = ME_ReadFromRTFString;
ME_StreamIn(editor, SF_RTF | (selection ? SFF_SELECTION : 0), &es);
}
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, const WCHAR *text, CHARRANGE *chrgText)
{
const int nLen = lstrlenW(text);
const int nTextLen = ME_GetTextLength(editor);
int nStart, nEnd;
int nMin, nMax;
ME_DisplayItem *item;
ME_DisplayItem *para;
WCHAR wLastChar = ' ';
TRACE("flags==0x%08x, chrg->cpMin==%d, chrg->cpMax==%d text==%s\n",
flags, chrg->cpMin, chrg->cpMax, debugstr_w(text));
if (flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD))
FIXME("Flags 0x%08x not implemented\n",
flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD));
nMin = chrg->cpMin;
if (chrg->cpMax == -1)
nMax = nTextLen;
else
nMax = chrg->cpMax > nTextLen ? nTextLen : chrg->cpMax;
/* when searching up, if cpMin < cpMax, then instead of searching
* on [cpMin,cpMax], we search on [0,cpMin], otherwise, search on
* [cpMax, cpMin]. The exception is when cpMax is -1, in which
* case, it is always bigger than cpMin.
*/
if (!(flags & FR_DOWN))
{
int nSwap = nMax;
nMax = nMin > nTextLen ? nTextLen : nMin;
if (nMin < nSwap || chrg->cpMax == -1)
nMin = 0;
else
nMin = nSwap;
}
if (!nLen || nMin < 0 || nMax < 0 || nMax < nMin)
{
if (chrgText)
chrgText->cpMin = chrgText->cpMax = -1;
return -1;
}
if (flags & FR_DOWN) /* Forward search */
{
/* If possible, find the character before where the search starts */
if ((flags & FR_WHOLEWORD) && nMin)
{
nStart = nMin - 1;
item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
if (!item)
{
if (chrgText)
chrgText->cpMin = chrgText->cpMax = -1;
return -1;
}
wLastChar = item->member.run.strText->szData[nStart];
}
nStart = nMin;
item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
if (!item)
{
if (chrgText)
chrgText->cpMin = chrgText->cpMax = -1;
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 && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE)))
{
if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
break;
nMatched++;
if (nMatched == nLen)
{
ME_DisplayItem *pNextItem = pCurItem;
int nNextStart = nCurStart;
WCHAR wNextChar;
/* Check to see if next character is a whitespace */
if (flags & FR_WHOLEWORD)
{
if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText))
{
pNextItem = ME_FindItemFwd(pCurItem, diRun);
nNextStart = -nMatched;
}
if (pNextItem)
wNextChar = pNextItem->member.run.strText->szData[nNextStart + nMatched];
else
wNextChar = ' ';
if (isalnumW(wNextChar))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -