riched20: New, clean, simple selection repaint logic - should fix all outstanding refresh issues.

This commit is contained in:
Krzysztof Foltman 2006-08-07 17:27:16 +02:00 committed by Alexandre Julliard
parent 6128a05071
commit bad844d0a9
8 changed files with 108 additions and 60 deletions

View File

@ -24,7 +24,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(richedit); WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static BOOL static BOOL
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs); ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
@ -87,7 +86,7 @@ void ME_SetSelection(ME_TextEditor *editor, int from, int to)
editor->pCursors[1].nOffset = 0; editor->pCursors[1].nOffset = 0;
editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
editor->pCursors[0].nOffset = 0; editor->pCursors[0].nOffset = 0;
ME_Repaint(editor); ME_InvalidateSelection(editor);
ME_ClearTempStyle(editor); ME_ClearTempStyle(editor);
return; return;
} }
@ -119,6 +118,8 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
assert(!pCursor->nOffset || !editor->bCaretAtEnd); assert(!pCursor->nOffset || !editor->bCaretAtEnd);
assert(height && x && y); assert(height && x && y);
assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP)); assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP));
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
if (pCursorRun->type == diRun) { if (pCursorRun->type == diRun) {
ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph); ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
@ -127,7 +128,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
HDC hDC = GetDC(editor->hWnd); HDC hDC = GetDC(editor->hWnd);
ME_Context c; ME_Context c;
ME_DisplayItem *run = pCursorRun; ME_DisplayItem *run = pCursorRun;
ME_DisplayItem *para; ME_DisplayItem *para = NULL;
SIZE sz = {0, 0}; SIZE sz = {0, 0};
ME_InitContext(&c, editor, hDC); ME_InitContext(&c, editor, hDC);
@ -135,19 +136,25 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
if (!pCursor->nOffset && !editor->bCaretAtEnd) if (!pCursor->nOffset && !editor->bCaretAtEnd)
{ {
ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow); ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
assert(prev);
if (prev->type == diRun) if (prev->type == diRun)
pSizeRun = prev; pSizeRun = prev;
} }
assert(row->type == diStartRow); /* paragraph -> run without start row ?*/ assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
para = ME_FindItemBack(row, diParagraph); para = ME_FindItemBack(row, diParagraph);
assert(para);
assert(para->type == diParagraph);
if (editor->bCaretAtEnd && !pCursor->nOffset && if (editor->bCaretAtEnd && !pCursor->nOffset &&
run == ME_FindItemFwd(row, diRun)) run == ME_FindItemFwd(row, diRun))
{ {
ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph); ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
assert(tmp);
if (tmp->type == diRun) if (tmp->type == diRun)
{ {
row = ME_FindItemBack(tmp, diStartRow); row = ME_FindItemBack(tmp, diStartRow);
pSizeRun = run = tmp; pSizeRun = run = tmp;
assert(run);
assert(run->type == diRun);
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, ME_StrLen(run->member.run.strText)); sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
} }
} }
@ -175,6 +182,7 @@ ME_MoveCaret(ME_TextEditor *editor)
{ {
int x, y, height; int x, y, height;
ME_WrapMarkedParagraphs(editor);
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height); ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
CreateCaret(editor->hWnd, NULL, 0, height); CreateCaret(editor->hWnd, NULL, 0, height);
SetCaretPos(x, y); SetCaretPos(x, y);
@ -992,6 +1000,10 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor) static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{ {
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow); ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
/* bCaretAtEnd doesn't make sense if the cursor isn't set at the
first character of the next row */
assert(!editor->bCaretAtEnd || !pCursor->nOffset);
ME_WrapMarkedParagraphs(editor);
if (pRow) { if (pRow) {
ME_DisplayItem *pRun; ME_DisplayItem *pRun;
if (editor->bCaretAtEnd && !pCursor->nOffset) { if (editor->bCaretAtEnd && !pCursor->nOffset) {
@ -1151,9 +1163,7 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
ME_Cursor tmp_curs = *p; ME_Cursor tmp_curs = *p;
BOOL success = FALSE; BOOL success = FALSE;
if (ME_IsSelection(editor) && !extend) ME_CheckCharOffsets(editor);
ME_InvalidateSelection(editor);
editor->nUDArrowX = -1; editor->nUDArrowX = -1;
switch(nVKey) { switch(nVKey) {
case VK_LEFT: case VK_LEFT:
@ -1202,8 +1212,8 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
editor->pCursors[1] = tmp_curs; editor->pCursors[1] = tmp_curs;
*p = tmp_curs; *p = tmp_curs;
if (ME_IsSelection(editor))
ME_InvalidateSelection(editor); ME_InvalidateSelection(editor);
ME_Repaint(editor);
HideCaret(editor->hWnd); HideCaret(editor->hWnd);
ME_EnsureVisible(editor, tmp_curs.pRun); ME_EnsureVisible(editor, tmp_curs.pRun);
ME_ShowCaret(editor); ME_ShowCaret(editor);

View File

@ -1048,7 +1048,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
ME_DeleteTextAtCursor(editor, 1, 1); ME_DeleteTextAtCursor(editor, 1, 1);
else else
return TRUE; return TRUE;
ME_QueueInvalidateFromCursor(editor, 1); ME_CommitUndo(editor);
ME_UpdateRepaint(editor); ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE); ME_SendRequestResize(editor, FALSE);
return TRUE; return TRUE;
@ -1130,6 +1130,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->nUndoMode = umAddToUndo; ed->nUndoMode = umAddToUndo;
ed->nParagraphs = 1; ed->nParagraphs = 1;
ed->nLastSelStart = ed->nLastSelEnd = 0; ed->nLastSelStart = ed->nLastSelEnd = 0;
ed->pLastSelStartPara = ed->pLastSelEndPara = ME_FindItemFwd(ed->pBuffer->pFirst, diParagraph);
ed->nScrollPosY = 0; ed->nScrollPosY = 0;
ed->nZoomNumerator = ed->nZoomDenominator = 0; ed->nZoomNumerator = ed->nZoomDenominator = 0;
ed->bRedraw = TRUE; ed->bRedraw = TRUE;

View File

@ -202,10 +202,12 @@ ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd); void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp); void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor); BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor);
void ME_SendRequestResize(ME_TextEditor *editor, BOOL force); void ME_SendRequestResize(ME_TextEditor *editor, BOOL force);
/* para.c */ /* para.c */
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end);
void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *editor); void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *editor);
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style); ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style);
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp); ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp);
@ -217,6 +219,7 @@ void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt); void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt);
/* marks from first up to (but not including) last */ /* marks from first up to (but not including) last */
void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last); void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last);
void ME_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last);
void ME_MarkAllForWrapping(ME_TextEditor *editor); void ME_MarkAllForWrapping(ME_TextEditor *editor);
/* paint.c */ /* paint.c */
@ -230,7 +233,6 @@ int ME_GetYScrollPos(ME_TextEditor *editor);
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun); void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
COLORREF ME_GetBackColor(ME_TextEditor *editor); COLORREF ME_GetBackColor(ME_TextEditor *editor);
void ME_Scroll(ME_TextEditor *editor, int cx, int cy); 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_InvalidateSelection(ME_TextEditor *editor);
void ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor); void ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor);
BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator); BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator);

