riched20: New, clean, simple selection repaint logic - should fix all outstanding refresh issues.
This commit is contained in:
parent
6128a05071
commit
bad844d0a9
|
@ -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, ¶->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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ¶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));
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue