riched20: Reduced screen flicker by using proper update region invalidation.
This commit is contained in:
parent
1406010d3c
commit
6818762a6e
|
@ -23,6 +23,11 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
|
||||
|
||||
|
||||
void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
|
||||
{
|
||||
*from = ME_GetCursorOfs(editor, 0);
|
||||
|
@ -102,24 +107,29 @@ void ME_SetSelection(ME_TextEditor *editor, int from, int to)
|
|||
ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
|
||||
}
|
||||
|
||||
void ME_MoveCaret(ME_TextEditor *editor)
|
||||
{
|
||||
HDC hDC = GetDC(editor->hWnd);
|
||||
ME_Context c;
|
||||
|
||||
ME_Cursor *pCursor = &editor->pCursors[0];
|
||||
void
|
||||
ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
|
||||
int *x, int *y, int *height)
|
||||
{
|
||||
ME_DisplayItem *pCursorRun = pCursor->pRun;
|
||||
ME_DisplayItem *pSizeRun = pCursor->pRun;
|
||||
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
|
||||
assert(!pCursor->nOffset || !editor->bCaretAtEnd);
|
||||
assert(height && x && y);
|
||||
|
||||
if (pCursorRun->type == diRun) {
|
||||
ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
|
||||
|
||||
if (row) {
|
||||
HDC hDC = GetDC(editor->hWnd);
|
||||
ME_Context c;
|
||||
ME_DisplayItem *run = pCursorRun;
|
||||
ME_DisplayItem *para;
|
||||
SIZE sz = {0, 0};
|
||||
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
|
||||
if (!pCursor->nOffset && !editor->bCaretAtEnd)
|
||||
{
|
||||
ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
|
||||
|
@ -142,24 +152,33 @@ void ME_MoveCaret(ME_TextEditor *editor)
|
|||
if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) {
|
||||
sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, pCursor->nOffset);
|
||||
}
|
||||
CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
|
||||
SetCaretPos(run->member.run.pt.x+sz.cx,
|
||||
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-ME_GetYScrollPos(editor));
|
||||
} else {
|
||||
assert(0 == "Wrapped paragraph run without a row?");
|
||||
CreateCaret(editor->hWnd, NULL, 0, 10);
|
||||
SetCaretPos(0,0);
|
||||
|
||||
*height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
|
||||
*x = run->member.run.pt.x + sz.cx;
|
||||
*y = para->member.para.nYPos + row->member.row.nBaseline + pSizeRun->member.run.pt.y - pSizeRun->member.run.nAscent - ME_GetYScrollPos(editor);
|
||||
|
||||
ME_DestroyContext(&c);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0 == "Cursor not on a run");
|
||||
CreateCaret(editor->hWnd, NULL, 0, 10); /* FIXME use global font */
|
||||
SetCaretPos(0,0);
|
||||
}
|
||||
ME_DestroyContext(&c);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
*height = 10; /* FIXME use global font */
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ME_MoveCaret(ME_TextEditor *editor)
|
||||
{
|
||||
int x, y, height;
|
||||
|
||||
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
|
||||
CreateCaret(editor->hWnd, NULL, 0, height);
|
||||
SetCaretPos(x, y);
|
||||
}
|
||||
|
||||
|
||||
void ME_ShowCaret(ME_TextEditor *ed)
|
||||
{
|
||||
ME_MoveCaret(ed);
|
||||
|
@ -410,68 +429,69 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
|||
}
|
||||
}
|
||||
|
||||
static BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
|
||||
|
||||
static BOOL
|
||||
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
{
|
||||
if (p->nOffset) {
|
||||
p->nOffset = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, -1);
|
||||
ME_DisplayItem *pRun;
|
||||
|
||||
if (nRelOfs == -1)
|
||||
{
|
||||
if (!pCursor->nOffset)
|
||||
{
|
||||
pRun = ME_FindItemBack(pCursor->pRun, diRunOrParagraph);
|
||||
assert(pRun);
|
||||
switch (pRun->type)
|
||||
{
|
||||
case diRun:
|
||||
pCursor->pRun = pRun;
|
||||
pCursor->nOffset = pRun->member.run.strText->nLen;
|
||||
break;
|
||||
case diParagraph:
|
||||
if (pRun->member.para.prev_para->type == diTextStart)
|
||||
return FALSE;
|
||||
pRun = ME_FindItemBack(pRun, diRunOrParagraph);
|
||||
/* every paragraph ought to have at least one run */
|
||||
assert(pRun && pRun->type == diRun);
|
||||
assert(pRun->member.run.nFlags & MERF_ENDPARA);
|
||||
pCursor->pRun = pRun;
|
||||
pCursor->nOffset = 0;
|
||||
break;
|
||||
default:
|
||||
assert(pRun->type != diRun && pRun->type != diParagraph);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pCursor->nOffset)
|
||||
pCursor->nOffset = ME_StrRelPos2(pCursor->pRun->member.run.strText, pCursor->nOffset, nRelOfs);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ME_DisplayItem *pRun = ME_FindItemBack(p->pRun, diRunOrParagraph);
|
||||
assert(pRun);
|
||||
if (pRun->type == diRun) {
|
||||
p->pRun = pRun;
|
||||
assert(p->pRun->type == diRun);
|
||||
assert(pRun->member.run.strText->nLen);
|
||||
p->nOffset = pRun->member.run.strText->nLen;
|
||||
if (p->nOffset) {
|
||||
p->nOffset = ME_StrRelPos2(pRun->member.run.strText, p->nOffset, -1);
|
||||
if (!(pCursor->pRun->member.run.nFlags & MERF_ENDPARA))
|
||||
{
|
||||
int new_ofs = ME_StrRelPos2(pCursor->pRun->member.run.strText, pCursor->nOffset, nRelOfs);
|
||||
|
||||
if (new_ofs < pCursor->pRun->member.run.strText->nLen)
|
||||
{
|
||||
pCursor->nOffset = new_ofs;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
if (pRun->type == diParagraph)
|
||||
pRun = ME_FindItemFwd(pCursor->pRun, diRun);
|
||||
if (pRun)
|
||||
{
|
||||
if (pRun->member.para.prev_para->type == diTextStart)
|
||||
return FALSE;
|
||||
assert(pRun->member.para.prev_para->type == diParagraph);
|
||||
pRun = ME_FindItemBack(pRun, diRunOrParagraph);
|
||||
/* every paragraph ought to have at least one run */
|
||||
assert(pRun && pRun->type == diRun);
|
||||
assert(pRun->member.run.nFlags & MERF_ENDPARA);
|
||||
p->pRun = pRun;
|
||||
p->nOffset = 0;
|
||||
pCursor->pRun = pRun;
|
||||
pCursor->nOffset = 0;
|
||||
return TRUE;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
|
||||
{
|
||||
ME_DisplayItem *pRun;
|
||||
|
||||
if (!(p->pRun->member.run.nFlags & MERF_ENDPARA))
|
||||
{
|
||||
int new_ofs = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, 1);
|
||||
|
||||
if (new_ofs<p->pRun->member.run.strText->nLen)
|
||||
{
|
||||
p->nOffset = new_ofs;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
pRun = ME_FindItemFwd(p->pRun, diRun);
|
||||
if (pRun) {
|
||||
p->pRun = pRun;
|
||||
assert(p->pRun->type == diRun);
|
||||
p->nOffset = 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
|
||||
{
|
||||
|
@ -716,50 +736,36 @@ static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
|
|||
return x;
|
||||
}
|
||||
|
||||
static void ME_ArrowUp(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pItem, *pItem2;
|
||||
int x = ME_GetXForArrow(editor, pCursor);
|
||||
|
||||
if (editor->bCaretAtEnd && !pCursor->nOffset)
|
||||
{
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
if (!pRun)
|
||||
return;
|
||||
}
|
||||
|
||||
/* start of this row */
|
||||
pItem = ME_FindItemBack(pRun, diStartRow);
|
||||
assert(pItem);
|
||||
/* start of the previous row */
|
||||
pItem2 = ME_FindItemBack(pItem, diStartRow);
|
||||
/* no previous row = the first line of the first paragraph */
|
||||
if (!pItem2) /* can't go up - don't go BOL (as in MS richedit) */
|
||||
return;
|
||||
/* FIXME
|
||||
ME_WrapTextParagraph(editor, ME_FindItemBack(pItem2, diParagraph));
|
||||
*/
|
||||
pCursor->pRun = ME_FindRunInRow(editor, pItem2, x, &pCursor->nOffset, &editor->bCaretAtEnd);
|
||||
}
|
||||
|
||||
static void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
static void
|
||||
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pItem;
|
||||
int x = ME_GetXForArrow(editor, pCursor);
|
||||
if (!pCursor->nOffset && editor->bCaretAtEnd)
|
||||
{
|
||||
|
||||
if (editor->bCaretAtEnd && !pCursor->nOffset)
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
/* x = pRun->member.run.pt.x + pRun->member.run.nWidth; */
|
||||
if (!pRun)
|
||||
return;
|
||||
if (nRelOfs == -1)
|
||||
{
|
||||
/* start of this row */
|
||||
pItem = ME_FindItemBack(pRun, diStartRow);
|
||||
assert(pItem);
|
||||
/* start of the previous row */
|
||||
pItem = ME_FindItemBack(pItem, diStartRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start of the next row */
|
||||
pItem = ME_FindItemFwd(pRun, diStartRow);
|
||||
/* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
|
||||
*/
|
||||
}
|
||||
/* start of the next row */
|
||||
pItem = ME_FindItemFwd(pRun, diStartRow);
|
||||
/* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
|
||||
*/
|
||||
if (!pItem)
|
||||
{
|
||||
/* next row not found - ignore */
|
||||
/* row not found - ignore */
|
||||
return;
|
||||
}
|
||||
pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
|
||||
|
@ -767,6 +773,7 @@ static void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
|||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
|
||||
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
|
@ -952,25 +959,6 @@ static int ME_GetSelCursor(ME_TextEditor *editor, int dir)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static BOOL ME_CancelSelection(ME_TextEditor *editor, int dir)
|
||||
{
|
||||
int cdir;
|
||||
|
||||
if (GetKeyState(VK_SHIFT)<0)
|
||||
return FALSE;
|
||||
if (!memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor)))
|
||||
return FALSE;
|
||||
|
||||
cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1);
|
||||
|
||||
if (cdir*dir>0)
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
else
|
||||
editor->pCursors[0] = editor->pCursors[1];
|
||||
ME_Repaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
ME_Cursor old_anchor = editor->pCursors[1];
|
||||
|
@ -997,14 +985,6 @@ BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
if (ME_UpdateSelection(editor, pTempCursor)) {
|
||||
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void ME_DeleteSelection(ME_TextEditor *editor)
|
||||
{
|
||||
int from, to;
|
||||
|
@ -1032,8 +1012,12 @@ ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor)
|
|||
void ME_SendSelChange(ME_TextEditor *editor)
|
||||
{
|
||||
SELCHANGE sc;
|
||||
|
||||
ME_ClearTempStyle(editor);
|
||||
|
||||
if (!(editor->nEventMask & ENM_SELCHANGE))
|
||||
return;
|
||||
|
||||
sc.nmhdr.hwndFrom = editor->hWnd;
|
||||
sc.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID);
|
||||
sc.nmhdr.code = EN_SELCHANGE;
|
||||
|
@ -1046,116 +1030,64 @@ void ME_SendSelChange(ME_TextEditor *editor)
|
|||
SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
|
||||
}
|
||||
|
||||
BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
||||
|
||||
BOOL
|
||||
ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend)
|
||||
{
|
||||
int nCursor = 0;
|
||||
ME_Cursor *p = &editor->pCursors[nCursor];
|
||||
ME_Cursor tmp_curs = *p;
|
||||
|
||||
switch(nVKey) {
|
||||
case VK_UP:
|
||||
ME_ArrowUp(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_DOWN:
|
||||
ME_ArrowDown(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_PRIOR:
|
||||
ME_ArrowPageUp(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_NEXT:
|
||||
ME_ArrowPageDown(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
}
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (ME_IsSelection(editor) && !extend)
|
||||
ME_InvalidateSelection(editor);
|
||||
|
||||
editor->nUDArrowX = -1;
|
||||
switch(nVKey) {
|
||||
case VK_BACK: { /* FIXME backspace and delete aren't the same, they act different wrt paragraph style of the merged paragraph */
|
||||
if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY)
|
||||
return FALSE;
|
||||
if (ME_IsSelection(editor))
|
||||
{
|
||||
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
|
||||
ME_DeleteSelection(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_SendRequestResize(editor, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
if (ME_ArrowLeft(editor, p)) {
|
||||
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_MoveCaret(editor);
|
||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_SendRequestResize(editor, FALSE);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
case VK_DELETE: {
|
||||
if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY)
|
||||
return FALSE;
|
||||
/* editor->bCaretAtEnd = 0; FIXME or maybe not */
|
||||
if (ME_IsSelection(editor))
|
||||
{
|
||||
ME_DeleteSelection(editor);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_SendRequestResize(editor, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_SendRequestResize(editor, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
case VK_LEFT:
|
||||
editor->bCaretAtEnd = 0;
|
||||
success = ME_MoveCursorChars(editor, &tmp_curs, -1);
|
||||
break;
|
||||
case VK_RIGHT:
|
||||
editor->bCaretAtEnd = 0;
|
||||
success = ME_MoveCursorChars(editor, &tmp_curs, +1);
|
||||
break;
|
||||
case VK_UP:
|
||||
ME_MoveCursorLines(editor, &tmp_curs, -1);
|
||||
break;
|
||||
case VK_DOWN:
|
||||
ME_MoveCursorLines(editor, &tmp_curs, +1);
|
||||
break;
|
||||
case VK_PRIOR:
|
||||
ME_ArrowPageUp(editor, &tmp_curs);
|
||||
break;
|
||||
case VK_NEXT:
|
||||
ME_ArrowPageDown(editor, &tmp_curs);
|
||||
break;
|
||||
case VK_HOME: {
|
||||
if (GetKeyState(VK_CONTROL)<0)
|
||||
ME_ArrowCtrlHome(editor, p);
|
||||
ME_ArrowCtrlHome(editor, &tmp_curs);
|
||||
else
|
||||
ME_ArrowHome(editor, p);
|
||||
ME_ArrowHome(editor, &tmp_curs);
|
||||
editor->bCaretAtEnd = 0;
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case VK_END:
|
||||
if (GetKeyState(VK_CONTROL)<0)
|
||||
ME_ArrowCtrlEnd(editor, p);
|
||||
ME_ArrowCtrlEnd(editor, &tmp_curs);
|
||||
else
|
||||
ME_ArrowEnd(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_LEFT:
|
||||
editor->bCaretAtEnd = 0;
|
||||
if (ME_CancelSelection(editor, -1))
|
||||
return TRUE;
|
||||
ME_ArrowLeft(editor, p);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_RIGHT:
|
||||
editor->bCaretAtEnd = 0;
|
||||
if (ME_CancelSelection(editor, +1))
|
||||
return TRUE;
|
||||
ME_ArrowRight(editor, p);
|
||||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
ME_ArrowEnd(editor, &tmp_curs);
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
if (!extend)
|
||||
editor->pCursors[1] = tmp_curs;
|
||||
*p = tmp_curs;
|
||||
|
||||
ME_InvalidateSelection(editor);
|
||||
HideCaret(editor->hWnd);
|
||||
ME_EnsureVisible(editor, tmp_curs.pRun);
|
||||
ME_ShowCaret(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -625,7 +625,6 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
|||
editor->nEventMask = nEventMask;
|
||||
if (editor->bRedraw)
|
||||
{
|
||||
InvalidateRect(editor->hWnd, NULL, TRUE);
|
||||
ME_UpdateRepaint(editor);
|
||||
}
|
||||
if (!(format & SFF_SELECTION)) {
|
||||
|
@ -800,6 +799,62 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, WCHAR *text, CH
|
|||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_KeyDown(ME_TextEditor *editor, WORD nKey)
|
||||
{
|
||||
BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000;
|
||||
BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000;
|
||||
|
||||
switch (nKey)
|
||||
{
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
case VK_UP:
|
||||
case VK_DOWN:
|
||||
case VK_HOME:
|
||||
case VK_END:
|
||||
case VK_PRIOR:
|
||||
case VK_NEXT:
|
||||
ME_ArrowKey(editor, nKey, shift_is_down);
|
||||
return TRUE;
|
||||
case VK_BACK:
|
||||
case VK_DELETE:
|
||||
/* FIXME backspace and delete aren't the same, they act different wrt paragraph style of the merged paragraph */
|
||||
if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY)
|
||||
return FALSE;
|
||||
if (ME_IsSelection(editor))
|
||||
ME_DeleteSelection(editor);
|
||||
else if (nKey == VK_DELETE || ME_ArrowKey(editor, VK_LEFT, FALSE))
|
||||
ME_DeleteTextAtCursor(editor, 1, 1);
|
||||
else
|
||||
return TRUE;
|
||||
ME_QueueInvalidateFromCursor(editor, 1);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_SendRequestResize(editor, FALSE);
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
if (ctrl_is_down)
|
||||
{
|
||||
if (nKey == 'W')
|
||||
{
|
||||
CHARFORMAT2W chf;
|
||||
char buf[2048];
|
||||
|
||||
ME_GetSelectionCharFormat(editor, &chf);
|
||||
ME_DumpStyleToBuf(&chf, buf);
|
||||
MessageBoxA(NULL, buf, "Style dump", MB_OK);
|
||||
}
|
||||
if (nKey == 'Q')
|
||||
{
|
||||
ME_CheckCharOffsets(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
||||
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
|
||||
HDC hDC;
|
||||
|
@ -832,6 +887,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
|||
ed->nScrollPosY = 0;
|
||||
ed->nZoomNumerator = ed->nZoomDenominator = 0;
|
||||
ed->bRedraw = TRUE;
|
||||
ed->nInvalidOfs = -1;
|
||||
GetClientRect(hWnd, &ed->rcFormat);
|
||||
for (i=0; i<HFONT_CACHE_SIZE; i++)
|
||||
{
|
||||
|
@ -1820,29 +1876,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
TRACE("editor wnd command = %d\n", LOWORD(wParam));
|
||||
return 0;
|
||||
case WM_KEYDOWN:
|
||||
if (ME_ArrowKey(editor, LOWORD(wParam), GetKeyState(VK_CONTROL)<0)) {
|
||||
ME_CommitUndo(editor);
|
||||
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
|
||||
HideCaret(hWnd);
|
||||
ME_MoveCaret(editor);
|
||||
ShowCaret(hWnd);
|
||||
if (ME_KeyDown(editor, LOWORD(wParam)))
|
||||
return 0;
|
||||
}
|
||||
if (GetKeyState(VK_CONTROL)<0)
|
||||
{
|
||||
if (LOWORD(wParam)=='W')
|
||||
{
|
||||
CHARFORMAT2W chf;
|
||||
char buf[2048];
|
||||
ME_GetSelectionCharFormat(editor, &chf);
|
||||
ME_DumpStyleToBuf(&chf, buf);
|
||||
MessageBoxA(NULL, buf, "Style dump", MB_OK);
|
||||
}
|
||||
if (LOWORD(wParam)=='Q')
|
||||
{
|
||||
ME_CheckCharOffsets(editor);
|
||||
}
|
||||
}
|
||||
goto do_default;
|
||||
case WM_CHAR:
|
||||
{
|
||||
|
|
|
@ -150,12 +150,14 @@ void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars);
|
|||
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
||||
const WCHAR *str, int len, ME_Style *style);
|
||||
void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt);
|
||||
BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, int nCtrl);
|
||||
BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend);
|
||||
|
||||
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
|
||||
void ME_DestroyContext(ME_Context *c);
|
||||
ME_Style *GetInsertStyle(ME_TextEditor *editor, int nCursor);
|
||||
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para);
|
||||
void ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
|
||||
int *x, int *y, int *height);
|
||||
int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor);
|
||||
void ME_GetSelection(ME_TextEditor *editor, int *from, int *to);
|
||||
int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to);
|
||||
|
@ -203,6 +205,9 @@ int ME_GetYScrollPos(ME_TextEditor *editor);
|
|||
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
|
||||
COLORREF ME_GetBackColor(ME_TextEditor *editor);
|
||||
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
|
||||
void ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs);
|
||||
void ME_InvalidateSelection(ME_TextEditor *editor);
|
||||
void ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor);
|
||||
BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator);
|
||||
|
||||
/* richole.c */
|
||||
|
|
|
@ -285,6 +285,7 @@ typedef struct tagME_TextEditor
|
|||
int nZoomNumerator, nZoomDenominator;
|
||||
RECT rcFormat;
|
||||
BOOL bRedraw;
|
||||
int nInvalidOfs;
|
||||
} ME_TextEditor;
|
||||
|
||||
typedef struct tagME_Context
|
||||
|
|
|
@ -143,7 +143,6 @@ void ME_Repaint(ME_TextEditor *editor)
|
|||
ME_Cursor *pCursor = &editor->pCursors[0];
|
||||
ME_DisplayItem *pRun = NULL;
|
||||
int nOffset = -1;
|
||||
HDC hDC;
|
||||
int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
|
||||
|
||||
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
|
||||
|
@ -155,11 +154,6 @@ void ME_Repaint(ME_TextEditor *editor)
|
|||
}
|
||||
if (editor->bRedraw)
|
||||
{
|
||||
hDC = GetDC(editor->hWnd);
|
||||
ME_HideCaret(editor);
|
||||
ME_PaintContent(editor, hDC, TRUE, NULL);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
ME_ShowCaret(editor);
|
||||
ME_EnsureVisible(editor, pCursor->pRun);
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +510,64 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs)
|
||||
{
|
||||
RECT rc;
|
||||
int x, y, height;
|
||||
ME_Cursor tmp;
|
||||
|
||||
ME_RunOfsFromCharOfs(editor, nCharOfs, &tmp.pRun, &tmp.nOffset);
|
||||
ME_GetCursorCoordinates(editor, &tmp, &x, &y, &height);
|
||||
|
||||
rc.left = 0;
|
||||
rc.top = y;
|
||||
rc.bottom = y + height;
|
||||
rc.right = editor->rcFormat.right;
|
||||
InvalidateRect(editor->hWnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ME_InvalidateSelection(ME_TextEditor *editor)
|
||||
{
|
||||
if (ME_IsSelection(editor) || editor->nLastSelStart != editor->nLastSelEnd)
|
||||
{
|
||||
int x, y, height;
|
||||
int x2, y2, height2;
|
||||
int last_x, last_y, last_height;
|
||||
int last_x2, last_y2, last_height2;
|
||||
RECT rc;
|
||||
ME_Cursor tmp;
|
||||
|
||||
ME_GetCursorCoordinates(editor, &editor->pCursors[1], &x, &y, &height);
|
||||
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x2, &y2, &height2);
|
||||
ME_RunOfsFromCharOfs(editor, editor->nLastSelStart, &tmp.pRun, &tmp.nOffset);
|
||||
ME_GetCursorCoordinates(editor, &tmp, &last_x, &last_y, &last_height);
|
||||
ME_RunOfsFromCharOfs(editor, editor->nLastSelEnd, &tmp.pRun, &tmp.nOffset);
|
||||
ME_GetCursorCoordinates(editor, &tmp, &last_x2, &last_y2, &last_height2);
|
||||
{
|
||||
rc.left = 0;
|
||||
|
||||
rc.top = min(min(y, last_y), min(y2, last_y2));
|
||||
rc.right = editor->rcFormat.right;
|
||||
rc.bottom = max(max(y + height, last_y + last_height),
|
||||
max(y2 + height2, last_y2 + last_height2));
|
||||
InvalidateRect(editor->hWnd, &rc, FALSE);
|
||||
}
|
||||
}
|
||||
ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor)
|
||||
{
|
||||
editor->nInvalidOfs = ME_GetCursorOfs(editor, nCursor);
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator)
|
||||
|
|
|
@ -380,15 +380,17 @@ void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
|
|||
|
||||
|
||||
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
|
||||
ME_DisplayItem *p;
|
||||
ME_DisplayItem *p, *pRow;
|
||||
|
||||
/* remove all items that will be reinserted by paragraph wrapper anyway */
|
||||
tp->member.para.nRows = 0;
|
||||
for (p = tp->next; p!=tp->member.para.next_para; p = p->next) {
|
||||
switch(p->type) {
|
||||
case diStartRow:
|
||||
pRow = p;
|
||||
p = p->prev;
|
||||
ME_Remove(p->next);
|
||||
ME_Remove(pRow);
|
||||
ME_DestroyDisplayItem(pRow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -422,6 +424,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
|||
ME_DisplayItem *item;
|
||||
ME_Context c;
|
||||
BOOL bModified = FALSE;
|
||||
int yStart = -1, yEnd = -1;
|
||||
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
c.pt.x = 0;
|
||||
|
@ -439,11 +442,17 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
|||
ME_WrapTextParagraph(&c, item);
|
||||
|
||||
if (bRedraw)
|
||||
{
|
||||
item->member.para.nFlags |= MEPF_REPAINT;
|
||||
if (yStart == -1)
|
||||
yStart = c.pt.y;
|
||||
}
|
||||
|
||||
bModified = bModified | bRedraw;
|
||||
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
if (bRedraw)
|
||||
yEnd = c.pt.y;
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
|
||||
|
@ -453,6 +462,32 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
|||
|
||||
ME_DestroyContext(&c);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
if (editor->bRedraw)
|
||||
{
|
||||
RECT rc = c.rcView;
|
||||
|
||||
/* Invalidate rewrapped rows */
|
||||
if (yStart != -1)
|
||||
{
|
||||
yStart -= ME_GetYScrollPos(editor);
|
||||
yEnd -= ME_GetYScrollPos(editor);
|
||||
if ((yStart >= 0 && yStart < c.rcView.bottom - c.rcView.top)
|
||||
|| (yEnd >= 0 && yEnd < c.rcView.bottom - c.rcView.top))
|
||||
{
|
||||
rc.top = yStart;
|
||||
rc.bottom = yEnd;
|
||||
InvalidateRect(editor->hWnd, &rc, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate cursor row */
|
||||
if (editor->nInvalidOfs != -1)
|
||||
{
|
||||
ME_InvalidateFromOfs(editor, editor->nInvalidOfs);
|
||||
editor->nInvalidOfs = -1;
|
||||
}
|
||||
}
|
||||
return bModified;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue