[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