riched20: Reduced screen flicker by using proper update region invalidation.

This commit is contained in:
Phil Krylov 2006-01-10 20:23:41 +01:00 committed by Alexandre Julliard
parent 1406010d3c
commit 6818762a6e
6 changed files with 318 additions and 259 deletions

View File

@ -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, &para->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;
}

View File

@ -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:
{

View File

@ -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 */

View File

@ -285,6 +285,7 @@ typedef struct tagME_TextEditor
int nZoomNumerator, nZoomDenominator;
RECT rcFormat;
BOOL bRedraw;
int nInvalidOfs;
} ME_TextEditor;
typedef struct tagME_Context

View File

@ -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)

View File

@ -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;
}