4 * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
5 * 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * 2002 Eric Pouech <eric.pouech@wanadoo.fr>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "winhelp_res.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
35 static BOOL WINHELP_RegisterWinClasses(void);
36 static LRESULT CALLBACK WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);
37 static LRESULT CALLBACK WINHELP_TextWndProc(HWND, UINT, WPARAM, LPARAM);
38 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);
39 static void WINHELP_CheckPopup(UINT);
40 static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE);
41 static void WINHELP_InitFonts(HWND hWnd);
42 static void WINHELP_DeleteLines(WINHELP_WINDOW*);
43 static void WINHELP_DeleteWindow(WINHELP_WINDOW*);
44 static void WINHELP_SetupText(HWND hWnd);
45 static WINHELP_LINE_PART* WINHELP_IsOverLink(HWND hWnd, WPARAM wParam, LPARAM lParam);
47 WINHELP_GLOBALS Globals = {3, 0, 0, 0, 0, 0};
49 static BOOL MacroTest = FALSE;
51 /***********************************************************************
55 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
60 Globals.hInstance = hInstance;
63 while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
67 if (*cmdline++ == ' ') continue;
70 if (option) cmdline++;
71 while (*cmdline && *cmdline == ' ') cmdline++;
77 while (*cmdline && *cmdline != ' ') cmdline++;
78 if (*cmdline) *cmdline++ = '\0';
79 lHash = HLPFILE_Hash(topic_id);
84 Globals.wVersion = option - '0';
93 /* Create primary window */
94 WINHELP_RegisterWinClasses();
95 WINHELP_CreateHelpWindowByHash(cmdline, lHash, "main", FALSE, NULL, NULL, show);
98 while (GetMessage(&msg, 0, 0, 0))
100 TranslateMessage(&msg);
101 DispatchMessage(&msg);
106 /***********************************************************************
110 static BOOL WINHELP_RegisterWinClasses(void)
112 WNDCLASS class_main, class_button_box, class_text, class_shadow;
114 class_main.style = CS_HREDRAW | CS_VREDRAW;
115 class_main.lpfnWndProc = WINHELP_MainWndProc;
116 class_main.cbClsExtra = 0;
117 class_main.cbWndExtra = sizeof(LONG);
118 class_main.hInstance = Globals.hInstance;
119 class_main.hIcon = LoadIcon(0, IDI_APPLICATION);
120 class_main.hCursor = LoadCursor(0, IDC_ARROW);
121 class_main.hbrBackground = GetStockObject(WHITE_BRUSH);
122 class_main.lpszMenuName = 0;
123 class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
125 class_button_box = class_main;
126 class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
127 class_button_box.hbrBackground = GetStockObject(GRAY_BRUSH);
128 class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
130 class_text = class_main;
131 class_text.lpfnWndProc = WINHELP_TextWndProc;
132 class_text.lpszClassName = TEXT_WIN_CLASS_NAME;
134 class_shadow = class_main;
135 class_shadow.lpfnWndProc = DefWindowProc;
136 class_shadow.hbrBackground = GetStockObject(GRAY_BRUSH);
137 class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;
139 return (RegisterClass(&class_main) &&
140 RegisterClass(&class_button_box) &&
141 RegisterClass(&class_text) &&
142 RegisterClass(&class_shadow));
145 /***********************************************************************
147 * WINHELP_CreateHelpWindow
150 static BOOL WINHELP_CreateHelpWindow(HLPFILE_PAGE* page, LPCSTR lpszWindow,
151 BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
153 CHAR szCaption[MAX_STRING_LEN];
154 CHAR szContents[MAX_STRING_LEN];
155 CHAR szSearch[MAX_STRING_LEN];
156 CHAR szBack[MAX_STRING_LEN];
157 CHAR szHistory[MAX_STRING_LEN];
158 SIZE size = {CW_USEDEFAULT, 0/*CW_USEDEFAULT*/};
159 POINT origin = {240, 0};
161 WINHELP_WINDOW *win, *oldwin;
162 HLPFILE_MACRO *macro;
168 else if (!lpszWindow || !lpszWindow[0])
169 lpszWindow = Globals.active_win->lpszName;
170 bPrimary = lpszWindow && !lstrcmpi(lpszWindow, "main");
172 /* Calculate horizontal size and position of a popup window */
176 GetWindowRect(hParentWnd, &parent_rect);
177 size.cx = (parent_rect.right - parent_rect.left) / 2;
178 size.cy = 10; /* need a non null value, so that border are taken into account while computing */
181 ClientToScreen(hParentWnd, &origin);
182 origin.x -= size.cx / 2;
183 origin.x = min(origin.x, GetSystemMetrics(SM_CXSCREEN) - size.cx);
184 origin.x = max(origin.x, 0);
187 /* Initialize WINHELP_WINDOW struct */
188 win = HeapAlloc(GetProcessHeap(), 0,
189 sizeof(WINHELP_WINDOW) + (lpszWindow ? strlen(lpszWindow) + 1 : 0));
190 if (!win) return FALSE;
192 win->next = Globals.win_list;
193 Globals.win_list = win;
196 ptr = (char*)win + sizeof(WINHELP_WINDOW);
197 lstrcpy(ptr, (LPSTR) lpszWindow);
200 else win->lpszName = NULL;
203 win->first_button = 0;
206 win->hButtonBoxWnd = 0;
210 win->hArrowCur = LoadCursorA(0, IDC_ARROWA);
211 win->hHandCur = LoadCursorA(0, IDC_HANDA);
213 Globals.active_win = win;
215 /* Initialize default pushbuttons */
216 if (MacroTest && !bPopup)
217 MACRO_CreateButton("BTN_TEST", "&Test", "MacroTest");
218 if (bPrimary && page)
220 LoadString(Globals.hInstance, 0x126, szContents, sizeof(szContents));
221 LoadString(Globals.hInstance, 0x127, szSearch, sizeof(szSearch));
222 LoadString(Globals.hInstance, 0x128, szBack, sizeof(szBack));
223 LoadString(Globals.hInstance, 0x129, szHistory, sizeof(szHistory));
224 MACRO_CreateButton("BTN_CONTENTS", szContents, "Contents()");
225 MACRO_CreateButton("BTN_SEARCH", szSearch, "Search()");
226 MACRO_CreateButton("BTN_BACK", szBack, "Back()");
227 MACRO_CreateButton("BTN_HISTORY", szHistory, "History()");
230 /* Initialize file specific pushbuttons */
232 for (macro = page->file->first_macro; macro; macro = macro->next)
233 MACRO_ExecuteMacro(macro->lpszMacro);
235 /* Reuse existing window */
237 for (oldwin = win->next; oldwin; oldwin = oldwin->next)
238 if (oldwin->lpszName && !lstrcmpi(oldwin->lpszName, lpszWindow))
240 WINHELP_BUTTON *button;
242 win->hMainWnd = oldwin->hMainWnd;
243 win->hButtonBoxWnd = oldwin->hButtonBoxWnd;
244 win->hTextWnd = oldwin->hTextWnd;
245 oldwin->hMainWnd = oldwin->hButtonBoxWnd = oldwin->hTextWnd = 0;
247 SetWindowLong(win->hMainWnd, 0, (LONG) win);
248 SetWindowLong(win->hButtonBoxWnd, 0, (LONG) win);
249 SetWindowLong(win->hTextWnd, 0, (LONG) win);
251 WINHELP_InitFonts(win->hMainWnd);
254 SetWindowText(win->hMainWnd, page->file->lpszTitle);
257 WINHELP_SetupText(win->hTextWnd);
258 InvalidateRect(win->hTextWnd, NULL, TRUE);
259 SendMessage(win->hMainWnd, WM_USER, 0, 0);
260 UpdateWindow(win->hTextWnd);
263 for (button = oldwin->first_button; button; button = button->next)
264 DestroyWindow(button->hWnd);
266 WINHELP_DeleteWindow(oldwin);
270 /* Create main Window */
271 if (!page) LoadString(Globals.hInstance, 0x120, szCaption, sizeof(szCaption));
272 hWnd = CreateWindow(bPopup ? TEXT_WIN_CLASS_NAME : MAIN_WIN_CLASS_NAME,
273 page ? page->file->lpszTitle : szCaption,
274 bPopup ? WS_POPUPWINDOW | WS_BORDER : WS_OVERLAPPEDWINDOW,
275 origin.x, origin.y, size.cx, size.cy,
276 0, bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,
277 Globals.hInstance, win);
279 ShowWindow(hWnd, nCmdShow);
285 /***********************************************************************
287 * WINHELP_CreateHelpWindowByPage
289 BOOL WINHELP_CreateHelpWindowByPage(HLPFILE_PAGE* page, LPCSTR lpszWindow,
290 BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
292 if (page) page->file->wRefCount++;
293 return WINHELP_CreateHelpWindow(page, lpszWindow, bPopup, hParentWnd, mouse, nCmdShow);
296 /***********************************************************************
298 * WINHELP_CreateHelpWindowByHash
300 BOOL WINHELP_CreateHelpWindowByHash(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWindow,
301 BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
308 page = lHash ? HLPFILE_PageByHash(lpszFile, lHash) : HLPFILE_Contents(lpszFile);
310 /* Add Suffix `.hlp' */
311 if (!page && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp"))
313 CHAR szFile_hlp[MAX_PATHNAME_LEN];
315 lstrcpyn(szFile_hlp, lpszFile, sizeof(szFile_hlp) - 4);
316 szFile_hlp[sizeof(szFile_hlp) - 5] = '\0';
317 lstrcat(szFile_hlp, ".hlp");
319 page = lHash ? HLPFILE_PageByHash(szFile_hlp, lHash) : HLPFILE_Contents(szFile_hlp);
322 WINHELP_MessageBoxIDS_s(HLPFILE_ERROR_s, lpszFile, WHERROR, MB_OK);
323 if (Globals.win_list) return FALSE;
328 return WINHELP_CreateHelpWindowByPage(page, lpszWindow, bPopup, hParentWnd, mouse, nCmdShow);
331 /***********************************************************************
333 * WINHELP_MainWndProc
335 static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
338 WINHELP_BUTTON *button;
339 RECT rect, button_box_rect;
342 WINHELP_CheckPopup(msg);
347 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
348 SetWindowLong(hWnd, 0, (LONG) win);
349 win->hMainWnd = hWnd;
353 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
355 /* Create button box and text Window */
356 CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
357 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
359 CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
360 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
364 case WM_WINDOWPOSCHANGED:
365 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
366 GetClientRect(hWnd, &rect);
368 /* Update button box and text Window */
369 SetWindowPos(win->hButtonBoxWnd, HWND_TOP,
371 rect.right - rect.left,
372 rect.bottom - rect.top, 0);
374 GetWindowRect(win->hButtonBoxWnd, &button_box_rect);
375 text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
377 SetWindowPos(win->hTextWnd, HWND_TOP,
379 rect.right - rect.left,
380 rect.bottom - text_top, 0);
385 Globals.active_win = win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
389 case 0x101: MACRO_FileOpen(); break;
390 case 0x104: MACRO_Print(); break;
391 case 0x106: MACRO_PrinterSetup(); break;
392 case 0x108: MACRO_Exit(); break;
395 case 0x10A: MACRO_CopyDialog(); break;
396 case 0x10C: MACRO_Annotate(); break;
399 case 0x10E: MACRO_BookmarkDefine(); break;
402 case 0x110: MACRO_HelpOn(); break;
403 case 0x111: MACRO_HelpOnTop(); break;
406 case 0x113: MACRO_About(); break;
409 ShellAbout(hWnd, "WINE", "Help", 0);
414 for (button = win->first_button; button; button = button->next)
415 if (wParam == button->wParam) break;
417 MACRO_ExecuteMacro(button->lpszMacro);
419 WINHELP_MessageBoxIDS(0x124, 0x121, MB_OK);
424 if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd);
428 return DefWindowProc(hWnd, msg, wParam, lParam);
431 /***********************************************************************
433 * WINHELP_ButtonBoxWndProc
435 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
439 WINHELP_BUTTON *button;
443 WINHELP_CheckPopup(msg);
448 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
449 SetWindowLong(hWnd, 0, (LONG) win);
450 win->hButtonBoxWnd = hWnd;
453 case WM_WINDOWPOSCHANGING:
454 winpos = (WINDOWPOS*) lParam;
455 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
460 for (button = win->first_button; button; button = button->next)
465 button->hWnd = CreateWindow(STRING_BUTTON, (LPSTR) button->lpszName,
466 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
468 hWnd, (HMENU) button->wParam,
469 Globals.hInstance, 0);
470 hDc = GetDC(button->hWnd);
471 GetTextExtentPoint(hDc, button->lpszName,
472 lstrlen(button->lpszName), &textsize);
473 ReleaseDC(button->hWnd, hDc);
475 button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
476 button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
481 for (button = win->first_button; button; button = button->next)
483 SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
485 if (x + 2 * button_size.cx <= winpos->cx)
488 x = 0, y += button_size.cy;
490 winpos->cy = y + (x ? button_size.cy : 0);
494 SendMessage(GetParent(hWnd), msg, wParam, lParam);
498 return DefWindowProc(hWnd, msg, wParam, lParam);
501 /***********************************************************************
503 * WINHELP_TextWndProc
505 static LRESULT CALLBACK WINHELP_TextWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
509 WINHELP_LINE_PART *part;
518 if (msg != WM_LBUTTONDOWN)
519 WINHELP_CheckPopup(msg);
524 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
525 SetWindowLong(hWnd, 0, (LONG) win);
526 win->hTextWnd = hWnd;
527 if (!win->lpszName) Globals.hPopupWnd = win->hMainWnd = hWnd;
528 WINHELP_InitFonts(hWnd);
532 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
534 /* Calculate vertical size and position of a popup window */
538 RECT old_window_rect;
539 RECT old_client_rect;
540 SIZE old_window_size;
541 SIZE old_client_size;
542 SIZE new_client_size;
543 SIZE new_window_size;
545 GetWindowRect(hWnd, &old_window_rect);
546 origin.x = old_window_rect.left;
547 origin.y = old_window_rect.top;
548 old_window_size.cx = old_window_rect.right - old_window_rect.left;
549 old_window_size.cy = old_window_rect.bottom - old_window_rect.top;
551 GetClientRect(hWnd, &old_client_rect);
552 old_client_size.cx = old_client_rect.right - old_client_rect.left;
553 old_client_size.cy = old_client_rect.bottom - old_client_rect.top;
555 new_client_size = old_client_size;
556 WINHELP_SplitLines(hWnd, &new_client_size);
558 if (origin.y + POPUP_YDISTANCE + new_client_size.cy <= GetSystemMetrics(SM_CYSCREEN))
559 origin.y += POPUP_YDISTANCE;
561 origin.y -= POPUP_YDISTANCE + new_client_size.cy;
563 new_window_size.cx = old_window_size.cx - old_client_size.cx + new_client_size.cx;
564 new_window_size.cy = old_window_size.cy - old_client_size.cy + new_client_size.cy;
567 CreateWindow(SHADOW_WIN_CLASS_NAME, "", WS_POPUP,
568 origin.x + SHADOW_DX, origin.y + SHADOW_DY,
569 new_window_size.cx, new_window_size.cy,
570 0, 0, Globals.hInstance, 0);
572 SetWindowPos(hWnd, HWND_TOP, origin.x, origin.y,
573 new_window_size.cx, new_window_size.cy,
575 SetWindowPos(win->hShadowWnd, hWnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
576 ShowWindow(win->hShadowWnd, SW_NORMAL);
577 SetActiveWindow(hWnd);
581 case WM_WINDOWPOSCHANGED:
582 winpos = (WINDOWPOS*) lParam;
584 if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd);
592 INT CurPos = GetScrollPos(hWnd, SB_VERT);
593 GetScrollRange(hWnd, SB_VERT, &Min, &Max);
594 GetClientRect(hWnd, &rect);
596 switch (wParam & 0xffff)
599 case SB_THUMBPOSITION: CurPos = wParam >> 16; break;
600 case SB_TOP: CurPos = Min; break;
601 case SB_BOTTOM: CurPos = Max; break;
602 case SB_PAGEUP: CurPos -= (rect.bottom - rect.top) / 2; break;
603 case SB_PAGEDOWN: CurPos += (rect.bottom - rect.top) / 2; break;
604 case SB_LINEUP: CurPos -= GetSystemMetrics(SM_CXVSCROLL); break;
605 case SB_LINEDOWN: CurPos += GetSystemMetrics(SM_CXVSCROLL); break;
606 default: update = FALSE;
610 INT dy = GetScrollPos(hWnd, SB_VERT) - CurPos;
611 SetScrollPos(hWnd, SB_VERT, CurPos, TRUE);
612 ScrollWindow(hWnd, 0, dy, NULL, NULL);
619 hDc = BeginPaint(hWnd, &ps);
620 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
621 scroll_pos = GetScrollPos(hWnd, SB_VERT);
623 for (line = win->first_line; line; line = line->next)
625 for (part = &line->first_part; part; part = part->next)
627 switch (part->cookie)
629 case hlp_line_part_text:
630 SelectObject(hDc, part->u.text.hFont);
631 SetTextColor(hDc, part->u.text.color);
632 TextOut(hDc, part->rect.left, part->rect.top - scroll_pos,
633 part->u.text.lpsText, part->u.text.wTextLen);
634 if (part->u.text.wUnderline)
638 switch (part->u.text.wUnderline)
642 hPen = CreatePen(PS_SOLID, 1, part->u.text.color);
645 hPen = CreatePen(PS_DOT, 1, part->u.text.color);
648 WINE_FIXME("Unknow underline type\n");
652 SelectObject(hDc, hPen);
653 MoveToEx(hDc, part->rect.left, part->rect.bottom - scroll_pos - 1, NULL);
654 LineTo(hDc, part->rect.right, part->rect.bottom - scroll_pos - 1);
655 if (part->u.text.wUnderline == 2)
657 MoveToEx(hDc, part->rect.left, part->rect.bottom - scroll_pos + 1, NULL);
658 LineTo(hDc, part->rect.right, part->rect.bottom - scroll_pos + 1);
663 case hlp_line_part_image:
667 hMemDC = CreateCompatibleDC(hDc);
668 SelectObject(hMemDC, part->u.image.hBitmap);
669 BitBlt(hDc, part->rect.left, part->rect.top - scroll_pos,
670 part->rect.right - part->rect.left, part->rect.bottom - part->rect.top,
671 hMemDC, 0, 0, SRCCOPY);
683 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
685 if (WINHELP_IsOverLink(hWnd, wParam, lParam))
686 SetCursor(win->hHandCur); /* set to hand pointer cursor to indicate a link */
688 SetCursor(win->hArrowCur); /* set to hand pointer cursor to indicate a link */
693 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
695 hPopupWnd = Globals.hPopupWnd;
696 Globals.hPopupWnd = 0;
698 part = WINHELP_IsOverLink(hWnd, wParam, lParam);
701 mouse.x = LOWORD(lParam);
702 mouse.y = HIWORD(lParam);
704 WINHELP_CreateHelpWindowByHash(part->link.lpszPath, part->link.lHash, NULL,
705 part->link.bPopup, hWnd, &mouse, SW_NORMAL);
709 DestroyWindow(hPopupWnd);
713 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
715 if (hWnd == Globals.hPopupWnd) Globals.hPopupWnd = 0;
716 if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
718 bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));
720 WINHELP_DeleteWindow(win);
722 if (bExit) MACRO_Exit();
724 if (!Globals.win_list)
729 return DefWindowProc(hWnd, msg, wParam, lParam);
732 /***********************************************************************
736 static void WINHELP_SetupText(HWND hWnd)
738 HDC hDc = GetDC(hWnd);
742 ShowScrollBar(hWnd, SB_VERT, FALSE);
743 if (!WINHELP_SplitLines(hWnd, NULL))
745 ShowScrollBar(hWnd, SB_VERT, TRUE);
746 GetClientRect(hWnd, &rect);
748 WINHELP_SplitLines(hWnd, &newsize);
749 SetScrollRange(hWnd, SB_VERT, 0, rect.top + newsize.cy - rect.bottom, TRUE);
751 else SetScrollPos(hWnd, SB_VERT, 0, FALSE);
753 ReleaseDC(hWnd, hDc);
756 /***********************************************************************
760 static BOOL WINHELP_AppendText(WINHELP_LINE ***linep, WINHELP_LINE_PART ***partp,
761 LPSIZE space, LPSIZE textsize,
762 INT *line_ascent, INT ascent,
763 LPCSTR text, UINT textlen,
764 HFONT font, COLORREF color, HLPFILE_LINK *link,
768 WINHELP_LINE_PART *part;
771 if (!*partp) /* New line */
773 *line_ascent = ascent;
775 line = HeapAlloc(GetProcessHeap(), 0,
776 sizeof(WINHELP_LINE) + textlen + (link ? lstrlen(link->lpszPath) + 1 : 0));
777 if (!line) return FALSE;
780 part = &line->first_part;
781 ptr = (char*)line + sizeof(WINHELP_LINE);
783 line->rect.top = (**linep ? (**linep)->rect.bottom : 0) + space->cy;
784 line->rect.bottom = line->rect.top;
785 line->rect.left = space->cx;
786 line->rect.right = space->cx;
788 if (**linep) *linep = &(**linep)->next;
796 if (*line_ascent < ascent)
798 WINHELP_LINE_PART *p;
799 for (p = &line->first_part; p; p = p->next)
801 p->rect.top += ascent - *line_ascent;
802 p->rect.bottom += ascent - *line_ascent;
804 line->rect.bottom += ascent - *line_ascent;
805 *line_ascent = ascent;
808 part = HeapAlloc(GetProcessHeap(), 0,
809 sizeof(WINHELP_LINE_PART) + textlen +
810 (link ? lstrlen(link->lpszPath) + 1 : 0));
811 if (!part) return FALSE;
813 ptr = (char*)part + sizeof(WINHELP_LINE_PART);
816 memcpy(ptr, text, textlen);
817 part->cookie = hlp_line_part_text;
818 part->rect.left = line->rect.right + (*partp ? space->cx : 0);
819 part->rect.right = part->rect.left + textsize->cx;
820 line->rect.right = part->rect.right;
822 ((*partp) ? line->rect.top : line->rect.bottom) + *line_ascent - ascent;
823 part->rect.bottom = part->rect.top + textsize->cy;
824 line->rect.bottom = max(line->rect.bottom, part->rect.bottom);
825 part->u.text.lpsText = ptr;
826 part->u.text.wTextLen = textlen;
827 part->u.text.hFont = font;
828 part->u.text.color = color;
829 part->u.text.wUnderline = underline;
831 WINE_TRACE("Appended text '%*.*s'[%d] @ (%d,%d-%d,%d)\n",
832 part->u.text.wTextLen,
833 part->u.text.wTextLen,
834 part->u.text.lpsText,
835 part->u.text.wTextLen,
836 part->rect.left, part->rect.top, part->rect.right, part->rect.bottom);
839 strcpy(ptr + textlen, link->lpszPath);
840 part->link.lpszPath = ptr + textlen;
841 part->link.lHash = link->lHash;
842 part->link.bPopup = link->bPopup;
844 else part->link.lpszPath = 0;
847 *partp = &part->next;
854 /***********************************************************************
856 * WINHELP_AppendBitmap
858 static BOOL WINHELP_AppendBitmap(WINHELP_LINE ***linep, WINHELP_LINE_PART ***partp,
860 HBITMAP hBmp, LPSIZE bmpSize,
861 HLPFILE_LINK *link, unsigned pos)
864 WINHELP_LINE_PART *part;
867 if (!*partp || pos == 1) /* New line */
869 line = HeapAlloc(GetProcessHeap(), 0,
870 sizeof(WINHELP_LINE) + (link ? lstrlen(link->lpszPath) + 1 : 0));
871 if (!line) return FALSE;
874 part = &line->first_part;
876 line->rect.top = (**linep ? (**linep)->rect.bottom : 0) + space->cy;
877 line->rect.bottom = line->rect.top;
878 line->rect.left = space->cx;
879 line->rect.right = space->cx;
881 if (**linep) *linep = &(**linep)->next;
884 ptr = (char*)line + sizeof(WINHELP_LINE);
888 if (pos == 2) WINE_FIXME("Left alignment not handled\n");
891 part = HeapAlloc(GetProcessHeap(), 0,
892 sizeof(WINHELP_LINE_PART) +
893 (link ? lstrlen(link->lpszPath) + 1 : 0));
894 if (!part) return FALSE;
896 ptr = (char*)part + sizeof(WINHELP_LINE_PART);
899 part->cookie = hlp_line_part_image;
900 part->rect.left = line->rect.right + (*partp ? space->cx : 0);
901 part->rect.right = part->rect.left + bmpSize->cx;
902 line->rect.right = part->rect.right;
904 ((*partp) ? line->rect.top : line->rect.bottom);
905 part->rect.bottom = part->rect.top + bmpSize->cy;
906 line->rect.bottom = max(line->rect.bottom, part->rect.bottom);
907 part->u.image.hBitmap = hBmp;
909 WINE_TRACE("Appended bitmap '%d' @ (%d,%d-%d,%d)\n",
910 (unsigned)part->u.image.hBitmap,
911 part->rect.left, part->rect.top, part->rect.right, part->rect.bottom);
915 strcpy(ptr, link->lpszPath);
916 part->link.lpszPath = ptr;
917 part->link.lHash = link->lHash;
918 part->link.bPopup = link->bPopup;
920 else part->link.lpszPath = 0;
923 *partp = &part->next;
931 /***********************************************************************
935 static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE newsize)
937 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
938 HLPFILE_PARAGRAPH *p;
939 WINHELP_LINE **line = &win->first_line;
940 WINHELP_LINE_PART **part = 0;
946 if (newsize) newsize->cx = newsize->cy = 0;
948 if (!win->page) return TRUE;
950 WINHELP_DeleteLines(win);
952 GetClientRect(hWnd, &rect);
954 rect.top += INTERNAL_BORDER_WIDTH;
955 rect.left += INTERNAL_BORDER_WIDTH;
956 rect.right -= INTERNAL_BORDER_WIDTH;
957 rect.bottom -= INTERNAL_BORDER_WIDTH;
960 space.cx = rect.left;
964 for (p = win->page->first_paragraph; p; p = p->next)
968 case para_normal_text:
969 case para_debug_text:
972 SIZE textsize = {0, 0};
973 LPCSTR text = p->u.text.lpszText;
975 UINT len = strlen(text);
976 unsigned underline = 0;
979 COLORREF color = RGB(0, 0, 0);
981 if (p->u.text.wFont < win->page->file->numFonts)
983 HLPFILE* hlpfile = win->page->file;
985 if (!hlpfile->fonts[p->u.text.wFont].hFont)
986 hlpfile->fonts[p->u.text.wFont].hFont = CreateFontIndirect(&hlpfile->fonts[p->u.text.wFont].LogFont);
987 hFont = hlpfile->fonts[p->u.text.wFont].hFont;
988 color = hlpfile->fonts[p->u.text.wFont].color;
992 UINT wFont = (p->u.text.wFont < win->fonts_len) ? p->u.text.wFont : 0;
994 hFont = win->fonts[wFont];
999 underline = (p->link->bPopup) ? 3 : 1;
1000 color = RGB(0, 0x80, 0);
1002 if (p->cookie == para_debug_text) color = RGB(0xff, 0, 0);
1004 SelectObject(hDc, hFont);
1006 GetTextMetrics(hDc, &tm);
1008 if (p->u.text.wIndent)
1010 indent = p->u.text.wIndent * 5 * tm.tmAveCharWidth;
1012 space.cx = rect.left + indent - 2 * tm.tmAveCharWidth;
1015 if (p->u.text.wVSpace)
1018 space.cx = rect.left + indent;
1019 space.cy += (p->u.text.wVSpace - 1) * tm.tmHeight;
1022 if (p->u.text.wHSpace)
1024 space.cx += p->u.text.wHSpace * 2 * tm.tmAveCharWidth;
1027 WINE_TRACE("splitting text %s\n", text);
1031 INT free_width = rect.right - (part ? (*line)->rect.right : rect.left) - space.cx;
1032 UINT low = 0, curr = len, high = len, textlen = 0;
1038 GetTextExtentPoint(hDc, text, curr, &textsize);
1040 if (textsize.cx <= free_width) low = curr;
1043 if (high <= low + 1) break;
1045 if (textsize.cx) curr = (curr * free_width) / textsize.cx;
1046 if (curr <= low) curr = low + 1;
1047 else if (curr >= high) curr = high - 1;
1050 while (textlen && text[textlen] && text[textlen] != ' ') textlen--;
1052 if (!part && !textlen) textlen = max(low, 1);
1054 if (free_width <= 0 || !textlen)
1057 space.cx = rect.left + indent;
1058 space.cx = min(space.cx, rect.right - rect.left - 1);
1062 WINE_TRACE("\t => %d %*s\n", textlen, textlen, text);
1064 if (!WINHELP_AppendText(&line, &part, &space, &textsize,
1065 &line_ascent, tm.tmAscent,
1066 text, textlen, hFont, color, p->link, underline) ||
1067 (!newsize && (*line)->rect.bottom > rect.bottom))
1069 ReleaseDC(hWnd, hDc);
1074 newsize->cx = max(newsize->cx, (*line)->rect.right + INTERNAL_BORDER_WIDTH);
1078 if (text[0] == ' ') text++, len--;
1088 if (p->u.image.pos & 0x8000)
1090 space.cx = rect.left;
1091 space.cy += (*line)->rect.bottom - (*line)->rect.top;
1095 GetObject(p->u.image.hBitmap, sizeof(dibs), &dibs);
1096 bmpSize.cx = dibs.dsBm.bmWidth;
1097 bmpSize.cy = dibs.dsBm.bmHeight;
1099 free_width = rect.right - (part ? (*line)->rect.right : rect.left) - space.cx;
1100 if (free_width <= 0)
1103 space.cx = rect.left;
1104 space.cx = min(space.cx, rect.right - rect.left - 1);
1106 if (!WINHELP_AppendBitmap(&line, &part, &space,
1107 p->u.image.hBitmap, &bmpSize,
1108 p->link, p->u.image.pos) ||
1109 (!newsize && (*line)->rect.bottom > rect.bottom))
1120 newsize->cy = (*line)->rect.bottom + INTERNAL_BORDER_WIDTH;
1122 ReleaseDC(hWnd, hDc);
1126 /***********************************************************************
1128 * WINHELP_CheckPopup
1130 static void WINHELP_CheckPopup(UINT msg)
1132 if (!Globals.hPopupWnd) return;
1137 case WM_LBUTTONDOWN:
1138 case WM_MBUTTONDOWN:
1139 case WM_RBUTTONDOWN:
1140 case WM_NCLBUTTONDOWN:
1141 case WM_NCMBUTTONDOWN:
1142 case WM_NCRBUTTONDOWN:
1143 DestroyWindow(Globals.hPopupWnd);
1144 Globals.hPopupWnd = 0;
1148 /***********************************************************************
1150 * WINHELP_DeleteLines
1152 static void WINHELP_DeleteLines(WINHELP_WINDOW *win)
1154 WINHELP_LINE *line, *next_line;
1155 WINHELP_LINE_PART *part, *next_part;
1156 for(line = win->first_line; line; line = next_line)
1158 next_line = line->next;
1159 for (part = &line->first_part; part; part = next_part)
1161 next_part = part->next;
1162 HeapFree(GetProcessHeap(), 0, part);
1165 win->first_line = 0;
1168 /***********************************************************************
1170 * WINHELP_DeleteWindow
1172 static void WINHELP_DeleteWindow(WINHELP_WINDOW *win)
1176 for (w = &Globals.win_list; *w; w = &(*w)->next)
1183 if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
1184 HLPFILE_FreeHlpFilePage(win->page);
1185 WINHELP_DeleteLines(win);
1186 HeapFree(GetProcessHeap(), 0, win);
1189 /***********************************************************************
1193 static void WINHELP_InitFonts(HWND hWnd)
1195 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
1196 LOGFONT logfontlist[] = {
1197 {-10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1198 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1199 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1200 {-12, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1201 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1202 {-10, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
1203 { -8, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"}};
1204 #define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
1206 static HFONT fonts[FONTS_LEN];
1207 static BOOL init = 0;
1209 win->fonts_len = FONTS_LEN;
1216 for(i = 0; i < FONTS_LEN; i++)
1218 fonts[i] = CreateFontIndirect(&logfontlist[i]);
1225 /***********************************************************************
1227 * WINHELP_MessageBoxIDS
1229 INT WINHELP_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
1231 CHAR text[MAX_STRING_LEN];
1232 CHAR title[MAX_STRING_LEN];
1234 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1235 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1237 return MessageBox(0, text, title, type);
1240 /***********************************************************************
1242 * MAIN_MessageBoxIDS_s
1244 INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
1246 CHAR text[MAX_STRING_LEN];
1247 CHAR title[MAX_STRING_LEN];
1248 CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
1250 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1251 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1252 wsprintf(newtext, text, str);
1254 return MessageBox(0, newtext, title, type);
1257 /******************************************************************
1258 * WINHELP_IsOverLink
1262 WINHELP_LINE_PART* WINHELP_IsOverLink(HWND hWnd, WPARAM wParam, LPARAM lParam)
1264 WINHELP_WINDOW* win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
1267 WINHELP_LINE_PART *part;
1268 int scroll_pos = GetScrollPos(hWnd, SB_VERT);
1270 mouse.x = LOWORD(lParam);
1271 mouse.y = HIWORD(lParam);
1272 for (line = win->first_line; line; line = line->next)
1274 for (part = &line->first_part; part; part = part->next)
1276 if (part->link.lpszPath &&
1277 part->rect.left <= mouse.x &&
1278 part->rect.right >= mouse.x &&
1279 part->rect.top <= mouse.y + scroll_pos &&
1280 part->rect.bottom >= mouse.y + scroll_pos)