[PATCH 15/45] [WinHelp]: implemented basic link support

Eric Pouech eric.pouech at orange.fr
Sun Mar 23 04:18:44 CDT 2008


this is done by storing on winhelp side a list of known links which refer to char pos in richedit

A+
---

 programs/winhelp/hlpfile.c |   53 ++++++++++++++
 programs/winhelp/hlpfile.h |   12 +++
 programs/winhelp/winhelp.c |  162 ++++++++++++++++++++++++++++++++++++++++++++
 programs/winhelp/winhelp.h |    2 +
 4 files changed, 227 insertions(+), 2 deletions(-)


diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
index 49eaba4..986448b 100644
--- a/programs/winhelp/hlpfile.c
+++ b/programs/winhelp/hlpfile.c
@@ -877,6 +877,37 @@ static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsign
     return TRUE;
 }
 
+static HLPFILE_LINK*    alloc_link(struct RtfData* rd, int cookie,
+                                   const char* string, unsigned long hash,
+                                   int window)
+{
+    HLPFILE_LINK*       link;
+    char*               where;
+
+    /* FIXME: should build a string table for the lpszPath,
+     * they are reallocated for each link
+     */
+    link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + strlen(string) + 1);
+    if (!link) return NULL;
+
+    link->cookie     = cookie;
+    link->string     = where = (char*)(link + 1);
+    strcpy(where, string);
+    link->hash       = hash;
+    link->window     = window;
+    link->next       = rd->first_link;
+    rd->first_link   = link;
+    link->cpMin      = rd->char_pos;
+    link->cpMax      = 0;
+
+    if (rd->current_link) WINE_FIXME("Pending link\n");
+    rd->current_link = link;
+
+    WINE_TRACE("Link[%d] to %s@%08x:%d\n",
+               link->cookie, link->string, link->hash, link->window);
+    return link;
+}
+
 /***********************************************************************
  *
  *           HLPFILE_BrowseParagraph
@@ -976,7 +1007,12 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
             textsize = strlen(text);
             if (textsize)
             {
-                if (rd->force_color && !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1 ")) goto done;
+                if (rd->force_color)
+                {
+                    if ((rd->current_link->cookie == hlp_link_popup) ?
+                        !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") :
+                        !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done;
+                }
                 if (!HLPFILE_RtfAddText(rd, text)) goto done;
                 if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done;
                 rd->char_pos += textsize;
@@ -1094,6 +1130,12 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
                 break;
 
 	    case 0x89:
+                if (!rd->current_link)
+                    WINE_FIXME("No existing link\n");
+                else
+                rd->current_link->cpMax = rd->char_pos;
+                rd->current_link = NULL;
+                rd->force_color = FALSE;
                 format += 1;
                 break;
 
@@ -1117,6 +1159,7 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
 
             case 0xE0:
             case 0xE1:
+                WINE_FIXME("got two\n");
                 WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));
                 format += 5;
                 break;
@@ -1125,6 +1168,9 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
 	    case 0xE3:
             case 0xE6:
             case 0xE7:
+                alloc_link(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
+                           hlpfile->lpszPath, GET_UINT(format, 1), -1);
+                rd->force_color = !(*format & 4);
                 format += 5;
                 break;
 
@@ -1135,8 +1181,8 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
                 {
                     char*       ptr = (char*) format + 8;
                     BYTE        type = format[3];
-                    int         wnd = -1;
                     char*       str;
+                    int         wnd = -1;
 
                     if (type == 1) wnd = *ptr++;
                     if (type == 4 || type == 6)
@@ -1155,6 +1201,8 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BY
                         if (wnd == -1)
                             WINE_WARN("Couldn't find window info for %s\n", ptr);
                     }
+                    alloc_link(rd, hlp_link_link, str, GET_UINT(format, 4), wnd);
+                    rd->force_color = !(*format & 4);
                 }
                 format += 3 + GET_USHORT(format, 1);
                 break;
@@ -1182,6 +1230,7 @@ BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd)
     rd->in_text = TRUE;
     rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768);
     rd->char_pos = 0;
+    rd->first_link = rd->current_link = NULL;
     rd->force_color = FALSE;
 
     if (!HLPFILE_RtfAddControl(rd, "{\\rtf1\\ansi\\ansicpg1252\\deff0")) return FALSE;
diff --git a/programs/winhelp/hlpfile.h b/programs/winhelp/hlpfile.h
index b50664b..0d2d0fc 100644
--- a/programs/winhelp/hlpfile.h
+++ b/programs/winhelp/hlpfile.h
@@ -70,6 +70,16 @@ typedef struct
     COLORREF                    color;
 } HLPFILE_FONT;
 
+typedef struct tagPageLink {
+    enum {hlp_link_link, hlp_link_popup, hlp_link_macro} cookie;
+    LPCSTR              string;         /* name of the file to for the link (NULL if same file) */
+    LONG                hash;           /* topic index */
+    unsigned            window;         /* window number for displaying the link (-1 is current) */
+    DWORD               cpMin;
+    DWORD               cpMax;
+    struct tagPageLink *next;
+} HLPFILE_LINK;
+
 typedef struct tagHlpFileFile
 {
     BYTE*                       file_buffer;
@@ -157,6 +167,8 @@ struct RtfData {
     unsigned    allocated;      /* overall allocated size */
     unsigned    char_pos;       /* current char position (in richedit) */
     char*       where;          /* pointer to feed back richedit */
+    HLPFILE_LINK*first_link;
+    HLPFILE_LINK*current_link;
     BOOL        force_color;
 };
 
diff --git a/programs/winhelp/winhelp.c b/programs/winhelp/winhelp.c
index b1c3b28..055564d 100644
--- a/programs/winhelp/winhelp.c
+++ b/programs/winhelp/winhelp.c
@@ -49,6 +49,7 @@ static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND, UINT, WPARAM, LPARAM);
 static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND, UINT, WPARAM, LPARAM);
 static void    WINHELP_CheckPopup(UINT);
 static void    WINHELP_DeleteWindow(WINHELP_WINDOW*);
