riched20: Initial word break procedure implementation

Phil Krylov phil at newstar.rinet.ru
Wed Jan 11 20:52:51 CST 2006


ChangeLog:

Implemented initial support for word break callback procedures in riched20.

---

 dlls/riched20/caret.c   |  101 +++++++++++++++++++++++++++++++++++++++++++++--
 dlls/riched20/editor.c  |   20 +++++++--
 dlls/riched20/editor.h  |    3 +
 dlls/riched20/editstr.h |    1 
 dlls/riched20/string.c  |   48 ++++++++++++++++++++++
 5 files changed, 161 insertions(+), 12 deletions(-)

f62baa4b4517f74426a08d477b6dc744f03cc4b7
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index a4232f6..74e17e0 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -2,6 +2,7 @@
  * RichEdit - Caret and selection functions.
  *
  * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2005 by Phil Krylov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -491,6 +492,90 @@ ME_MoveCursorChars(ME_TextEditor *editor
 }
 
 
+static BOOL
+ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
+{
+  ME_DisplayItem *pRun = cursor->pRun, *pOtherRun;
+  int nOffset = cursor->nOffset;
+  
+  if (nRelOfs == -1)
+  {
+    /* Backward movement */
+    while (TRUE)
+    {
+      nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
+                                     nOffset, WB_MOVEWORDLEFT);
+       if (nOffset)
+        break;
+      pOtherRun = ME_FindItemBack(pRun, diRunOrParagraph);
+      if (pOtherRun->type == diRun)
+      {
+        if (ME_CallWordBreakProc(editor, pOtherRun->member.run.strText,
+                                 pOtherRun->member.run.strText->nLen - 1,
+                                 WB_ISDELIMITER)
+            && !(pRun->member.run.nFlags & MERF_ENDPARA)
+            && !(cursor->pRun == pRun && cursor->nOffset == 0)
+            && !ME_CallWordBreakProc(editor, pRun->member.run.strText, 0,
+                                     WB_ISDELIMITER))
+          break;
+        pRun = pOtherRun;
+        nOffset = pOtherRun->member.run.strText->nLen;
+      }
+      else if (pOtherRun->type == diParagraph)
+      {
+        if (cursor->pRun == pRun && cursor->nOffset == 0)
+        {
+          /* Paragraph breaks are treated as separate words */
+          if (pOtherRun->member.para.prev_para->type == diTextStart)
+            return FALSE;
+          pRun = ME_FindItemBack(pOtherRun, diRunOrParagraph);
+        }
+        break;
+      }
+    }
+  }
+  else
+  {
+    /* Forward movement */
+    BOOL last_delim = FALSE;
+    
+    while (TRUE)
+    {
+      if (last_delim && !ME_CallWordBreakProc(editor, pRun->member.run.strText,
+                                              nOffset, WB_ISDELIMITER))
+        break;
+      nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
+                                     nOffset, WB_MOVEWORDRIGHT);
+      if (nOffset < pRun->member.run.strText->nLen)
+        break;
+      pOtherRun = ME_FindItemFwd(pRun, diRunOrParagraphOrEnd);
+      if (pOtherRun->type == diRun)
+      {
+        last_delim = ME_CallWordBreakProc(editor, pRun->member.run.strText,
+                                          nOffset - 1, WB_ISDELIMITER);
+        pRun = pOtherRun;
+        nOffset = 0;
+      }
+      else if (pOtherRun->type == diParagraph)
+      {
+        if (cursor->pRun == pRun)
+          pRun = ME_FindItemFwd(pOtherRun, diRun);
+        nOffset = 0;
+        break;
+      }
+      else /* diTextEnd */
+      {
+        if (cursor->pRun == pRun)
+          return FALSE;
+        nOffset = 0;
+        break;
+      }
+    }
+  }
+  cursor->pRun = pRun;
+  cursor->nOffset = nOffset;
+  return TRUE;
+}
 
 
 int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
