riched20: new selection invalidation logic
Krzysztof Foltman
wdev at foltman.com
Mon Aug 7 10:27:16 CDT 2006
ChangeLog:
* New, clean, simple selection repaint logic - should fix all
outstanding refresh issues (and bug#5882)
Krzysztof
-------------- next part --------------
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index 5124822..5096bf8 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -24,6 +24,7 @@ #include "editor.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+#define static
static BOOL
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
@@ -87,7 +88,7 @@ void ME_SetSelection(ME_TextEditor *edit
editor->pCursors[1].nOffset = 0;
editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
editor->pCursors[0].nOffset = 0;
- ME_Repaint(editor);
+ ME_InvalidateSelection(editor);
ME_ClearTempStyle(editor);
return;
}
@@ -119,6 +120,8 @@ ME_GetCursorCoordinates(ME_TextEditor *e
assert(!pCursor->nOffset || !editor->bCaretAtEnd);
assert(height && x && y);
assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP));
+ assert(pCursor->pRun);
+ assert(pCursor->pRun->type == diRun);
if (pCursorRun->type == diRun) {
ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
@@ -127,7 +130,7 @@ ME_GetCursorCoordinates(ME_TextEditor *e
HDC hDC = GetDC(editor->hWnd);
ME_Context c;
ME_DisplayItem *run = pCursorRun;
- ME_DisplayItem *para;
+ ME_DisplayItem *para = NULL;
SIZE sz = {0, 0};
ME_InitContext(&c, editor, hDC);
@@ -135,19 +138,25 @@ ME_GetCursorCoordinates(ME_TextEditor *e
if (!pCursor->nOffset && !editor->bCaretAtEnd)
{
ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
+ assert(prev);
if (prev->type == diRun)
pSizeRun = prev;
}
assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
para = ME_FindItemBack(row, diParagraph);
+ assert(para);
+ assert(para->type == diParagraph);
if (editor->bCaretAtEnd && !pCursor->nOffset &&
run == ME_FindItemFwd(row, diRun))
{
ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
+ assert(tmp);
if (tmp->type == diRun)
{
row = ME_FindItemBack(tmp, diStartRow);
pSizeRun = run = tmp;
+ assert(run);
+ assert(run->type == diRun);
sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
}
}
@@ -175,6 +184,7 @@ ME_MoveCaret(ME_TextEditor *editor)
{
int x, y, height;
+ ME_WrapMarkedParagraphs(editor);
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
CreateCaret(editor->hWnd, NULL, 0, height);
SetCaretPos(x, y);
@@ -992,6 +1002,10 @@ static void ME_ArrowPageDown(ME_TextEdit
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
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) {
ME_DisplayItem *pRun;
if (editor->bCaretAtEnd && !pCursor->nOffset) {
@@ -1150,10 +1164,8 @@ ME_ArrowKey(ME_TextEditor *editor, int n
ME_Cursor *p = &editor->pCursors[nCursor];
ME_Cursor tmp_curs = *p;
BOOL success = FALSE;
-
- if (ME_IsSelection(editor) && !extend)
- ME_InvalidateSelection(editor);
+ ME_CheckCharOffsets(editor);
editor->nUDArrowX = -1;
switch(nVKey) {
case VK_LEFT:
@@ -1202,8 +1214,8 @@ ME_ArrowKey(ME_TextEditor *editor, int n
editor->pCursors[1] = tmp_curs;
*p = tmp_curs;
- if (ME_IsSelection(editor))
- ME_InvalidateSelection(editor);
+ ME_InvalidateSelection(editor);
+ ME_Repaint(editor);
HideCaret(editor->hWnd);
ME_EnsureVisible(editor, tmp_curs.pRun);
ME_ShowCaret(editor);
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 1268782..7c45edb 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -1048,7 +1048,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD n
ME_DeleteTextAtCursor(editor, 1, 1);
else
return TRUE;
- ME_QueueInvalidateFromCursor(editor, 1);
+ ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE);
return TRUE;
@@ -1130,6 +1130,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd)
ed->nUndoMode = umAddToUndo;
ed->nParagraphs = 1;
ed->nLastSelStart = ed->nLastSelEnd = 0;
+ ed->pLastSelStartPara = ed->pLastSelEndPara = ME_FindItemFwd(ed->pBuffer->pFirst, diParagraph);
ed->nScrollPosY = 0;
ed->nZoomNumerator = ed->nZoomDenominator = 0;
ed->bRedraw = TRUE;
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
index 93952fd..4409069 100644
--- a/dlls/riched20/editor.h
+++ b/dlls/riched20/editor.h
@@ -202,10 +202,12 @@ ME_DisplayItem *ME_MakeRow(int height, i
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
+void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor);
void ME_SendRequestResize(ME_TextEditor *editor, BOOL force);
/* para.c */
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);
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style);
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp);
@@ -217,6 +219,7 @@ void ME_GetParaFormat(ME_TextEditor *edi
void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt);
/* marks from first up to (but not including) 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);
/* paint.c */
@@ -230,7 +233,6 @@ int ME_GetYScrollPos(ME_TextEditor *edit
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);
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index 7d096e8..1109175 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -64,6 +64,7 @@ typedef struct tagME_Style
} ME_Style;
typedef enum {
+ diInvalid,
diTextStart, /* start of the text buffer */
diParagraph, /* paragraph start */
diRun, /* run (sequence of chars with the same character format) */
@@ -292,7 +293,6 @@ typedef struct tagME_TextEditor
int nTotalLength, nLastTotalLength;
int nUDArrowX;
int nSequence;
- int nOldSelFrom, nOldSelTo;
COLORREF rgbBackColor;
HBRUSH hbrBackground;
BOOL bCaretAtEnd;
@@ -304,6 +304,7 @@ typedef struct tagME_TextEditor
ME_UndoMode nUndoMode;
int nParagraphs;
int nLastSelStart, nLastSelEnd;
+ ME_DisplayItem *pLastSelStartPara, *pLastSelEndPara;
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
BOOL bScrollX, bScrollY;
int nScrollPosY;
diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c
index 899f2d0..41f2652 100644
--- a/dlls/riched20/paint.c
+++ b/dlls/riched20/paint.c
@@ -505,36 +505,50 @@ ME_InvalidateFromOfs(ME_TextEditor *edit
void
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);
- 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;
+ ME_GetSelectionParas(editor, ¶1, ¶2);
+ assert(para1->type == diParagraph);
+ assert(para2->type == diParagraph);
+ /* last selection markers aren't always updated, which means
+ they can point past the end of the document */
+ if (editor->nLastSelStart > len)
+ editor->nLastSelEnd = len;
+ if (editor->nLastSelEnd > len)
+ editor->nLastSelEnd = len;
+
+ /* if the start part of selection is being expanded or contracted... */
+ if (nStart < editor->nLastSelStart) {
+ ME_MarkForPainting(editor, para1, ME_FindItemFwd(editor->pLastSelStartPara, diParagraphOrEnd));
+ } else
+ if (nStart > editor->nLastSelStart) {
+ ME_MarkForPainting(editor, editor->pLastSelStartPara, ME_FindItemFwd(para1, diParagraphOrEnd));
+ }
- 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);
- }
+ /* if the end part of selection is being contracted or expanded... */
+ if (nEnd < editor->nLastSelEnd) {
+ ME_MarkForPainting(editor, para2, ME_FindItemFwd(editor->pLastSelEndPara, diParagraphOrEnd));
+ } else
+ 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_GetSelectionParas(editor, &editor->pLastSelStartPara, &editor->pLastSelEndPara);
+ assert(editor->pLastSelStartPara->type == diParagraph);
+ assert(editor->pLastSelEndPara->type == diParagraph);
}
-
void
ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor)
{
diff --git a/dlls/riched20/para.c b/dlls/riched20/para.c
index def9012..1774957 100644
--- a/dlls/riched20/para.c
+++ b/dlls/riched20/para.c
@@ -92,6 +92,15 @@ void ME_MarkForWrapping(ME_TextEditor *e
}
}
+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 */
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style)
{
@@ -245,6 +254,11 @@ ME_DisplayItem *ME_JoinParagraphs(ME_Tex
ME_Remove(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;
pNext->member.para.next_para->member.para.prev_para = tp;
ME_Remove(pNext);
diff --git a/dlls/riched20/undo.c b/dlls/riched20/undo.c
index 63c9910..181121a 100644
--- a/dlls/riched20/undo.c
+++ b/dlls/riched20/undo.c
@@ -148,7 +148,6 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEdito
}
void ME_CommitUndo(ME_TextEditor *editor) {
-
if (editor->nUndoMode == umIgnore)
return;
diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c
index 6206c0f..af6e9a9 100644
--- a/dlls/riched20/wrap.c
+++ b/dlls/riched20/wrap.c
@@ -462,33 +462,40 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEdit
ME_DestroyContext(&c);
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)
{
- RECT rc = c.rcView;
+ RECT rc = c.rcView;
+ int ofs = ME_GetYScrollPos(editor);
- /* 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;
- }
+ ME_DisplayItem *item = editor->pBuffer->pFirst;
+ 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)
+ {
+ rc.top = editor->nTotalLength - ofs;
+ rc.bottom = editor->nLastTotalLength - ofs;
+ InvalidateRect(editor->hWnd, &rc, TRUE);
+ }
}
- return bModified;
+ ME_DestroyContext(&c);
+ ReleaseDC(editor->hWnd, hDC);
}
More information about the wine-patches
mailing list