View File

@ -64,6 +64,7 @@ typedef struct tagME_Style
} ME_Style; } ME_Style;
typedef enum { typedef enum {
diInvalid,
diTextStart, /* start of the text buffer */ diTextStart, /* start of the text buffer */
diParagraph, /* paragraph start */ diParagraph, /* paragraph start */
diRun, /* run (sequence of chars with the same character format) */ diRun, /* run (sequence of chars with the same character format) */
@ -292,7 +293,6 @@ typedef struct tagME_TextEditor
int nTotalLength, nLastTotalLength; int nTotalLength, nLastTotalLength;
int nUDArrowX; int nUDArrowX;
int nSequence; int nSequence;
int nOldSelFrom, nOldSelTo;
COLORREF rgbBackColor; COLORREF rgbBackColor;
HBRUSH hbrBackground; HBRUSH hbrBackground;
BOOL bCaretAtEnd; BOOL bCaretAtEnd;
@ -304,6 +304,7 @@ typedef struct tagME_TextEditor
ME_UndoMode nUndoMode; ME_UndoMode nUndoMode;
int nParagraphs; int nParagraphs;
int nLastSelStart, nLastSelEnd; int nLastSelStart, nLastSelEnd;
ME_DisplayItem *pLastSelStartPara, *pLastSelEndPara;
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE]; ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
BOOL bScrollX, bScrollY; BOOL bScrollX, bScrollY;
int nScrollPosY; int nScrollPosY;

View File

@ -505,36 +505,50 @@ ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs)
void void
ME_InvalidateSelection(ME_TextEditor *editor) ME_InvalidateSelection(ME_TextEditor *editor)
{ {
ME_DisplayItem *para1, *para2;
int nStart, nEnd;
int len = ME_GetTextLength(editor);
ME_GetSelection(editor, &nStart, &nEnd);
/* if both old and new selection are 0-char (= caret only), then
there's no (inverted) area to be repainted, neither old nor new */
if (nStart == nEnd && editor->nLastSelStart == editor->nLastSelEnd)
return;
ME_WrapMarkedParagraphs(editor); ME_WrapMarkedParagraphs(editor);
if (ME_IsSelection(editor) || editor->nLastSelStart != editor->nLastSelEnd) ME_GetSelectionParas(editor, &para1, &para2);
{ assert(para1->type == diParagraph);
int x, y, height; assert(para2->type == diParagraph);
int x2, y2, height2; /* last selection markers aren't always updated, which means
int last_x, last_y, last_height; they can point past the end of the document */
int last_x2, last_y2, last_height2; if (editor->nLastSelStart > len)
RECT rc; editor->nLastSelEnd = len;
ME_Cursor tmp; if (editor->nLastSelEnd > len)
editor->nLastSelEnd = len;
ME_GetCursorCoordinates(editor, &editor->pCursors[1], &x, &y, &height); /* if the start part of selection is being expanded or contracted... */
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x2, &y2, &height2); if (nStart < editor->nLastSelStart) {
ME_RunOfsFromCharOfs(editor, editor->nLastSelStart, &tmp.pRun, &tmp.nOffset); ME_MarkForPainting(editor, para1, ME_FindItemFwd(editor->pLastSelStartPara, diParagraphOrEnd));
ME_GetCursorCoordinates(editor, &tmp, &last_x, &last_y, &last_height); } else
ME_RunOfsFromCharOfs(editor, editor->nLastSelEnd, &tmp.pRun, &tmp.nOffset); if (nStart > editor->nLastSelStart) {
ME_GetCursorCoordinates(editor, &tmp, &last_x2, &last_y2, &last_height2); ME_MarkForPainting(editor, editor->pLastSelStartPara, ME_FindItemFwd(para1, diParagraphOrEnd));
{ }
rc.left = 0;
rc.top = min(min(y, last_y), min(y2, last_y2)); /* if the end part of selection is being contracted or expanded... */
rc.right = editor->rcFormat.right; if (nEnd < editor->nLastSelEnd) {
rc.bottom = max(max(y + height, last_y + last_height), ME_MarkForPainting(editor, para2, ME_FindItemFwd(editor->pLastSelEndPara, diParagraphOrEnd));
max(y2 + height2, last_y2 + last_height2)); } else
InvalidateRect(editor->hWnd, &rc, FALSE); if (nEnd > editor->nLastSelEnd) {
} ME_MarkForPainting(editor, editor->pLastSelEndPara, ME_FindItemFwd(para2, diParagraphOrEnd));
} }
ME_InvalidateMarkedParagraphs(editor);
/* remember the last invalidated position */
ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd); ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
ME_GetSelectionParas(editor, &editor->pLastSelStartPara, &editor->pLastSelEndPara);
assert(editor->pLastSelStartPara->type == diParagraph);
assert(editor->pLastSelEndPara->type == diParagraph);
} }
void void
ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor) ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor)
{ {

View File

@ -92,6 +92,15 @@ void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_Display
} }
} }
void ME_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last)
{
while(first != last)
{
first->member.para.nFlags |= MEPF_REPAINT;
first = first->member.para.next_para;
}
}
/* split paragraph at the beginning of the run */ /* split paragraph at the beginning of the run */
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style) ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style)
{ {
@ -245,6 +254,11 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
ME_Remove(pRun); ME_Remove(pRun);
ME_DestroyDisplayItem(pRun); ME_DestroyDisplayItem(pRun);
if (editor->pLastSelStartPara == pNext)
editor->pLastSelStartPara = tp;
if (editor->pLastSelEndPara == pNext)
editor->pLastSelEndPara = tp;
tp->member.para.next_para = pNext->member.para.next_para; tp->member.para.next_para = pNext->member.para.next_para;
pNext->member.para.next_para->member.para.prev_para = tp; pNext->member.para.next_para->member.para.prev_para = tp;
ME_Remove(pNext); ME_Remove(pNext);

View File

@ -148,7 +148,6 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
} }
void ME_CommitUndo(ME_TextEditor *editor) { void ME_CommitUndo(ME_TextEditor *editor) {
if (editor->nUndoMode == umIgnore) if (editor->nUndoMode == umIgnore)
return; return;

View File

@ -463,32 +463,39 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_DestroyContext(&c); ME_DestroyContext(&c);
ReleaseDC(hWnd, hDC); ReleaseDC(hWnd, hDC);
if (bModified || editor->nTotalLength < editor->nLastTotalLength)
ME_InvalidateMarkedParagraphs(editor);
return bModified;
}
void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) {
ME_Context c;
HDC hDC = GetDC(editor->hWnd);
ME_InitContext(&c, editor, hDC);
if (editor->bRedraw) if (editor->bRedraw)
{ {
RECT rc = c.rcView; RECT rc = c.rcView;
int ofs = ME_GetYScrollPos(editor);
/* Invalidate rewrapped rows */ ME_DisplayItem *item = editor->pBuffer->pFirst;
if (yStart != -1) while(item != editor->pBuffer->pLast) {
if (item->member.para.nFlags & MEPF_REPAINT) {
rc.top = item->member.para.nYPos - ofs;
rc.bottom = item->member.para.nYPos + item->member.para.nHeight - ofs;
InvalidateRect(editor->hWnd, &rc, TRUE);
}
item = item->member.para.next_para;
}
if (editor->nTotalLength < editor->nLastTotalLength)
{ {
yStart -= ME_GetYScrollPos(editor); rc.top = editor->nTotalLength - ofs;
yEnd -= ME_GetYScrollPos(editor); rc.bottom = editor->nLastTotalLength - ofs;
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); InvalidateRect(editor->hWnd, &rc, TRUE);
} }
} }
ME_DestroyContext(&c);
/* Invalidate cursor row */ ReleaseDC(editor->hWnd, hDC);
if (editor->nInvalidOfs != -1)
{
ME_InvalidateFromOfs(editor, editor->nInvalidOfs);
editor->nInvalidOfs = -1;
}
}
return bModified;
} }