RICHEDIT: scrollbar/repainting fixes, string handling fixes, Page Down handling

Krzysztof Foltman wdev at foltman.com
Fri Mar 18 15:53:58 CST 2005


ChangeLog:
 * made string operations consistent wrt whitespace handling (which 
should greatly improve stability of the wrap code and eliminate 
regressions of the most recent versions)
 * completely new scrollbar handling (much more reliable) and related 
redraw fixes
 * Page Down handler (no Page Up yet, fixing wrap/redraw/scrollbar bugs 
was of higher priority)

Krzysztof
-------------- next part --------------
Index: caret.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/caret.c,v
retrieving revision 1.6
diff -u -r1.6 caret.c
--- caret.c	17 Mar 2005 10:23:40 -0000	1.6
+++ caret.c	18 Mar 2005 21:40:10 -0000
@@ -697,6 +697,54 @@
   assert(pCursor->pRun->type == diRun);
 }
 
+void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRun = pCursor->pRun;
+  ME_DisplayItem *pLast, *p;
+  int x, y, ys, yd, yp, yprev;
+  ME_Cursor tmp_curs = *pCursor;
+  
+  x = ME_GetXForArrow(editor, pCursor);
+  if (!pCursor->nOffset && editor->bCaretAtEnd)
+    pRun = ME_FindItemBack(pRun, diRun);
+  
+  p = ME_FindItemBack(pRun, diStartRowOrParagraph);
+  assert(p->type == diStartRow);
+  yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
+  yprev = ys = y = yp + p->member.row.nYPos;
+  yd = y + editor->sizeWindow.cy;
+  pLast = p;
+  
+  do {
+    p = ME_FindItemFwd(p, diStartRowOrParagraph);
+    if (!p)
+      break;
+    if (p->type == diParagraph) {
+      yp = p->member.para.nYPos;
+      continue;
+    }
+    y = yp + p->member.row.nYPos;
+    if (y >= yd)
+      break;
+    pLast = p;
+    yprev = y;
+  } while(1);
+  
+  pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
+  ME_UpdateSelection(editor, &tmp_curs);
+  if (yprev >= editor->nTotalLength-editor->sizeWindow.cy)
+  {
+    ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
+    ME_Repaint(editor);
+  }
+  else {
+    ME_Repaint(editor);
+    ME_Scroll(editor, 0, ys-yprev);
+  }
+  assert(pCursor->pRun);
+  assert(pCursor->pRun->type == diRun);
+}
+
 void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
 {
   ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
@@ -798,7 +846,7 @@
   return TRUE;
 }
 
-void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
+BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
 {
   ME_Cursor old_anchor = editor->pCursors[1];
   
@@ -807,20 +855,30 @@
     /* any selection was present ? if so, it's no more, repaint ! */
     editor->pCursors[1] = editor->pCursors[0];
     if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
-      ME_Repaint(editor);
-      return;
+      return TRUE;
     }
-    return;
+    return FALSE;
   }
   else
   {
     if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
     {
       editor->pCursors[1] = *pTempCursor;
+      return TRUE;
+//      ME_EnsureVisible(editor, editor->pCursors[0].pRun);
     }
   }
 
   ME_Repaint(editor);
+  return TRUE;
+}
+
+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)
@@ -883,6 +941,11 @@
       ME_RepaintSelection(editor, &tmp_curs);
       ME_SendSelChange(editor);
       return TRUE;
+    case VK_NEXT:
+      ME_ArrowPageDown(editor, p);
+      ME_ClearTempStyle(editor);
+      ME_SendSelChange(editor);
+      return TRUE;
   }
   
   editor->nUDArrowX = -1;
Index: editor.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.c,v
retrieving revision 1.16
diff -u -r1.16 editor.c
--- editor.c	18 Mar 2005 10:24:51 -0000	1.16
+++ editor.c	18 Mar 2005 21:40:11 -0000
@@ -505,10 +505,10 @@
   ME_CommitUndo(editor);
   ME_ReleaseStyle(style); 
   editor->nEventMask = nEventMask;
+  InvalidateRect(editor->hWnd, NULL, TRUE);
   ME_UpdateRepaint(editor);
   if (!(format & SFF_SELECTION)) {
     ME_ClearTempStyle(editor);
-    ME_EnsureVisible(editor, editor->pCursors[0].pRun);
   }
   ME_MoveCaret(editor);
   ME_SendSelChange(editor);
@@ -1147,6 +1147,8 @@
   case WM_SIZE:
   {
     ME_MarkAllForWrapping(editor);
+    ME_WrapMarkedParagraphs(editor);
+    ME_UpdateScrollBar(editor);
     ME_Repaint(editor);
     return DefWindowProcW(hWnd, msg, wParam, lParam);
   }