+static void    WINHELP_DeletePageLinks(WINHELP_WINDOW* win);
 static void    WINHELP_FillRichEdit(HWND hText, WINHELP_WINDOW *win);
 
 WINHELP_GLOBALS Globals = {3, NULL, NULL, TRUE, NULL, NULL, NULL, NULL};
@@ -187,6 +188,39 @@ HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
     return &mwi;
 }
 
+/******************************************************************
+ *		HLPFILE_GetPopupWindowInfo
+ *
+ *
+ */
+static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
+                                                          HWND hParentWnd,
+                                                          LPARAM mouse)
+{
+    static      HLPFILE_WINDOWINFO      wi;
+    RECT parent_rect;
+
+    wi.type[0] = wi.name[0] = wi.caption[0] = '\0';
+
+    /* Calculate horizontal size and position of a popup window */
+    GetWindowRect(hParentWnd, &parent_rect);
+    wi.size.cx = (parent_rect.right  - parent_rect.left) / 2;
+    wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */
+
+    wi.origin.x = (short)LOWORD(mouse);
+    wi.origin.y = (short)HIWORD(mouse);
+    ClientToScreen(hParentWnd, &wi.origin);
+    wi.origin.x -= wi.size.cx / 2;
+    wi.origin.x  = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);
+    wi.origin.x  = max(wi.origin.x, 0);
+
+    wi.style = SW_SHOW;
+    wi.win_style = WS_POPUP | WS_BORDER;
+    wi.sr_color = wi.sr_color = 0xFFFFFF;
+
+    return &wi;
+}
+
 /***********************************************************************
  *
  *           WinMain
@@ -454,6 +488,9 @@ static BOOL     WINHELP_ReuseWindow(WINHELP_WINDOW* win, WINHELP_WINDOW* oldwin,
     win->hHistoryWnd   = oldwin->hHistoryWnd;
     oldwin->hMainWnd   = oldwin->hHistoryWnd = 0;
 
+    WINHELP_DeletePageLinks(oldwin);
+    win->page_links = oldwin->page_links = NULL;
+
     SetWindowLong(win->hMainWnd,      0, (LONG)win);
     SetWindowLong(win->hHistoryWnd,   0, (LONG)win);
 
@@ -558,6 +595,7 @@ BOOL WINHELP_CreateHelpWindow(HLPFILE_PAGE* page, HLPFILE_WINDOWINFO* wi,
     win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
 
     win->info = wi;
+    win->page_links = NULL;
 
     Globals.active_win = win;
 
@@ -683,6 +721,104 @@ BOOL WINHELP_CreateHelpWindowByOffset(HLPFILE* hlpfile, LONG lOffset,
 
 /***********************************************************************
  *
+ *           WINHELP_FindLink
+ */
+static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)
+{
+    HLPFILE_LINK*           link;
+    POINTL                  mouse_ptl, char_ptl, char_next_ptl;
+    DWORD                   cp;
+
+    mouse_ptl.x = (short)LOWORD(pos);
+    mouse_ptl.y = (short)HIWORD(pos);
+    cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,
+                      0, (LPARAM)&mouse_ptl);
+
+    for (link = win->page_links; link; link = link->next)
+    {
+        if (link->cpMin <= cp && cp <= link->cpMax)
+        {
+            /* check whether we're at end of line */
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_ptl, cp);
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_next_ptl, cp + 1);
+            if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
+                link = NULL;
+            break;
+        }
+    }
+    return link;
+}
+
+/******************************************************************
+ *		WINHELP_HandleTextMouse
+ *
+ */
+static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, const MSGFILTER* msgf)
+{
+    HLPFILE*                hlpfile;
+    HLPFILE_LINK*           link;
+    BOOL                    ret = FALSE;
+
+    switch (msgf->msg)
+    {
+    case WM_MOUSEMOVE:
+        if (WINHELP_FindLink(win, msgf->lParam))
+            SetCursor(win->hHandCur);
+        else
+            SetCursor(LoadCursor(0, IDC_ARROW));
+        break;
+
+     case WM_LBUTTONDOWN:
+         if ((win->current_link = WINHELP_FindLink(win, msgf->lParam)))
+             ret = TRUE;
+         break;
+
+    case WM_LBUTTONUP:
+        if ((link = WINHELP_FindLink(win, msgf->lParam)) && link == win->current_link)
+        {
+            HLPFILE_WINDOWINFO*     wi;
+
+            switch (link->cookie)
+            {
+            case hlp_link_link:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                {
+                    if (link->window == -1)
+                        wi = win->info;
+                    else if ((link->window >= 0) && (link->window < hlpfile->numWindows))
+                        wi = &hlpfile->windows[link->window];
+                    else
+                    {
+                        WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);
+                        break;
+                    }
+                    WINHELP_CreateHelpWindowByHash(hlpfile, link->hash, wi, SW_NORMAL);
+                }
+                break;
+            case hlp_link_popup:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                    WINHELP_CreateHelpWindowByHash(hlpfile, link->hash,
+                                                   WINHELP_GetPopupWindowInfo(hlpfile, win->hMainWnd, msgf->lParam),
+                                                   SW_NORMAL);
+                break;
+            case hlp_link_macro:
+                MACRO_ExecuteMacro(link->string);
+                break;
+            default:
+                WINE_FIXME("Unknown link cookie %d\n", link->cookie);
+            }
+            ret = TRUE;
+        }
+        win->current_link = NULL;
+        break;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *
  *           WINHELP_MainWndProc
  */
 static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -750,6 +886,14 @@ static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
             return 0;
         }
         break;
