Fixed int/HANDLE mismatches revealed by -DSTRICT.
[wine/multimedia.git] / programs / winhelp / winhelp.c
blobccb2702a7174067dc4de19fc6edac7c5b1b32c25
1 /*
2 * Help Viewer
4 * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
5 */
7 #include <stdio.h>
8 #include <string.h>
9 #include "windows.h"
10 #include "windowsx.h"
11 #include "winhelp.h"
13 #ifdef WINELIB
14 #include "options.h"
15 #endif
17 static BOOL WINHELP_RegisterWinClasses();
18 static LRESULT CALLBACK WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);
19 static LRESULT CALLBACK WINHELP_TextWndProc(HWND, UINT, WPARAM, LPARAM);
20 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);
21 static VOID WINHELP_CheckPopup(UINT);
22 static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE);
23 static VOID WINHELP_InitFonts(HWND hWnd);
24 static VOID WINHELP_DeleteLines(WINHELP_WINDOW*);
25 static VOID WINHELP_DeleteWindow(WINHELP_WINDOW*);
26 static VOID WINHELP_SetupText(HWND hWnd);
27 static BOOL WINHELP_AppendText(WINHELP_LINE***, WINHELP_LINE_PART***,
28 LPSIZE, LPSIZE, INT*, INT, LPCSTR, UINT,
29 HFONT, COLORREF, HLPFILE_LINK*);
31 WINHELP_GLOBALS Globals = {3, 0, 0, 0, 0, 0};
33 static BOOL MacroTest = FALSE;
35 /***********************************************************************
37 * WinMain
40 int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
42 LPCSTR opt_lang = "En";
43 CHAR lang[3];
44 MSG msg;
45 LONG lHash = 0;
46 INT langnum;
48 Globals.hInstance = hInstance;
50 /* Get options */
51 while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
53 CHAR option;
54 LPCSTR topic_id;
55 if (*cmdline++ == ' ') continue;
57 option = *cmdline;
58 if (option) cmdline++;
59 while (*cmdline && *cmdline == ' ') cmdline++;
60 switch(option)
62 case 'i':
63 case 'I':
64 topic_id = cmdline;
65 while (*cmdline && *cmdline != ' ') cmdline++;
66 if (*cmdline) *cmdline++ = '\0';
67 lHash = HLPFILE_Hash(topic_id);
68 break;
70 case '3':
71 case '4':
72 Globals.wVersion = option - '0';
73 break;
75 case 't':
76 MacroTest = TRUE;
77 break;
81 /* Find language specific string table */
82 for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
84 Globals.wStringTableOffset = langnum * 0x100;
85 if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)) &&
86 !lstrcmp(opt_lang, lang))
87 break;
89 if (langnum > MAX_LANGUAGE_NUMBER)
91 /* Find fallback language */
92 for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
94 Globals.wStringTableOffset = langnum * 0x100;
95 if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)))
96 break;
98 if (langnum > MAX_LANGUAGE_NUMBER)
100 MessageBox(0, "No language found", "FATAL ERROR", MB_OK);
101 return(1);
105 /* Change Resource names */
106 lstrcpyn(STRING_MENU_Xx + lstrlen(STRING_MENU_Xx) - 2, lang, 3);
108 /* Create primary window */
109 WINHELP_RegisterWinClasses();
110 WINHELP_CreateHelpWindow(cmdline, lHash, "main", FALSE, NULL, NULL, show);
112 /* Message loop */
113 while (GetMessage (&msg, 0, 0, 0))
115 TranslateMessage (&msg);
116 DispatchMessage (&msg);
118 return 0;
121 /***********************************************************************
123 * RegisterWinClasses
126 static BOOL WINHELP_RegisterWinClasses()
128 WNDCLASS class_main, class_button_box, class_text, class_shadow;
130 class_main.style = CS_HREDRAW | CS_VREDRAW;
131 class_main.lpfnWndProc = WINHELP_MainWndProc;
132 class_main.cbClsExtra = 0;
133 class_main.cbWndExtra = sizeof(LONG);
134 class_main.hInstance = Globals.hInstance;
135 class_main.hIcon = LoadIcon (0, IDI_APPLICATION);
136 class_main.hCursor = LoadCursor (0, IDC_ARROW);
137 class_main.hbrBackground = GetStockObject (WHITE_BRUSH);
138 class_main.lpszMenuName = 0;
139 class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
141 class_button_box = class_main;
142 class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
143 class_button_box.hbrBackground = GetStockObject(GRAY_BRUSH);
144 class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
146 class_text = class_main;
147 class_text.lpfnWndProc = WINHELP_TextWndProc;
148 class_text.lpszClassName = TEXT_WIN_CLASS_NAME;
150 class_shadow = class_main;
151 class_shadow.lpfnWndProc = DefWindowProc;
152 class_shadow.hbrBackground = GetStockObject(GRAY_BRUSH);
153 class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;
155 return (RegisterClass(&class_main) &&
156 RegisterClass(&class_button_box) &&
157 RegisterClass(&class_text) &&
158 RegisterClass(&class_shadow));
161 /***********************************************************************
163 * WINHELP_CreateHelpWindow
166 VOID WINHELP_CreateHelpWindow(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWindow,
167 BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
169 CHAR szCaption[MAX_STRING_LEN];
170 CHAR szContents[MAX_STRING_LEN];
171 CHAR szSearch[MAX_STRING_LEN];
172 CHAR szBack[MAX_STRING_LEN];
173 CHAR szHistory[MAX_STRING_LEN];
174 SIZE size = {CW_USEDEFAULT, CW_USEDEFAULT};
175 POINT origin = {240, 0};
176 LPSTR ptr;
177 HGLOBAL handle;
178 WINHELP_WINDOW *win, *oldwin;
179 HLPFILE_PAGE *page;
180 HLPFILE_MACRO *macro;
181 HWND hWnd;
182 BOOL bPrimary;
184 if (bPopup)
185 lpszWindow = NULL;
186 else if (!lpszWindow || !lpszWindow[0])
187 lpszWindow = Globals.active_win->lpszName;
188 bPrimary = lpszWindow && !lstrcmpi(lpszWindow, "main");
190 /* Read help file */
191 if (lpszFile[0])
193 page = lHash ? HLPFILE_PageByHash(lpszFile, lHash) : HLPFILE_Contents(lpszFile);
195 /* Add Suffix `.hlp' */
196 if (!page && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp"))
198 CHAR szFile_hlp[MAX_PATHNAME_LEN];
200 lstrcpyn(szFile_hlp, lpszFile, sizeof(szFile_hlp) - 4);
201 szFile_hlp[sizeof(szFile_hlp) - 5] = '\0';
202 lstrcat(szFile_hlp, ".hlp");
204 page = lHash ? HLPFILE_PageByHash(szFile_hlp, lHash) : HLPFILE_Contents(szFile_hlp);
205 if (!page)
207 WINHELP_MessageBoxIDS_s(IDS_HLPFILE_ERROR_s, lpszFile, IDS_ERROR, MB_OK);
208 if (Globals.win_list) return;
212 else page = 0;
214 /* Calculate horizontal size and position of a popup window */
215 if (bPopup)
217 RECT parent_rect;
218 GetWindowRect(hParentWnd, &parent_rect);
219 size.cx = (parent_rect.right - parent_rect.left) / 2;
221 origin = *mouse;
222 ClientToScreen(hParentWnd, &origin);
223 origin.x -= size.cx / 2;
224 origin.x = min(origin.x, GetSystemMetrics(SM_CXSCREEN) - size.cx);
225 origin.x = max(origin.x, 0);
228 /* Initialize WINHELP_WINDOW struct */
229 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_WINDOW) +
230 (lpszWindow ? strlen(lpszWindow) + 1 : 0));
231 if (!handle) return;
232 win = GlobalLock(handle);
233 win->hSelf = handle;
234 win->next = Globals.win_list;
235 Globals.win_list = win;
236 if (lpszWindow)
238 ptr = GlobalLock(handle);
239 ptr += sizeof(WINHELP_WINDOW);
240 lstrcpy(ptr, (LPSTR) lpszWindow);
241 win->lpszName = ptr;
243 else win->lpszName = NULL;
244 win->page = page;
245 win->first_button = 0;
246 win->first_line = 0;
247 win->hMainWnd = 0;
248 win->hButtonBoxWnd = 0;
249 win->hTextWnd = 0;
250 win->hShadowWnd = 0;
252 Globals.active_win = win;
254 /* Initialize default pushbuttons */
255 if (MacroTest && !bPopup)
256 MACRO_CreateButton("BTN_TEST", "&Test", "MacroTest");
257 if (bPrimary && page)
259 LoadString(Globals.hInstance, IDS_CONTENTS, szContents, sizeof(szContents));
260 LoadString(Globals.hInstance, IDS_SEARCH, szSearch, sizeof(szSearch));
261 LoadString(Globals.hInstance, IDS_BACK, szBack, sizeof(szBack));
262 LoadString(Globals.hInstance, IDS_HISTORY, szHistory, sizeof(szHistory));
263 MACRO_CreateButton("BTN_CONTENTS", szContents, "Contents()");
264 MACRO_CreateButton("BTN_SEARCH", szSearch, "Search()");
265 MACRO_CreateButton("BTN_BACK", szBack, "Back()");
266 MACRO_CreateButton("BTN_HISTORY", szHistory, "History()");
269 /* Initialize file specific pushbuttons */
270 if (!bPopup && page)
271 for (macro = page->file->first_macro; macro; macro = macro->next)
272 MACRO_ExecuteMacro(macro->lpszMacro);
274 /* Reuse existing window */
275 if (lpszWindow)
276 for (oldwin = win->next; oldwin; oldwin = oldwin->next)
277 if (oldwin->lpszName && !lstrcmpi(oldwin->lpszName, lpszWindow))
279 WINHELP_BUTTON *button;
281 win->hMainWnd = oldwin->hMainWnd;
282 win->hButtonBoxWnd = oldwin->hButtonBoxWnd;
283 win->hTextWnd = oldwin->hTextWnd;
284 oldwin->hMainWnd = oldwin->hButtonBoxWnd = oldwin->hTextWnd = 0;
286 SetWindowLong(win->hMainWnd, 0, (LONG) win);
287 SetWindowLong(win->hButtonBoxWnd, 0, (LONG) win);
288 SetWindowLong(win->hTextWnd, 0, (LONG) win);
290 WINHELP_InitFonts(win->hMainWnd);
292 if (page) {
293 SetWindowText(win->hMainWnd, page->file->lpszTitle);
296 WINHELP_SetupText(win->hTextWnd);
297 InvalidateRect(win->hTextWnd, NULL, TRUE);
298 SendMessage(win->hMainWnd, WM_USER, 0, 0);
299 UpdateWindow(win->hTextWnd);
302 for (button = oldwin->first_button; button; button = button->next)
303 DestroyWindow(button->hWnd);
305 WINHELP_DeleteWindow(oldwin);
306 return;
309 /* Create main Window */
310 if (!page) LoadString(Globals.hInstance, IDS_WINE_HELP, szCaption, sizeof(szCaption));
311 hWnd = CreateWindow (bPopup ? TEXT_WIN_CLASS_NAME : MAIN_WIN_CLASS_NAME,
312 page ? page->file->lpszTitle : szCaption,
313 bPopup ? WS_POPUPWINDOW | WS_BORDER : WS_OVERLAPPEDWINDOW,
314 origin.x, origin.y, size.cx, size.cy,
315 0, bPrimary ? LoadMenu(Globals.hInstance, STRING_MENU_Xx) : 0,
316 Globals.hInstance, win);
318 ShowWindow (hWnd, nCmdShow);
319 UpdateWindow (hWnd);
322 /***********************************************************************
324 * WINHELP_MainWndProc
327 static LRESULT CALLBACK WINHELP_MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
329 WINHELP_WINDOW *win;
330 WINHELP_BUTTON *button;
331 RECT rect, button_box_rect;
332 INT text_top;
334 WINHELP_CheckPopup(msg);
336 switch (msg)
338 case WM_NCCREATE:
339 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
340 SetWindowLong(hWnd, 0, (LONG) win);
341 win->hMainWnd = hWnd;
342 break;
344 case WM_CREATE:
345 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
347 /* Create button box and text Window */
348 CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
349 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
351 CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
352 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
354 /* Fall through */
355 case WM_USER:
356 case WM_WINDOWPOSCHANGED:
357 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
358 GetClientRect(hWnd, &rect);
360 /* Update button box and text Window */
361 SetWindowPos(win->hButtonBoxWnd, HWND_TOP,
362 rect.left, rect.top,
363 rect.right - rect.left,
364 rect.bottom - rect.top, 0);
366 GetWindowRect(win->hButtonBoxWnd, &button_box_rect);
367 text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
369 SetWindowPos(win->hTextWnd, HWND_TOP,
370 rect.left, text_top,
371 rect.right - rect.left,
372 rect.bottom - text_top, 0);
374 break;
376 case WM_COMMAND:
377 Globals.active_win = win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
378 switch (wParam)
380 /* Menu FILE */
381 case WH_OPEN: MACRO_FileOpen(); break;
382 case WH_PRINT: MACRO_Print(); break;
383 case WH_PRINTER_SETUP: MACRO_PrinterSetup(); break;
384 case WH_EXIT: MACRO_Exit(); break;
386 /* Menu EDIT */
387 case WH_COPY_DIALOG: MACRO_CopyDialog(); break;
388 case WH_ANNOTATE: MACRO_Annotate(); break;
390 /* Menu Bookmark */
391 case WH_BOOKMARK_DEFINE: MACRO_BookmarkDefine(); break;
393 /* Menu Help */
394 case WH_HELP_ON_HELP: MACRO_HelpOn(); break;
395 case WH_HELP_ON_TOP: MACRO_HelpOnTop(); break;
397 /* Menu Info */
398 case WH_ABOUT: MACRO_About(); break;
400 case WH_ABOUT_WINE:
401 ShellAbout(hWnd, "WINE", "Help", 0);
402 break;
404 default:
405 /* Buttons */
406 for (button = win->first_button; button; button = button->next)
407 if (wParam == button->wParam) break;
408 if (button)
409 MACRO_ExecuteMacro(button->lpszMacro);
410 else
411 WINHELP_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
412 break;
414 break;
417 return DefWindowProc (hWnd, msg, wParam, lParam);
420 /***********************************************************************
422 * WINHELP_ButtonBoxWndProc
425 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
427 WINDOWPOS *winpos;
428 WINHELP_WINDOW *win;
429 WINHELP_BUTTON *button;
430 SIZE button_size;
431 INT x, y;
433 WINHELP_CheckPopup(msg);
435 switch(msg)
437 case WM_NCCREATE:
438 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
439 SetWindowLong(hWnd, 0, (LONG) win);
440 win->hButtonBoxWnd = hWnd;
441 break;
443 case WM_WINDOWPOSCHANGING:
444 winpos = (WINDOWPOS*) lParam;
445 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
447 /* Update buttons */
448 button_size.cx = 0;
449 button_size.cy = 0;
450 for (button = win->first_button; button; button = button->next)
452 HDC hDc;
453 SIZE textsize;
454 if (!button->hWnd)
455 button->hWnd = CreateWindow(STRING_BUTTON, (LPSTR) button->lpszName,
456 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
457 0, 0, 0, 0,
458 hWnd, (HMENU) button->wParam,
459 Globals.hInstance, 0);
460 hDc = GetDC(button->hWnd);
461 GetTextExtentPoint(hDc, button->lpszName,
462 lstrlen(button->lpszName), &textsize);
463 ReleaseDC(button->hWnd, hDc);
465 button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
466 button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
469 x = 0;
470 y = 0;
471 for (button = win->first_button; button; button = button->next)
473 SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
475 if (x + 2 * button_size.cx <= winpos->cx)
476 x += button_size.cx;
477 else
478 x = 0, y += button_size.cy;
480 winpos->cy = y + (x ? button_size.cy : 0);
481 break;
483 case WM_COMMAND:
484 SendMessage(GetParent(hWnd), msg, wParam, lParam);
485 break;
488 return(DefWindowProc(hWnd, msg, wParam, lParam));
491 /***********************************************************************
493 * WINHELP_TextWndProc
496 static LRESULT CALLBACK WINHELP_TextWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
498 WINHELP_WINDOW *win;
499 WINHELP_LINE *line;
500 WINHELP_LINE_PART *part;
501 WINDOWPOS *winpos;
502 PAINTSTRUCT ps;
503 HDC hDc;
504 POINT mouse;
505 INT scroll_pos;
506 HWND hPopupWnd;
507 BOOL bExit;
509 if (msg != WM_LBUTTONDOWN)
510 WINHELP_CheckPopup(msg);
512 switch (msg)
514 case WM_NCCREATE:
515 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
516 SetWindowLong(hWnd, 0, (LONG) win);
517 win->hTextWnd = hWnd;
518 if (!win->lpszName) Globals.hPopupWnd = win->hMainWnd = hWnd;
519 WINHELP_InitFonts(hWnd);
520 break;
522 case WM_CREATE:
523 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
525 /* Calculate vertical size and position of a popup window */
526 if (!win->lpszName)
528 POINT origin;
529 RECT old_window_rect;
530 RECT old_client_rect;
531 SIZE old_window_size;
532 SIZE old_client_size;
533 SIZE new_client_size;
534 SIZE new_window_size;
536 GetWindowRect(hWnd, &old_window_rect);
537 origin.x = old_window_rect.left;
538 origin.y = old_window_rect.top;
539 old_window_size.cx = old_window_rect.right - old_window_rect.left;
540 old_window_size.cy = old_window_rect.bottom - old_window_rect.top;
542 GetClientRect(hWnd, &old_client_rect);
543 old_client_size.cx = old_client_rect.right - old_client_rect.left;
544 old_client_size.cy = old_client_rect.bottom - old_client_rect.top;
546 new_client_size = old_client_size;
547 WINHELP_SplitLines(hWnd, &new_client_size);
549 if (origin.y + POPUP_YDISTANCE + new_client_size.cy <= GetSystemMetrics(SM_CYSCREEN))
550 origin.y += POPUP_YDISTANCE;
551 else
552 origin.y -= POPUP_YDISTANCE + new_client_size.cy;
554 new_window_size.cx = old_window_size.cx - old_client_size.cx + new_client_size.cx;
555 new_window_size.cy = old_window_size.cy - old_client_size.cy + new_client_size.cy;
557 win->hShadowWnd =
558 CreateWindow(SHADOW_WIN_CLASS_NAME, "", WS_POPUP | WS_VISIBLE,
559 origin.x + SHADOW_DX, origin.y + SHADOW_DY,
560 new_window_size.cx, new_window_size.cy,
561 0, 0, Globals.hInstance, 0);
563 SetWindowPos(hWnd, HWND_TOP, origin.x, origin.y,
564 new_window_size.cx, new_window_size.cy,
565 SWP_NOZORDER | SWP_NOACTIVATE);
566 ShowWindow(win->hShadowWnd, SW_NORMAL);
568 break;
570 case WM_WINDOWPOSCHANGED:
571 winpos = (WINDOWPOS*) lParam;
572 if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd);
573 break;
575 case WM_VSCROLL:
577 BOOL update = TRUE;
578 RECT rect;
579 INT Min, Max;
580 INT CurPos = GetScrollPos(hWnd, SB_VERT);
581 GetScrollRange(hWnd, SB_VERT, &Min, &Max);
582 GetClientRect(hWnd, &rect);
584 switch (wParam & 0xffff)
586 case SB_THUMBTRACK:
587 case SB_THUMBPOSITION: CurPos = wParam >> 16; break;
588 case SB_TOP: CurPos = Min; break;
589 case SB_BOTTOM: CurPos = Max; break;
590 case SB_PAGEUP: CurPos -= (rect.bottom - rect.top) / 2; break;
591 case SB_PAGEDOWN: CurPos += (rect.bottom - rect.top) / 2; break;
592 case SB_LINEUP: CurPos -= GetSystemMetrics(SM_CXVSCROLL); break;
593 case SB_LINEDOWN: CurPos += GetSystemMetrics(SM_CXVSCROLL); break;
594 default: update = FALSE;
596 if (update)
598 INT dy = GetScrollPos(hWnd, SB_VERT) - CurPos;
599 SetScrollPos(hWnd, SB_VERT, CurPos, TRUE);
600 ScrollWindow(hWnd, 0, dy, NULL, NULL);
601 UpdateWindow(hWnd);
604 break;
606 case WM_PAINT:
607 hDc = BeginPaint (hWnd, &ps);
608 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
609 scroll_pos = GetScrollPos(hWnd, SB_VERT);
611 for (line = win->first_line; line; line = line->next)
612 for (part = &line->first_part; part; part = part->next)
614 SelectObject(hDc, part->hFont);
615 SetTextColor(hDc, part->color);
616 TextOut(hDc, part->rect.left, part->rect.top - scroll_pos,
617 (LPSTR) part->lpsText, part->wTextLen);
620 EndPaint (hWnd, &ps);
621 break;
623 case WM_LBUTTONDOWN:
624 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
625 scroll_pos = GetScrollPos(hWnd, SB_VERT);
627 hPopupWnd = Globals.hPopupWnd;
628 Globals.hPopupWnd = 0;
630 mouse.x = LOWORD(lParam);
631 mouse.y = HIWORD(lParam);
632 for (line = win->first_line; line; line = line->next)
633 for (part = &line->first_part; part; part = part->next)
634 if (part->link.lpszPath &&
635 part->rect.left <= mouse.x &&
636 part->rect.right >= mouse.x &&
637 part->rect.top <= mouse.y + scroll_pos &&
638 part->rect.bottom >= mouse.y + scroll_pos)
639 WINHELP_CreateHelpWindow(part->link.lpszPath, part->link.lHash, NULL,
640 part->link.bPopup, hWnd, &mouse, SW_NORMAL);
641 if (hPopupWnd)
642 DestroyWindow(hPopupWnd);
643 break;
645 case WM_NCDESTROY:
646 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
648 if (hWnd == Globals.hPopupWnd) Globals.hPopupWnd = 0;
650 bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));
652 WINHELP_DeleteWindow(win);
654 if (bExit) MACRO_Exit();
656 if (!Globals.win_list)
657 PostQuitMessage (0);
658 break;
661 return DefWindowProc (hWnd, msg, wParam, lParam);
664 /***********************************************************************
666 * SetupText
669 static VOID WINHELP_SetupText(HWND hWnd)
671 HDC hDc = GetDC(hWnd);
672 RECT rect;
673 SIZE newsize;
675 ShowScrollBar(hWnd, SB_VERT, FALSE);
676 if (!WINHELP_SplitLines(hWnd, NULL))
678 ShowScrollBar(hWnd, SB_VERT, TRUE);
679 GetClientRect(hWnd, &rect);
681 WINHELP_SplitLines(hWnd, &newsize);
682 SetScrollRange(hWnd, SB_VERT, 0, rect.top + newsize.cy - rect.bottom, TRUE);
684 else SetScrollPos(hWnd, SB_VERT, 0, FALSE);
686 ReleaseDC(hWnd, hDc);
689 /***********************************************************************
691 * WINHELP_SplitLines
694 static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE newsize)
696 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
697 HLPFILE_PARAGRAPH *p;
698 WINHELP_LINE **line = &win->first_line;
699 WINHELP_LINE_PART **part = 0;
700 INT line_ascent = 0;
701 SIZE space;
702 RECT rect;
703 HDC hDc;
705 if (newsize) newsize->cx = newsize->cy = 0;
707 if (!win->page) return TRUE;
709 WINHELP_DeleteLines(win);
711 GetClientRect(hWnd, &rect);
713 rect.top += INTERNAL_BORDER_WIDTH;
714 rect.left += INTERNAL_BORDER_WIDTH;
715 rect.right -= INTERNAL_BORDER_WIDTH;
716 rect.bottom -= INTERNAL_BORDER_WIDTH;
719 space.cy = rect.top;
720 space.cx = rect.left;
722 hDc = GetDC(hWnd);
724 for (p = win->page->first_paragraph; p; p = p->next)
726 TEXTMETRIC tm;
727 SIZE textsize = {0, 0};
728 LPCSTR text = p->lpszText;
729 UINT len = strlen(text);
730 UINT indent = 0;
732 UINT wFont = (p->wFont < win->fonts_len) ? p->wFont : 0;
733 BOOL bUnderline = p->link && !p->link->bPopup;
734 HFONT hFont = win->fonts[wFont][bUnderline ? 1 : 0];
736 COLORREF color = RGB(0, 0, 0);
737 if (p->link) color = RGB(0, 0x80, 0);
738 if (p->bDebug) color = RGB(0xff, 0, 0);
740 SelectObject(hDc, hFont);
742 GetTextMetrics (hDc, &tm);
744 if (p->wIndent)
746 indent = p->wIndent * 5 * tm.tmAveCharWidth;
747 if (!part)
748 space.cx = rect.left + indent - 2 * tm.tmAveCharWidth;
751 if (p->wVSpace)
753 part = 0;
754 space.cx = rect.left + indent;
755 space.cy += (p->wVSpace - 1) * tm.tmHeight;
758 if (p->wHSpace)
760 space.cx += p->wHSpace * 2 * tm.tmAveCharWidth;
763 while (len)
765 INT free_width = rect.right - (part ? (*line)->rect.right : rect.left) - space.cx;
766 UINT low = 0, curr = len, high = len, textlen = 0;
768 if (free_width > 0)
770 while (1)
772 GetTextExtentPoint(hDc, text, curr, &textsize);
774 if (textsize.cx <= free_width) low = curr;
775 else high = curr;
777 if (high <= low + 1) break;
779 if (textsize.cx) curr = (curr * free_width) / textsize.cx;
780 if (curr <= low) curr = low + 1;
781 else if (curr >= high) curr = high - 1;
783 textlen = low;
784 while (textlen && text[textlen] && text[textlen] != ' ') textlen--;
786 if (!part && !textlen) textlen = max(low, 1);
788 if (free_width <= 0 || !textlen)
790 part = 0;
791 space.cx = rect.left + indent;
792 space.cx = min(space.cx, rect.right - rect.left - 1);
793 continue;
796 if (!WINHELP_AppendText(&line, &part, &space, &textsize,
797 &line_ascent, tm.tmAscent,
798 text, textlen, hFont, color, p->link) ||
799 (!newsize && (*line)->rect.bottom > rect.bottom))
801 ReleaseDC(hWnd, hDc);
802 return FALSE;
805 if (newsize)
806 newsize->cx = max(newsize->cx, (*line)->rect.right + INTERNAL_BORDER_WIDTH);
808 len -= textlen;
809 text += textlen;
810 if (text[0] == ' ') text++, len--;
814 if (newsize)
815 newsize->cy = (*line)->rect.bottom + INTERNAL_BORDER_WIDTH;
817 ReleaseDC(hWnd, hDc);
818 return TRUE;
821 /***********************************************************************
823 * WINHELP_AppendText
826 static BOOL WINHELP_AppendText(WINHELP_LINE ***linep, WINHELP_LINE_PART ***partp,
827 LPSIZE space, LPSIZE textsize,
828 INT *line_ascent, INT ascent,
829 LPCSTR text, UINT textlen,
830 HFONT font, COLORREF color, HLPFILE_LINK *link)
832 HGLOBAL handle;
833 WINHELP_LINE *line;
834 WINHELP_LINE_PART *part;
835 LPSTR ptr;
837 if (!*partp) /* New line */
839 *line_ascent = ascent;
841 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE) + textlen +
842 (link ? lstrlen(link->lpszPath) + 1 : 0));
843 if (!handle) return FALSE;
844 line = GlobalLock(handle);
845 line->next = 0;
846 part = &line->first_part;
847 ptr = GlobalLock(handle);
848 ptr += sizeof(WINHELP_LINE);
850 line->rect.top = (**linep ? (**linep)->rect.bottom : 0) + space->cy;
851 line->rect.bottom = line->rect.top;
852 line->rect.left = space->cx;
853 line->rect.right = space->cx;
855 if (**linep) *linep = &(**linep)->next;
856 **linep = line;
857 space->cy = 0;
859 else /* Same line */
861 line = **linep;
863 if (*line_ascent < ascent)
865 WINHELP_LINE_PART *p;
866 for (p = &line->first_part; p; p = p->next)
868 p->rect.top += ascent - *line_ascent;
869 p->rect.bottom += ascent - *line_ascent;
871 line->rect.bottom += ascent - *line_ascent;
872 *line_ascent = ascent;
875 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE_PART) + textlen +
876 (link ? lstrlen(link->lpszPath) + 1 : 0));
877 if (!handle) return FALSE;
878 part = GlobalLock(handle);
879 **partp = part;
880 ptr = GlobalLock(handle);
881 ptr += sizeof(WINHELP_LINE_PART);
884 memcpy(ptr, text, textlen);
885 part->rect.left = line->rect.right + (*partp ? space->cx : 0);
886 part->rect.right = part->rect.left + textsize->cx;
887 line->rect.right = part->rect.right;
888 part->rect.top =
889 ((*partp) ? line->rect.top : line->rect.bottom) + *line_ascent - ascent;
890 part->rect.bottom = part->rect.top + textsize->cy;
891 line->rect.bottom = max(line->rect.bottom, part->rect.bottom);
892 part->hSelf = handle;
893 part->lpsText = ptr;
894 part->wTextLen = textlen;
895 part->hFont = font;
896 part->color = color;
897 if (link)
899 strcpy(ptr + textlen, link->lpszPath);
900 part->link.lpszPath = ptr + textlen;
901 part->link.lHash = link->lHash;
902 part->link.bPopup = link->bPopup;
904 else part->link.lpszPath = 0;
906 part->next = 0;
907 *partp = &part->next;
909 space->cx = 0;
911 return TRUE;
914 /***********************************************************************
916 * WINHELP_CheckPopup
919 static VOID WINHELP_CheckPopup(UINT msg)
921 if (!Globals.hPopupWnd) return;
923 switch (msg)
925 case WM_COMMAND:
926 case WM_LBUTTONDOWN:
927 case WM_MBUTTONDOWN:
928 case WM_RBUTTONDOWN:
929 case WM_NCLBUTTONDOWN:
930 case WM_NCMBUTTONDOWN:
931 case WM_NCRBUTTONDOWN:
932 DestroyWindow(Globals.hPopupWnd);
933 Globals.hPopupWnd = 0;
937 /***********************************************************************
939 * WINHELP_DeleteLines
942 static VOID WINHELP_DeleteLines(WINHELP_WINDOW *win)
944 WINHELP_LINE *line, *next_line;
945 WINHELP_LINE_PART *part, *next_part;
946 for(line = win->first_line; line; line = next_line)
948 next_line = line->next;
949 for(part = &line->first_part; part; part = next_part)
951 next_part = part->next;
952 GlobalFree(part->hSelf);
955 win->first_line = 0;
958 /***********************************************************************
960 * WINHELP_DeleteWindow
963 static VOID WINHELP_DeleteWindow(WINHELP_WINDOW *win)
965 WINHELP_WINDOW **w;
967 for (w = &Globals.win_list; *w; w = &(*w)->next)
968 if (*w == win)
970 *w = win->next;
971 break;
974 if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
975 HLPFILE_FreeHlpFilePage(win->page);
976 WINHELP_DeleteLines(win);
977 GlobalFree(win->hSelf);
980 /***********************************************************************
982 * WINHELP_InitFonts
985 static VOID WINHELP_InitFonts(HWND hWnd)
987 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
988 LOGFONT logfontlist[] = {
989 {-10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
990 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
991 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
992 {-12, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
993 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
994 {-10, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
995 { -8, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"}};
996 #define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
998 static HFONT fonts[FONTS_LEN][2];
999 static BOOL init = 0;
1001 win->fonts_len = FONTS_LEN;
1002 win->fonts = fonts;
1004 if (!init)
1006 INT i;
1008 for(i = 0; i < FONTS_LEN; i++)
1010 LOGFONT logfont = logfontlist[i];
1012 fonts[i][0] = CreateFontIndirect(&logfont);
1013 logfont.lfUnderline = 1;
1014 fonts[i][1] = CreateFontIndirect(&logfont);
1017 init = 1;
1021 /***********************************************************************
1023 * WINHELP_MessageBoxIDS
1026 INT WINHELP_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
1028 CHAR text[MAX_STRING_LEN];
1029 CHAR title[MAX_STRING_LEN];
1031 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1032 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1034 return(MessageBox(0, text, title, type));
1037 /***********************************************************************
1039 * MAIN_MessageBoxIDS_s
1042 INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
1044 CHAR text[MAX_STRING_LEN];
1045 CHAR title[MAX_STRING_LEN];
1046 CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
1048 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1049 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1050 wsprintf(newtext, text, str);
1052 return(MessageBox(0, newtext, title, type));
1055 /* Local Variables: */
1056 /* c-file-style: "GNU" */
1057 /* End: */