Index: editor.h
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.h,v
retrieving revision 1.9
diff -u -r1.9 editor.h
--- editor.h	17 Mar 2005 10:23:40 -0000	1.9
+++ editor.h	18 Mar 2005 21:40:11 -0000
@@ -161,13 +161,14 @@
 void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
 int ME_GetTextLength(ME_TextEditor *editor);
 ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
+BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor);
 
 /* wrap.c */
 void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
 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);
-void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
+BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
 
 /* para.c */
 ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); 
@@ -189,10 +190,11 @@
 void ME_Repaint(ME_TextEditor *editor);
 void ME_UpdateRepaint(ME_TextEditor *editor);
 void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
-void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
+void ME_UpdateScrollBar(ME_TextEditor *editor);
 int ME_GetScrollPos(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);
 
 /* richole.c */
 extern LRESULT CreateIRichEditOle(LPVOID *);
Index: editstr.h
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editstr.h,v
retrieving revision 1.5
diff -u -r1.5 editstr.h
--- editstr.h	14 Mar 2005 21:41:16 -0000	1.5
+++ editstr.h	18 Mar 2005 21:40:11 -0000
@@ -246,6 +246,7 @@
   int nLastSelStart, nLastSelEnd;
   ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
   ME_OutStream *pStream;
+  BOOL bScrollX, bScrollY;
 } ME_TextEditor;
 
 typedef struct tagME_Context
Index: paint.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/paint.c,v
retrieving revision 1.6
diff -u -r1.6 paint.c
--- paint.c	17 Mar 2005 10:23:40 -0000	1.6
+++ paint.c	18 Mar 2005 21:40:11 -0000
@@ -35,7 +35,9 @@
   item = editor->pBuffer->pFirst->next;
   c.pt.y -= yoffset;
   while(item != editor->pBuffer->pLast) {
+    int ye;
     assert(item->type == diParagraph);
+    ye = c.pt.y + item->member.para.nHeight;
     if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
     {
       BOOL bPaint = (rcUpdate == NULL);
@@ -45,10 +47,11 @@
       if (bPaint)
       {
         ME_DrawParagraph(&c, item);
-        item->member.para.nFlags &= ~MEPF_REPAINT;
+        if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye))
+          item->member.para.nFlags &= ~MEPF_REPAINT;
       }
     }
-    c.pt.y += item->member.para.nHeight;
+    c.pt.y = ye;
     item = item->member.para.next_para;
   }
   if (c.pt.y<c.rcView.bottom) {
@@ -152,12 +155,15 @@
   assert(pRun == pCursor->pRun);
   assert(nOffset == pCursor->nOffset);
   ME_MarkSelectionForRepaint(editor);
-  ME_WrapMarkedParagraphs(editor);
+  if (ME_WrapMarkedParagraphs(editor)) {
+    ME_UpdateScrollBar(editor);
+  }
   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);
 }
 
 void ME_UpdateRepaint(ME_TextEditor *editor)
@@ -372,38 +378,67 @@
   SetTextAlign(c->hDC, align);
 }
 
-void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos)
+void ME_Scroll(ME_TextEditor *editor, int cx, int cy)
 {
-  float perc = 0.0;
   SCROLLINFO si;
   HWND hWnd = editor->hWnd;
-  int overflow = editor->nTotalLength - editor->sizeWindow.cy;
+
   si.cbSize = sizeof(SCROLLINFO);
-  si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
+  si.fMask = SIF_POS;
   GetScrollInfo(hWnd, SB_VERT, &si);
+  si.nPos -= cy;
+  SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+  ScrollWindow(hWnd, cx, cy, NULL, NULL);
+}
+
+void ME_UpdateScrollBar(ME_TextEditor *editor)
+{
+  HWND hWnd = editor->hWnd;
+  SCROLLINFO si;
+  int nOldLen = editor->nTotalLength;
+  BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy);
+  BOOL bUpdateScrollBars;
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_POS | SIF_RANGE;
+  GetScrollInfo(hWnd, SB_VERT, &si);
+  bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy));
   
-  if (ypos < 0) {
-    if (si.nMax<1) si.nMax = 1;
-    perc = 1.0*si.nPos/si.nMax;
-    ypos = perc*overflow;
-  }
-  if (ypos >= overflow && overflow > 0)
-    ypos = overflow - 1;
-
-  if (overflow > 0) {
-    EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
-    SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
-    SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
-  } else {
-    EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
-    SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
-    SetScrollPos(hWnd, SB_VERT, 0, TRUE);
-  }
-  if (ypos != si.nPos)
+  if (bScrollY != editor->bScrollY)
   {
-    TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc);
-    ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
-    UpdateWindow(hWnd);
+    si.fMask = SIF_RANGE | SIF_PAGE;
+    si.nMin = 0;
+    si.nPage = editor->sizeWindow.cy;
+    if (bScrollY) {
+      si.nMax = editor->nTotalLength;
+    } else {
+      si.nMax = 0;
+    }
+    SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
+    ME_MarkAllForWrapping(editor);
+    editor->bScrollY = bScrollY;
+    ME_WrapMarkedParagraphs(editor);
+    bUpdateScrollBars = TRUE;
+  }
+  if (bUpdateScrollBars) {
+    int nScroll = 0;
+    si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+    if (editor->nTotalLength > editor->sizeWindow.cy) {
+      si.nMax = editor->nTotalLength;
+      si.nPage = editor->sizeWindow.cy;
+      if (si.nPos > si.nMax-si.nPage) {
+        nScroll = (si.nMax-si.nPage)-si.nPos;
+        si.nPos = si.nMax-si.nPage;
+      }
+    }
+    else {
+      si.nMax = 0;
+      si.nPage = 0;
+      si.nPos = 0;
+    }
+    TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll);
+    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+    if (nScroll)
+      ScrollWindow(hWnd, 0, -nScroll, NULL, NULL);
   }
 }
 