+    case WM_NOTIFY:
+        if (wParam == CTL_ID_TEXT)
+        {
+            return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLong(hWnd, 0),
+                                           (const MSGFILTER*)lParam);
+        }
+        break;
+
     case WM_NCDESTROY:
     {
         BOOL bExit;
@@ -805,6 +949,7 @@ static void WINHELP_FillRichEdit(HWND hTextWnd, WINHELP_WINDOW *win)
             es.pfnCallback = WINHELP_RtfStreamIn;
 
             SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
+            win->page_links = rd.first_link;
         }
         /* FIXME: else leaking potentially the rd.first_link chain */
         HeapFree(GetProcessHeap(), 0, rd.data);
@@ -1018,6 +1163,22 @@ static void WINHELP_CheckPopup(UINT msg)
     }
 }
 
+/******************************************************************
+ *		WINHELP_DeletePageLinks
+ *
+ */
+static void WINHELP_DeletePageLinks(WINHELP_WINDOW* win)
+{
+    HLPFILE_LINK*       curr;
+    HLPFILE_LINK*       next;
+
+    for (curr = win->page_links; curr; curr = next)
+    {
+        next = curr->next;
+        HeapFree(GetProcessHeap(), 0, curr);
+    }
+}
+
 /***********************************************************************
  *
  *           WINHELP_DeleteWindow
@@ -1051,6 +1212,7 @@ static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
         bp = b->next;
         HeapFree(GetProcessHeap(), 0, b);
     }
+    WINHELP_DeletePageLinks(win);
 
     if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
     if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
diff --git a/programs/winhelp/winhelp.h b/programs/winhelp/winhelp.h
index 2c351c8..58c4df8 100644
--- a/programs/winhelp/winhelp.h
+++ b/programs/winhelp/winhelp.h
@@ -69,6 +69,8 @@ typedef struct tagWinHelp
     HCURSOR             hHandCur;
 
     HLPFILE_WINDOWINFO* info;
+    HLPFILE_LINK*       page_links;
+    HLPFILE_LINK*       current_link;
 
     /* FIXME: for now it's a fixed size */
     HLPFILE_PAGE*       history[40];





More information about the wine-patches mailing list