@@ -1032,7 +1117,7 @@ void ME_SendSelChange(ME_TextEditor *edi
 
 
 BOOL
-ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend)
+ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
 {
   int nCursor = 0;
   ME_Cursor *p = &editor->pCursors[nCursor];
@@ -1046,11 +1131,17 @@ ME_ArrowKey(ME_TextEditor *editor, int n
   switch(nVKey) {
     case VK_LEFT:
       editor->bCaretAtEnd = 0;
-      success = ME_MoveCursorChars(editor, &tmp_curs, -1);
+      if (ctrl)
+        success = ME_MoveCursorWords(editor, &tmp_curs, -1);
+      else
+        success = ME_MoveCursorChars(editor, &tmp_curs, -1);
       break;
     case VK_RIGHT:
       editor->bCaretAtEnd = 0;
-      success = ME_MoveCursorChars(editor, &tmp_curs, +1);
+      if (ctrl)
+        success = ME_MoveCursorWords(editor, &tmp_curs, +1);
+      else
+        success = ME_MoveCursorChars(editor, &tmp_curs, +1);
       break;
     case VK_UP:
       ME_MoveCursorLines(editor, &tmp_curs, -1);
@@ -1065,7 +1156,7 @@ ME_ArrowKey(ME_TextEditor *editor, int n
       ME_ArrowPageDown(editor, &tmp_curs);
       break;
     case VK_HOME: {
-      if (GetKeyState(VK_CONTROL)<0)
+      if (ctrl)
         ME_ArrowCtrlHome(editor, &tmp_curs);
       else
         ME_ArrowHome(editor, &tmp_curs);
@@ -1073,7 +1164,7 @@ ME_ArrowKey(ME_TextEditor *editor, int n
       break;
     }
     case VK_END: 
-      if (GetKeyState(VK_CONTROL)<0)
+      if (ctrl)
         ME_ArrowCtrlEnd(editor, &tmp_curs);
       else
         ME_ArrowEnd(editor, &tmp_curs);
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 723b69b..98ffd9c 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -71,7 +71,7 @@
 ? + EM_GETTEXTRANGE (ANSI&Unicode)
   - EM_GETTYPOGRAPHYOPTIONS 3.0
   - EM_GETUNDONAME
-  - EM_GETWORDBREAKPROC
+  + EM_GETWORDBREAKPROC
   - EM_GETWORDBREAKPROCEX
   - EM_GETWORDWRAPMODE 1.0asian
   + EM_GETZOOM 3.0
@@ -117,7 +117,7 @@
   - EM_SETTEXTMODE 2.0
   - EM_SETTYPOGRAPHYOPTIONS 3.0
   - EM_SETUNDOLIMIT 2.0
-  - EM_SETWORDBREAKPROC
+  + EM_SETWORDBREAKPROC (used only for word movement at the moment)
   - EM_SETWORDBREAKPROCEX
   - EM_SETWORDWRAPMODE 1.0asian
   + EM_SETZOOM 3.0
@@ -815,7 +815,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD n
     case VK_END:
     case VK_PRIOR:
     case VK_NEXT:
-      ME_ArrowKey(editor, nKey, shift_is_down);
+      ME_ArrowKey(editor, nKey, shift_is_down, ctrl_is_down);
       return TRUE;
     case VK_BACK:
     case VK_DELETE:
@@ -824,7 +824,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD n
         return FALSE;
       if (ME_IsSelection(editor))
         ME_DeleteSelection(editor);
-      else if (nKey == VK_DELETE || ME_ArrowKey(editor, VK_LEFT, FALSE))
+      else if (nKey == VK_DELETE || ME_ArrowKey(editor, VK_LEFT, FALSE, FALSE))
         ME_DeleteTextAtCursor(editor, 1, 1);
       else
         return TRUE;
@@ -888,6 +888,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) 
   ed->nZoomNumerator = ed->nZoomDenominator = 0;
   ed->bRedraw = TRUE;
   ed->nInvalidOfs = -1;
+  ed->pfnWordBreak = NULL;
   GetClientRect(hWnd, &ed->rcFormat);
   for (i=0; i<HFONT_CACHE_SIZE; i++)
   {
@@ -1194,7 +1195,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 
   UNSUPPORTED_MSG(EM_GETTEXTMODE)
   UNSUPPORTED_MSG(EM_GETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_GETUNDONAME)
-  UNSUPPORTED_MSG(EM_GETWORDBREAKPROC)
   UNSUPPORTED_MSG(EM_GETWORDBREAKPROCEX)
   UNSUPPORTED_MSG(EM_HIDESELECTION)
   UNSUPPORTED_MSG(EM_LIMITTEXT) /* also known as EM_SETLIMITTEXT */
@@ -1216,7 +1216,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 
   UNSUPPORTED_MSG(EM_SETTEXTMODE)
   UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
-  UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
   UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
   UNSUPPORTED_MSG(EM_SHOWSCROLLBAR)
   UNSUPPORTED_MSG(WM_SETFONT)
@@ -2041,6 +2040,15 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 
     FIXME("EM_GETOLEINTERFACE %p: stub\n", ppvObj);
     return CreateIRichEditOle(ppvObj);
   }
+  case EM_GETWORDBREAKPROC:
+    return (LRESULT)editor->pfnWordBreak;
+  case EM_SETWORDBREAKPROC:
+  {
+    EDITWORDBREAKPROCW pfnOld = editor->pfnWordBreak;
+
+    editor->pfnWordBreak = (EDITWORDBREAKPROCW)lParam;
+    return (LRESULT)pfnOld;
+  }
   default:
   do_default:
     return DefWindowProcW(hWnd, msg, wParam, lParam);
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
index 5243552..3ead3c0 100644
--- a/dlls/riched20/editor.h
+++ b/dlls/riched20/editor.h
@@ -72,6 +72,7 @@ int ME_StrLen(ME_String *s);
 int ME_StrVLen(ME_String *s);
 int ME_FindNonWhitespaceV(ME_String *s, int nVChar);
 int ME_FindWhitespaceV(ME_String *s, int nVChar);
+int ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code);
 int ME_GetCharFwd(ME_String *s, int nPos); /* get char starting from start */
 int ME_GetCharBack(ME_String *s, int nPos); /* get char starting from \0  */
 int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars);
@@ -150,7 +151,7 @@ void ME_DeleteTextAtCursor(ME_TextEditor
 void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
                              const WCHAR *str, int len, ME_Style *style);
 void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt);
-BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend);
+BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend, BOOL ctrl);
 
 void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
 void ME_DestroyContext(ME_Context *c);
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index 86dcfdb..37af096 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -286,6 +286,7 @@ typedef struct tagME_TextEditor
   RECT rcFormat;
   BOOL bRedraw;
   int nInvalidOfs;