@@ -416,18 +451,24 @@
 {
   ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
   ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
-  int y, yrel, yheight;
+  int y, yrel, yheight, yold;
+  HWND hWnd = editor->hWnd;
   
   assert(pRow);
   assert(pPara);
   
   y = pPara->member.para.nYPos+pRow->member.row.nYPos;
   yheight = pRow->member.row.nHeight;
-  yrel = y - ME_GetScrollPos(editor);
-  if (yrel < 0)
-    ME_UpdateScrollBar(editor, y);
-  else if (yrel + yheight > editor->sizeWindow.cy)
-  {
-    ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);  
+  yold = ME_GetScrollPos(editor);
+  yrel = y - yold;
+  if (yrel < 0) {
+    SetScrollPos(hWnd, SB_VERT, y, TRUE);
+    ScrollWindow(hWnd, 0, -yrel, NULL, NULL);
+    UpdateWindow(hWnd);
+  } else if (yrel + yheight > editor->sizeWindow.cy) {
+    int newy = y+yheight-editor->sizeWindow.cy;
+    SetScrollPos(hWnd, SB_VERT, newy, TRUE);
+    ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL);
+    UpdateWindow(hWnd);
   }
 }
Index: run.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/run.c,v
retrieving revision 1.6
diff -u -r1.6 run.c
--- run.c	17 Mar 2005 10:23:40 -0000	1.6
+++ run.c	18 Mar 2005 21:40:11 -0000
@@ -174,6 +174,8 @@
   assert(p->member.run.nCharOfs != -1);
   ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
 
+  if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
+    editor->bCaretAtEnd = FALSE;
   for (i=0; i<editor->nCursors; i++) {
     if (editor->pCursors[i].pRun == pNext) {
       editor->pCursors[i].pRun = p;
Index: string.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/string.c,v
retrieving revision 1.2
diff -u -r1.2 string.c
--- string.c	17 Mar 2005 10:23:40 -0000	1.2
+++ string.c	18 Mar 2005 21:40:12 -0000
@@ -123,7 +123,6 @@
 
 int ME_IsSplitable(ME_String *s)
 {
-  /* FIXME multibyte */
   WCHAR *pos = s->szData;
   WCHAR ch;
   while(ME_IsWSpace(*pos++))
@@ -131,7 +130,7 @@
   pos--;
   while((ch = *pos++) != 0)
   {
-    if (ME_IsWSpace(*pos++))
+    if (ME_IsWSpace(ch))
       return 1;
   }
   return 0;
@@ -255,7 +254,7 @@
 
 int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
   int i;
-  for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
+  for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++)
     ;
     
   return i;
@@ -264,7 +263,7 @@
 /* note: returns offset of the first trailing whitespace */
 int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
   int i;
-  for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
+  for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--)
     ;
     
   return i;
@@ -273,7 +272,7 @@
 /* note: returns offset of the first trailing nonwhitespace */
 int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
   int i;
-  for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
+  for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--)
     ;
     
   return i;
Index: wrap.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/wrap.c,v
retrieving revision 1.5
diff -u -r1.5 wrap.c
--- wrap.c	17 Mar 2005 10:23:40 -0000	1.5
+++ wrap.c	18 Mar 2005 21:40:12 -0000
@@ -409,11 +409,12 @@
   }
 }
 
-void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
+BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
   HWND hWnd = editor->hWnd;
   HDC hDC = GetDC(hWnd);
   ME_DisplayItem *item;
   ME_Context c;
+  BOOL bModified = FALSE;
   
   ME_InitContext(&c, editor, hDC);
   c.pt.x = 0;
@@ -433,6 +434,8 @@
     if (bRedraw)
       item->member.para.nFlags |= MEPF_REPAINT;
 
+    bModified = bModified | bRedraw;
+
     c.pt.y += item->member.para.nHeight;
     item = item->member.para.next_para;
   }
@@ -442,4 +445,5 @@
   
   ME_DestroyContext(&c);
   ReleaseDC(hWnd, hDC);
+  return bModified;
 }


More information about the wine-patches mailing list