From 6818762a6ed50aa9a726085b3439be215916d897 Mon Sep 17 00:00:00 2001 From: Phil Krylov Date: Tue, 10 Jan 2006 20:23:41 +0100 Subject: [PATCH] riched20: Reduced screen flicker by using proper update region invalidation. --- dlls/riched20/caret.c | 376 ++++++++++++++++++++---------------------------- dlls/riched20/editor.c | 81 ++++++++--- dlls/riched20/editor.h | 7 +- dlls/riched20/editstr.h | 1 + dlls/riched20/paint.c | 65 ++++++++- dlls/riched20/wrap.c | 39 ++++- 6 files changed, 314 insertions(+), 255 deletions(-) diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c index 03bfcf3781a..a4232f6b7b9 100644 --- a/dlls/riched20/caret.c +++ b/dlls/riched20/caret.c @@ -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_ofspRun->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) + +static void +ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs) { ME_DisplayItem *pRun = pCursor->pRun; - ME_DisplayItem *pItem, *pItem2; + ME_DisplayItem *pItem; 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) */ + if (!pRun) 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) -{ - ME_DisplayItem *pRun = pCursor->pRun; - ME_DisplayItem *pItem; - int x = ME_GetXForArrow(editor, pCursor); - if (!pCursor->nOffset && editor->bCaretAtEnd) + if (nRelOfs == -1) { - pRun = ME_FindItemBack(pRun, diRun); -/* x = pRun->member.run.pt.x + pRun->member.run.nWidth; */ + /* 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; + BOOL success = FALSE; + + if (ME_IsSelection(editor) && !extend) + ME_InvalidateSelection(editor); + editor->nUDArrowX = -1; switch(nVKey) { + 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_ArrowUp(editor, p); - ME_ClearTempStyle(editor); - ME_RepaintSelection(editor, &tmp_curs); - ME_SendSelChange(editor); - return TRUE; + ME_MoveCursorLines(editor, &tmp_curs, -1); + break; case VK_DOWN: - ME_ArrowDown(editor, p); - ME_ClearTempStyle(editor); - ME_RepaintSelection(editor, &tmp_curs); - ME_SendSelChange(editor); - return TRUE; + ME_MoveCursorLines(editor, &tmp_curs, +1); + break; case VK_PRIOR: - ME_ArrowPageUp(editor, p); - ME_ClearTempStyle(editor); - ME_SendSelChange(editor); - return TRUE; + ME_ArrowPageUp(editor, &tmp_curs); + break; case VK_NEXT: - ME_ArrowPageDown(editor, p); - ME_ClearTempStyle(editor); - ME_SendSelChange(editor); - return TRUE; - } - - 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; - } + 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; } diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index a4c7618d9d8..723b69b2386 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -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; ipCursors[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: { diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index 98167c789df..52435529bff 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -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 */ diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 7a7398f37fa..86dcfdb17cf 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -285,6 +285,7 @@ typedef struct tagME_TextEditor int nZoomNumerator, nZoomDenominator; RECT rcFormat; BOOL bRedraw; + int nInvalidOfs; } ME_TextEditor; typedef struct tagME_Context diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index e1c56b4ffa5..94f0bf384a9 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -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) diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index 4ea9ac45e2c..f3d3e9d8cb9 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -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; } -- 2.11.4.GIT