+  EDITWORDBREAKPROCW pfnWordBreak;
 } ME_TextEditor;
 
 typedef struct tagME_Context
diff --git a/dlls/riched20/string.c b/dlls/riched20/string.c
index 6d23e2f..ad385d4 100644
--- a/dlls/riched20/string.c
+++ b/dlls/riched20/string.c
@@ -271,6 +271,54 @@ int ME_ReverseFindWhitespaceV(ME_String 
   return i;
 }
 
+
+static int
+ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code)
+{
+  /* FIXME: Native also knows about punctuation */
+  TRACE("s==%s, start==%d, len==%d, code==%d\n",
+        debugstr_wn(s, len), start, len, code);
+  switch (code)
+  {
+    case WB_ISDELIMITER:
+      return ME_IsWSpace(s[start]);
+    case WB_LEFT:
+    case WB_MOVEWORDLEFT:
+      while (start && ME_IsWSpace(s[start - 1]))
+        start--;
+      while (start && !ME_IsWSpace(s[start - 1]))
+        start--;
+      return start;
+    case WB_RIGHT:
+    case WB_MOVEWORDRIGHT:
+      if (start && ME_IsWSpace(s[start - 1]))
+      {
+        while (start < len && ME_IsWSpace(s[start]))
+          start++;
+      }
+      else
+      {
+        while (start < len && !ME_IsWSpace(s[start]))
+          start++;
+        while (start < len && ME_IsWSpace(s[start]))
+          start++;
+      }
+      return start;
+  }
+  return 0;
+}
+
+
+int
+ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code)
+{
+  /* FIXME: ANSIfy the string when bEmulateVersion10 is TRUE */
+  if (!editor->pfnWordBreak)
+    return ME_WordBreakProc(str->szData, start, str->nLen, code);
+  else
+    return editor->pfnWordBreak(str->szData, start, str->nLen, code);
+}
+
 LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz)
 {
   if (IsWindowUnicode(hWnd))
-- 
1.0.GIT



More information about the wine-patches mailing list