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);
static BOOL
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[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 +118,8 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
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 +128,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
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 +136,25 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
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, &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;
ME_WrapMarkedParagraphs(editor);
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
CreateCaret(editor->hWnd, NULL, 0, height);
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)
{
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 +1162,8 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
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 +1212,8 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
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);

View File

@ -1048,7 +1048,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
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;

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_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 *editor, ME_DisplayItem *para, PARAFORMAT2 *
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 *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);

View File

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

View File

@ -505,35 +505,49 @@ ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs)
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;
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_GetSelectionParas(editor, &para1, &para2);
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));
}
ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
}
/* 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)

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 */
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_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);

View File

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

View File

@ -462,33 +462,40 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
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);
}