📄 editor.c
字号:
int count = 0;
int ystart, yend;
while(p) {
p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
if (p->type == diTextEnd)
break;
if (p->type == diParagraph) {
ypara = p->member.para.nYPos;
continue;
}
ystart = ypara + p->member.row.nYPos;
yend = ystart + p->member.row.nHeight;
if (y < yend) {
break;
}
count++;
}
return count;
}
case EM_HIDESELECTION:
{
editor->bHideSelection = (wParam != 0);
ME_InvalidateSelection(editor);
return 0;
}
case EM_LINESCROLL:
{
ME_ScrollDown(editor, lParam * 8); /* FIXME follow the original */
return TRUE; /* Should return false if a single line richedit control */
}
case WM_CLEAR:
{
int from, to;
ME_GetSelection(editor, &from, &to);
ME_InternalDeleteText(editor, from, to-from);
ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
return 0;
}
case EM_REPLACESEL:
{
int from, to;
ME_Style *style;
LPWSTR wszText = ME_ToUnicode(unicode, (void *)lParam);
size_t len = lstrlenW(wszText);
TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText));
ME_GetSelection(editor, &from, &to);
style = ME_GetSelectionInsertStyle(editor);
ME_InternalDeleteText(editor, from, to-from);
ME_InsertTextFromCursor(editor, 0, wszText, len, style);
ME_ReleaseStyle(style);
/* drop temporary style if line end */
/*
* FIXME question: does abc\n mean: put abc,
* clear temp style, put \n? (would require a change)
*/
if (len>0 && wszText[len-1] == '\n')
ME_ClearTempStyle(editor);
ME_EndToUnicode(unicode, wszText);
ME_CommitUndo(editor);
if (!wParam)
ME_EmptyUndoStack(editor);
ME_UpdateRepaint(editor);
return 0;
}
case EM_SCROLLCARET:
{
int top, bottom; /* row's edges relative to document top */
int nPos;
ME_DisplayItem *para, *row;
nPos = ME_GetYScrollPos(editor);
row = ME_RowStart(editor->pCursors[0].pRun);
para = ME_GetParagraph(row);
top = para->member.para.nYPos + row->member.row.nYPos;
bottom = top + row->member.row.nHeight;
if (top < nPos) /* caret above window */
ME_ScrollAbs(editor, top);
else if (nPos + editor->sizeWindow.cy < bottom) /*below*/
ME_ScrollAbs(editor, bottom - editor->sizeWindow.cy);
return 0;
}
case WM_SETFONT:
{
LOGFONTW lf;
CHARFORMAT2W fmt;
HDC hDC;
BOOL bRepaint = LOWORD(lParam);
if (!wParam)
wParam = (WPARAM)GetStockObject(SYSTEM_FONT);
GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf);
hDC = GetDC(hWnd);
ME_CharFormatFromLogFont(hDC, &lf, &fmt);
ReleaseDC(hWnd, hDC);
ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), &fmt);
ME_SetDefaultCharFormat(editor, &fmt);
ME_CommitUndo(editor);
if (bRepaint)
ME_RewrapRepaint(editor);
return 0;
}
case WM_SETTEXT:
{
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
if (lParam)
{
TRACE("WM_SETTEXT lParam==%lx\n",lParam);
if (!unicode && !strncmp((char *)lParam, "{\\rtf", 5))
{
/* Undocumented: WM_SETTEXT supports RTF text */
ME_StreamInRTFString(editor, 0, (char *)lParam);
}
else
{
LPWSTR wszText = ME_ToUnicode(unicode, (void *)lParam);
TRACE("WM_SETTEXT - %s\n", debugstr_w(wszText)); /* debugstr_w() */
if (lstrlenW(wszText) > 0)
{
/* uses default style! */
ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
}
ME_EndToUnicode(unicode, wszText);
}
}
else
TRACE("WM_SETTEXT - NULL\n");
ME_CommitUndo(editor);
ME_EmptyUndoStack(editor);
ME_SetSelection(editor, 0, 0);
ME_UpdateRepaint(editor);
return 1;
}
case EM_CANPASTE:
{
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
if (IsClipboardFormatAvailable(nRTFFormat))
return TRUE;
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
return TRUE;
return FALSE;
}
case WM_PASTE:
{
DWORD dwFormat = 0;
EDITSTREAM es;
ME_GlobalDestStruct gds;
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
UINT cf = 0;
if (IsClipboardFormatAvailable(nRTFFormat))
cf = nRTFFormat, dwFormat = SF_RTF;
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE;
else
return 0;
if (!OpenClipboard(hWnd))
return 0;
gds.hData = GetClipboardData(cf);
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
ME_StreamIn(editor, dwFormat|SFF_SELECTION, &es);
CloseClipboard();
return 0;
}
case WM_CUT:
case WM_COPY:
{
LPDATAOBJECT dataObj = NULL;
CHARRANGE range;
HRESULT hr = S_OK;
if (editor->cPasswordMask)
return 0; /* Copying or Cutting masked text isn't allowed */
ME_GetSelection(editor, (int*)&range.cpMin, (int*)&range.cpMax);
if(editor->lpOleCallback)
hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, &range, RECO_COPY, &dataObj);
if(FAILED(hr) || !dataObj)
hr = ME_GetDataObject(editor, &range, &dataObj);
if(SUCCEEDED(hr)) {
hr = OleSetClipboard(dataObj);
IDataObject_Release(dataObj);
}
if (SUCCEEDED(hr) && msg == WM_CUT)
{
ME_InternalDeleteText(editor, range.cpMin, range.cpMax-range.cpMin);
ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
}
return 0;
}
case WM_GETTEXTLENGTH:
return ME_GetTextLength(editor);
case EM_GETTEXTLENGTHEX:
return ME_GetTextLengthEx(editor, (GETTEXTLENGTHEX *)wParam);
case WM_GETTEXT:
{
TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
tr.chrg.cpMin = 0;
tr.chrg.cpMax = wParam ? (wParam - 1) : 0;
tr.lpstrText = (WCHAR *)lParam;
return RichEditWndProc_common(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr, unicode);
}
case EM_GETTEXTEX:
{
GETTEXTEX *ex = (GETTEXTEX*)wParam;
int nStart, nCount;
if (ex->flags & ~(GT_SELECTION | GT_USECRLF))
FIXME("GETTEXTEX flags 0x%08x not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF));
if (ex->flags & GT_SELECTION)
{
ME_GetSelection(editor, &nStart, &nCount);
nCount -= nStart;
nCount = min(nCount, ex->cb - 1);
}
else
{
nStart = 0;
nCount = ex->cb - 1;
}
if (ex->codepage == 1200)
{
nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1);
return ME_GetTextW(editor, (LPWSTR)lParam, nStart, nCount, ex->flags & GT_USECRLF);
}
else
{
/* potentially each char may be a CR, why calculate the exact value with O(N) when
we can just take a bigger buffer? :) */
int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1;
LPWSTR buffer = richedit_alloc((crlfmul*nCount + 1) * sizeof(WCHAR));
DWORD buflen = ex->cb;
LRESULT rc;
DWORD flags = 0;
buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF);
rc = WideCharToMultiByte(ex->codepage, flags, buffer, -1, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar);
if (rc) rc--; /* do not count 0 terminator */
richedit_free(buffer);
return rc;
}
}
case EM_GETSELTEXT:
{
int from, to;
TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
ME_GetSelection(editor, &from, &to);
tr.chrg.cpMin = from;
tr.chrg.cpMax = to;
tr.lpstrText = (WCHAR *)lParam;
return RichEditWndProc_common(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr, unicode);
}
case EM_GETSCROLLPOS:
{
POINT *point = (POINT *)lParam;
point->x = 0; /* FIXME side scrolling not implemented */
point->y = ME_GetYScrollPos(editor);
return 1;
}
case EM_GETTEXTRANGE:
{
TEXTRANGEW *rng = (TEXTRANGEW *)lParam;
TRACE("EM_GETTEXTRANGE min=%d max=%d unicode=%d emul1.0=%d length=%d\n",
rng->chrg.cpMin, rng->chrg.cpMax, unicode,
editor->bEmulateVersion10, ME_GetTextLength(editor));
if (unicode)
return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10);
else
{
int nLen = rng->chrg.cpMax-rng->chrg.cpMin;
WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, editor->bEmulateVersion10);
/* FIXME this is a potential security hole (buffer overrun)
if you know more about wchar->mbyte conversion please explain
*/
WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)rng->lpstrText, nLen+1, NULL, NULL);
FREE_OBJ(p);
return nChars;
}
}
case EM_GETLINE:
{
ME_DisplayItem *run;
const unsigned int nMaxChars = *(WORD *) lParam;
unsigned int nEndChars, nCharsLeft = nMaxChars;
char *dest = (char *) lParam;
/* rich text editor 1.0 uses \r\n for line end, 2.0 uses just \r;
we need to know how if we have the extra \n or not */
int nLF = editor->bEmulateVersion10;
TRACE("EM_GETLINE: row=%d, nMaxChars=%d (%s)\n", (int) wParam, nMaxChars,
unicode ? "Unicode" : "Ansi");
run = ME_FindRowWithNumber(editor, wParam);
if (run == NULL)
return 0;
while (nCharsLeft && (run = ME_FindItemFwd(run, diRunOrStartRow))
&& !(run->member.run.nFlags & MERF_ENDPARA))
{
unsigned int nCopy;
ME_String *strText;
if (run->type != diRun)
break;
strText = run->member.run.strText;
nCopy = min(nCharsLeft, strText->nLen);
if (unicode)
lstrcpynW((LPWSTR) dest, strText->szData, nCopy);
else
nCopy = WideCharToMultiByte(CP_ACP, 0, strText->szData, nCopy, dest,
nCharsLeft, NULL, NULL);
dest += nCopy * (unicode ? sizeof(WCHAR) : 1);
nCharsLeft -= nCopy;
}
/* append \r\0 (or \r\n\0 in 1.0), space allowing */
nEndChars = min(nCharsLeft, 2 + nLF);
nCharsLeft -= nEndChars;
if (unicode)
{
const WCHAR src[] = {'\r', '\0'};
const WCHAR src10[] = {'\r', '\n', '\0'};
lstrcpynW((LPWSTR) dest, nLF ? src10 : src, nEndChars);
}
else
lstrcpynA(dest, nLF ? "\r\n" : "\r", nEndChars);
TRACE("EM_GETLINE: got %u bytes\n", nMaxChars - nCharsLeft);
if (nEndChars == 2 + nLF)
return nMaxChars - nCharsLeft - 1; /* don't count \0 */
else
return nMaxChars - nCharsLeft;
}
case EM_GETLINECOUNT:
{
ME_DisplayItem *item = editor->pBuffer->pFirst->next;
int nRows = 0;
while (item != editor->pBuffer->pLast)
{
assert(item->type == diParagraph);
nRows += item->member.para.nRows;
item = item->member.para.next_para;
}
TRACE("EM_GETLINECOUNT: nRows==%d\n", nRows);
return max(1, nRows);
}
case EM_LINEFROMCHAR:
{
if (wParam == -1)
return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor, 1));
else
return ME_RowNumberFromCharOfs(editor, wParam);
}
case EM_EXLINEFROMCHAR:
{
if (lParam == -1)
return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor,1));
else
return ME_RowNumberFromCharOfs(editor, lParam);
}
case EM_LINEINDEX:
{
ME_DisplayItem *item, *para;
int nCharOfs;
if (wParam == -1)
item = ME_FindItemBack(editor->pCursors[0].pRun, diStartRow);
else
item = ME_FindRowWithNumber(editor, wParam);
if (!item)
return -1;
para = ME_GetParagraph(item);
item = ME_FindItemFwd(item, diRun);
nCharOfs = para->member.para.nCharOfs + item->member.run.nCharOfs;
TRACE("EM_LINEINDEX: nCharOfs==%d\n", nCharOfs);
return nCharOfs;
}
case EM_LINELENGTH:
{
ME_DisplayItem *item, *item_end;
int nChars = 0, nThisLineOfs = 0, nNextLineOfs = 0;
if (wParam > ME_GetTextLength(editor))
return 0;
if (wParam == -1)
{
FIXME("EM_LINELENGTH: returning number of unselected characters on lines with selection unsupported.\n");
return 0;
}
item = ME_FindItemAtOffset(editor, diRun, wParam, NULL);
item = ME_RowStart(item);
nThisLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item, diRun), 0);
item_end = ME_FindItemFwd(item, diStartRowOrParagraphOrEnd);
if (item_end->type == diStartRow)
nNextLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item_end, diRun), 0);
else
nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs
- (editor->bEmulateVersion10?2:1);
nChars = nNextLineOfs - nThisLineOfs;
TRACE("EM_LINELENGTH(%ld)==%d\n",wParam, nChars);
return nChars;
}
case EM_EXLIMITTEXT:
{
if ((int)lParam < 0)
return 0;
if (lParam == 0)
editor->nTextLimit = 65536;
else
editor->nTextLimit = (int) lParam;
return 0;
}
case EM_LIMITTEXT:
{
if (wParam == 0)
editor->nTextLimit = 65536;
else
editor->nTextLimit = (int) wParam;
return 0;
}
case EM_GETLIMITTEXT:
{
return editor->nTextLimit;
}
case EM_FINDTEXT:
{
FINDTEXTA *ft = (FINDTEXTA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0);
WCHAR *tmp;
LRESULT r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -