Stub implementation of LHashValOfNameSysA.
[wine/dcerpc.git] / programs / winhelp / winhelp.c
blobef1b220476e1cb9c2077306e14ccaa23b607b496
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 (HANDLE hInstance, HANDLE 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 #ifdef WINELIB
82 opt_lang = Languages[Options.language].name;
83 #endif
85 /* Find language specific string table */
86 for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
88 Globals.wStringTableOffset = langnum * 0x100;
89 if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)) &&
90 !lstrcmp(opt_lang, lang))
91 break;
93 if (langnum > MAX_LANGUAGE_NUMBER)
95 /* Find fallback language */
96 for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
98 Globals.wStringTableOffset = langnum * 0x100;
99 if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)))
100 break;
102 if (langnum > MAX_LANGUAGE_NUMBER)
104 MessageBox(0, "No language found", "FATAL ERROR", MB_OK);
105 return(1);
109 /* Change Resource names */
110 lstrcpyn(STRING_MENU_Xx + lstrlen(STRING_MENU_Xx) - 2, lang, 3);
112 /* Create primary window */
113 WINHELP_RegisterWinClasses();
114 WINHELP_CreateHelpWindow(cmdline, lHash, "main", FALSE, NULL, NULL, show);
116 /* Message loop */
117 while (GetMessage (&msg, 0, 0, 0))
119 TranslateMessage (&msg);
120 DispatchMessage (&msg);
122 return 0;
125 /***********************************************************************
127 * RegisterWinClasses
130 static BOOL WINHELP_RegisterWinClasses()
132 WNDCLASS class_main, class_button_box, class_text, class_shadow;
134 class_main.style = CS_HREDRAW | CS_VREDRAW;
135 class_main.lpfnWndProc = WINHELP_MainWndProc;
136 class_main.cbClsExtra = 0;
137 class_main.cbWndExtra = sizeof(LONG);
138 class_main.hInstance = Globals.hInstance;
139 class_main.hIcon = LoadIcon (0, IDI_APPLICATION);
140 class_main.hCursor = LoadCursor (0, IDC_ARROW);
141 class_main.hbrBackground = GetStockObject (WHITE_BRUSH);
142 class_main.lpszMenuName = 0;
143 class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
145 class_button_box = class_main;
146 class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
147 class_button_box.hbrBackground = GetStockObject(GRAY_BRUSH);
148 class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
150 class_text = class_main;
151 class_text.lpfnWndProc = WINHELP_TextWndProc;
152 class_text.lpszClassName = TEXT_WIN_CLASS_NAME;
154 class_shadow = class_main;
155 class_shadow.lpfnWndProc = DefWindowProc;
156 class_shadow.hbrBackground = GetStockObject(GRAY_BRUSH);
157 class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;
159 return (RegisterClass(&class_main) &&
160 RegisterClass(&class_button_box) &&
161 RegisterClass(&class_text) &&
162 RegisterClass(&class_shadow));
165 /***********************************************************************
167 * WINHELP_CreateHelpWindow
170 VOID WINHELP_CreateHelpWindow(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWindow,
171 BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
173 CHAR szCaption[MAX_STRING_LEN];
174 CHAR szContents[MAX_STRING_LEN];
175 CHAR szSearch[MAX_STRING_LEN];
176 CHAR szBack[MAX_STRING_LEN];
177 CHAR szHistory[MAX_STRING_LEN];
178 SIZE size = {CW_USEDEFAULT, CW_USEDEFAULT};
179 POINT origin = {240, 0};
180 LPSTR ptr;
181 HGLOBAL handle;
182 WINHELP_WINDOW *win, *oldwin;
183 HLPFILE_PAGE *page;
184 HLPFILE_MACRO *macro;
185 HWND hWnd;
186 BOOL bPrimary;
188 if (bPopup)
189 lpszWindow = NULL;
190 else if (!lpszWindow || !lpszWindow[0])
191 lpszWindow = Globals.active_win->lpszName;
192 bPrimary = lpszWindow && !lstrcmpi(lpszWindow, "main");
194 /* Read help file */
195 if (lpszFile[0])
197 page = lHash ? HLPFILE_PageByHash(lpszFile, lHash) : HLPFILE_Contents(lpszFile);
199 /* Add Suffix `.hlp' */
200 if (!page && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp"))
202 CHAR szFile_hlp[MAX_PATHNAME_LEN];
204 lstrcpyn(szFile_hlp, lpszFile, sizeof(szFile_hlp) - 4);
205 szFile_hlp[sizeof(szFile_hlp) - 5] = '\0';
206 lstrcat(szFile_hlp, ".hlp");
208 page = lHash ? HLPFILE_PageByHash(szFile_hlp, lHash) : HLPFILE_Contents(szFile_hlp);
209 if (!page)
211 WINHELP_MessageBoxIDS_s(IDS_HLPFILE_ERROR_s, lpszFile, IDS_ERROR, MB_OK);
212 if (Globals.win_list) return;
216 else page = 0;
218 /* Calculate horizontal size and position of a popup window */
219 if (bPopup)
221 RECT parent_rect;
222 GetWindowRect(hParentWnd, &parent_rect);
223 size.cx = (parent_rect.right - parent_rect.left) / 2;
225 origin = *mouse;
226 ClientToScreen(hParentWnd, &origin);
227 origin.x -= size.cx / 2;
228 origin.x = min(origin.x, GetSystemMetrics(SM_CXSCREEN) - size.cx);
229 origin.x = max(origin.x, 0);
232 /* Initialize WINHELP_WINDOW struct */
233 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_WINDOW) +
234 (lpszWindow ? strlen(lpszWindow) + 1 : 0));
235 if (!handle) return;
236 win = GlobalLock(handle);
237 win->hSelf = handle;
238 win->next = Globals.win_list;
239 Globals.win_list = win;
240 if (lpszWindow)
242 ptr = GlobalLock(handle);
243 ptr += sizeof(WINHELP_WINDOW);
244 lstrcpy(ptr, (LPSTR) lpszWindow);
245 win->lpszName = ptr;
247 else win->lpszName = NULL;
248 win->page = page;
249 win->first_button = 0;
250 win->first_line = 0;
251 win->hMainWnd = 0;
252 win->hButtonBoxWnd = 0;
253 win->hTextWnd = 0;
254 win->hShadowWnd = 0;
256 Globals.active_win = win;
258 /* Initialize default pushbuttons */
259 if (MacroTest && !bPopup)
260 MACRO_CreateButton("BTN_TEST", "&Test", "MacroTest");
261 if (bPrimary && page)
263 LoadString(Globals.hInstance, IDS_CONTENTS, szContents, sizeof(szContents));
264 LoadString(Globals.hInstance, IDS_SEARCH, szSearch, sizeof(szSearch));
265 LoadString(Globals.hInstance, IDS_BACK, szBack, sizeof(szBack));
266 LoadString(Globals.hInstance, IDS_HISTORY, szHistory, sizeof(szHistory));
267 MACRO_CreateButton("BTN_CONTENTS", szContents, "Contents()");
268 MACRO_CreateButton("BTN_SEARCH", szSearch, "Search()");
269 MACRO_CreateButton("BTN_BACK", szBack, "Back()");
270 MACRO_CreateButton("BTN_HISTORY", szHistory, "History()");
273 /* Initialize file specific pushbuttons */
274 if (!bPopup && page)
275 for (macro = page->file->first_macro; macro; macro = macro->next)
276 MACRO_ExecuteMacro(macro->lpszMacro);
278 /* Reuse existing window */
279 if (lpszWindow)
280 for (oldwin = win->next; oldwin; oldwin = oldwin->next)
281 if (oldwin->lpszName && !lstrcmpi(oldwin->lpszName, lpszWindow))
283 WINHELP_BUTTON *button;
285 win->hMainWnd = oldwin->hMainWnd;
286 win->hButtonBoxWnd = oldwin->hButtonBoxWnd;
287 win->hTextWnd = oldwin->hTextWnd;
288 oldwin->hMainWnd = oldwin->hButtonBoxWnd = oldwin->hTextWnd = 0;
290 SetWindowLong(win->hMainWnd, 0, (LONG) win);
291 SetWindowLong(win->hButtonBoxWnd, 0, (LONG) win);
292 SetWindowLong(win->hTextWnd, 0, (LONG) win);
294 WINHELP_InitFonts(win->hMainWnd);
296 if (page) {
297 SetWindowText(win->hMainWnd, page->file->lpszTitle);
300 WINHELP_SetupText(win->hTextWnd);
301 InvalidateRect(win->hTextWnd, NULL, TRUE);
302 SendMessage(win->hMainWnd, WM_USER, 0, 0);
303 UpdateWindow(win->hTextWnd);
306 for (button = oldwin->first_button; button; button = button->next)
307 DestroyWindow(button->hWnd);
309 WINHELP_DeleteWindow(oldwin);
310 return;
313 /* Create main Window */
314 if (!page) LoadString(Globals.hInstance, IDS_WINE_HELP, szCaption, sizeof(szCaption));
315 hWnd = CreateWindow (bPopup ? TEXT_WIN_CLASS_NAME : MAIN_WIN_CLASS_NAME,
316 page ? page->file->lpszTitle : szCaption,
317 bPopup ? WS_POPUPWINDOW | WS_BORDER : WS_OVERLAPPEDWINDOW,
318 origin.x, origin.y, size.cx, size.cy,
319 0, bPrimary ? LoadMenu(Globals.hInstance, STRING_MENU_Xx) : 0,
320 Globals.hInstance, win);
322 ShowWindow (hWnd, nCmdShow);
323 UpdateWindow (hWnd);
326 /***********************************************************************
328 * WINHELP_MainWndProc
331 static LRESULT CALLBACK WINHELP_MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
333 WINHELP_WINDOW *win;
334 WINHELP_BUTTON *button;
335 RECT rect, button_box_rect;
336 INT text_top;
338 WINHELP_CheckPopup(msg);
340 switch (msg)
342 case WM_NCCREATE:
343 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
344 SetWindowLong(hWnd, 0, (LONG) win);
345 win->hMainWnd = hWnd;
346 break;
348 case WM_CREATE:
349 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
351 /* Create button box and text Window */
352 CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
353 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
355 CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
356 0, 0, 0, 0, hWnd, 0, Globals.hInstance, win);
358 /* Fall through */
359 case WM_USER:
360 case WM_WINDOWPOSCHANGED:
361 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
362 GetClientRect(hWnd, &rect);
364 /* Update button box and text Window */
365 SetWindowPos(win->hButtonBoxWnd, HWND_TOP,
366 rect.left, rect.top,
367 rect.right - rect.left,
368 rect.bottom - rect.top, 0);
370 GetWindowRect(win->hButtonBoxWnd, &button_box_rect);
371 text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
373 SetWindowPos(win->hTextWnd, HWND_TOP,
374 rect.left, text_top,
375 rect.right - rect.left,
376 rect.bottom - text_top, 0);
378 break;
380 case WM_COMMAND:
381 Globals.active_win = win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
382 switch (wParam)
384 /* Menu FILE */
385 case WH_OPEN: MACRO_FileOpen(); break;
386 case WH_PRINT: MACRO_Print(); break;
387 case WH_PRINTER_SETUP: MACRO_PrinterSetup(); break;
388 case WH_EXIT: MACRO_Exit(); break;
390 /* Menu EDIT */
391 case WH_COPY_DIALOG: MACRO_CopyDialog(); break;
392 case WH_ANNOTATE: MACRO_Annotate(); break;
394 /* Menu Bookmark */
395 case WH_BOOKMARK_DEFINE: MACRO_BookmarkDefine(); break;
397 /* Menu Help */
398 case WH_HELP_ON_HELP: MACRO_HelpOn(); break;
399 case WH_HELP_ON_TOP: MACRO_HelpOnTop(); break;
401 /* Menu Info */
402 case WH_ABOUT: MACRO_About(); break;
404 case WH_ABOUT_WINE:
405 ShellAbout(hWnd, "WINE", "Help", 0);
406 break;
408 default:
409 /* Buttons */
410 for (button = win->first_button; button; button = button->next)
411 if (wParam == button->wParam) break;
412 if (button)
413 MACRO_ExecuteMacro(button->lpszMacro);
414 else
415 WINHELP_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
416 break;
418 break;
421 return DefWindowProc (hWnd, msg, wParam, lParam);
424 /***********************************************************************
426 * WINHELP_ButtonBoxWndProc
429 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
431 WINDOWPOS *winpos;
432 WINHELP_WINDOW *win;
433 WINHELP_BUTTON *button;
434 SIZE button_size;
435 INT x, y;
437 WINHELP_CheckPopup(msg);
439 switch(msg)
441 case WM_NCCREATE:
442 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
443 SetWindowLong(hWnd, 0, (LONG) win);
444 win->hButtonBoxWnd = hWnd;
445 break;
447 case WM_WINDOWPOSCHANGING:
448 winpos = (WINDOWPOS*) lParam;
449 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
451 /* Update buttons */
452 button_size.cx = 0;
453 button_size.cy = 0;
454 for (button = win->first_button; button; button = button->next)
456 HDC hDc;
457 SIZE textsize;
458 if (!button->hWnd)
459 button->hWnd = CreateWindow(STRING_BUTTON, (LPSTR) button->lpszName,
460 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
461 0, 0, 0, 0,
462 hWnd, (HMENU) button->wParam,
463 Globals.hInstance, 0);
464 hDc = GetDC(button->hWnd);
465 GetTextExtentPoint(hDc, button->lpszName,
466 lstrlen(button->lpszName), &textsize);
467 ReleaseDC(button->hWnd, hDc);
469 button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
470 button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
473 x = 0;
474 y = 0;
475 for (button = win->first_button; button; button = button->next)
477 SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
479 if (x + 2 * button_size.cx <= winpos->cx)
480 x += button_size.cx;
481 else
482 x = 0, y += button_size.cy;
484 winpos->cy = y + (x ? button_size.cy : 0);
485 break;
487 case WM_COMMAND:
488 SendMessage(GetParent(hWnd), msg, wParam, lParam);
489 break;
492 return(DefWindowProc(hWnd, msg, wParam, lParam));
495 /***********************************************************************
497 * WINHELP_TextWndProc
500 static LRESULT CALLBACK WINHELP_TextWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
502 WINHELP_WINDOW *win;
503 WINHELP_LINE *line;
504 WINHELP_LINE_PART *part;
505 WINDOWPOS *winpos;
506 PAINTSTRUCT ps;
507 HDC hDc;
508 POINT mouse;
509 INT scroll_pos;
510 HWND hPopupWnd;
511 BOOL bExit;
513 if (msg != WM_LBUTTONDOWN)
514 WINHELP_CheckPopup(msg);
516 switch (msg)
518 case WM_NCCREATE:
519 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
520 SetWindowLong(hWnd, 0, (LONG) win);
521 win->hTextWnd = hWnd;
522 if (!win->lpszName) Globals.hPopupWnd = win->hMainWnd = hWnd;
523 WINHELP_InitFonts(hWnd);
524 break;
526 case WM_CREATE:
527 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
529 /* Calculate vertical size and position of a popup window */
530 if (!win->lpszName)
532 POINT origin;
533 RECT old_window_rect;
534 RECT old_client_rect;
535 SIZE old_window_size;
536 SIZE old_client_size;
537 SIZE new_client_size;
538 SIZE new_window_size;
540 GetWindowRect(hWnd, &old_window_rect);
541 origin.x = old_window_rect.left;
542 origin.y = old_window_rect.top;
543 old_window_size.cx = old_window_rect.right - old_window_rect.left;
544 old_window_size.cy = old_window_rect.bottom - old_window_rect.top;
546 GetClientRect(hWnd, &old_client_rect);
547 old_client_size.cx = old_client_rect.right - old_client_rect.left;
548 old_client_size.cy = old_client_rect.bottom - old_client_rect.top;
550 new_client_size = old_client_size;
551 WINHELP_SplitLines(hWnd, &new_client_size);
553 if (origin.y + POPUP_YDISTANCE + new_client_size.cy <= GetSystemMetrics(SM_CYSCREEN))
554 origin.y += POPUP_YDISTANCE;
555 else
556 origin.y -= POPUP_YDISTANCE + new_client_size.cy;
558 new_window_size.cx = old_window_size.cx - old_client_size.cx + new_client_size.cx;
559 new_window_size.cy = old_window_size.cy - old_client_size.cy + new_client_size.cy;
561 win->hShadowWnd =
562 CreateWindow(SHADOW_WIN_CLASS_NAME, "", WS_POPUP | WS_VISIBLE,
563 origin.x + SHADOW_DX, origin.y + SHADOW_DY,
564 new_window_size.cx, new_window_size.cy,
565 0, 0, Globals.hInstance, 0);
567 SetWindowPos(hWnd, HWND_TOP, origin.x, origin.y,
568 new_window_size.cx, new_window_size.cy,
569 SWP_NOZORDER | SWP_NOACTIVATE);
570 ShowWindow(win->hShadowWnd, SW_NORMAL);
572 break;
574 case WM_WINDOWPOSCHANGED:
575 winpos = (WINDOWPOS*) lParam;
576 if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd);
577 break;
579 case WM_VSCROLL:
581 BOOL update = TRUE;
582 RECT rect;
583 INT Min, Max;
584 INT CurPos = GetScrollPos(hWnd, SB_VERT);
585 GetScrollRange(hWnd, SB_VERT, &Min, &Max);
586 GetClientRect(hWnd, &rect);
588 switch (wParam & 0xffff)
590 case SB_THUMBTRACK:
591 case SB_THUMBPOSITION: CurPos = wParam >> 16; break;
592 case SB_TOP: CurPos = Min; break;
593 case SB_BOTTOM: CurPos = Max; break;
594 case SB_PAGEUP: CurPos -= (rect.bottom - rect.top) / 2; break;
595 case SB_PAGEDOWN: CurPos += (rect.bottom - rect.top) / 2; break;
596 case SB_LINEUP: CurPos -= GetSystemMetrics(SM_CXVSCROLL); break;
597 case SB_LINEDOWN: CurPos += GetSystemMetrics(SM_CXVSCROLL); break;
598 default: update = FALSE;
600 if (update)
602 INT dy = GetScrollPos(hWnd, SB_VERT) - CurPos;
603 SetScrollPos(hWnd, SB_VERT, CurPos, TRUE);
604 ScrollWindow(hWnd, 0, dy, NULL, NULL);
605 UpdateWindow(hWnd);
608 break;
610 case WM_PAINT:
611 hDc = BeginPaint (hWnd, &ps);
612 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
613 scroll_pos = GetScrollPos(hWnd, SB_VERT);
615 for (line = win->first_line; line; line = line->next)
616 for (part = &line->first_part; part; part = part->next)
618 SelectObject(hDc, part->hFont);
619 SetTextColor(hDc, part->color);
620 TextOut(hDc, part->rect.left, part->rect.top - scroll_pos,
621 (LPSTR) part->lpsText, part->wTextLen);
624 EndPaint (hWnd, &ps);
625 break;
627 case WM_LBUTTONDOWN:
628 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
629 scroll_pos = GetScrollPos(hWnd, SB_VERT);
631 hPopupWnd = Globals.hPopupWnd;
632 Globals.hPopupWnd = 0;
634 mouse.x = LOWORD(lParam);
635 mouse.y = HIWORD(lParam);
636 for (line = win->first_line; line; line = line->next)
637 for (part = &line->first_part; part; part = part->next)
638 if (part->link.lpszPath &&
639 part->rect.left <= mouse.x &&
640 part->rect.right >= mouse.x &&
641 part->rect.top <= mouse.y + scroll_pos &&
642 part->rect.bottom >= mouse.y + scroll_pos)
643 WINHELP_CreateHelpWindow(part->link.lpszPath, part->link.lHash, NULL,
644 part->link.bPopup, hWnd, &mouse, SW_NORMAL);
645 if (hPopupWnd)
646 DestroyWindow(hPopupWnd);
647 break;
649 case WM_NCDESTROY:
650 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
652 if (hWnd == Globals.hPopupWnd) Globals.hPopupWnd = 0;
654 bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));
656 WINHELP_DeleteWindow(win);
658 if (bExit) MACRO_Exit();
660 if (!Globals.win_list)
661 PostQuitMessage (0);
662 break;
665 return DefWindowProc (hWnd, msg, wParam, lParam);
668 /***********************************************************************
670 * SetupText
673 static VOID WINHELP_SetupText(HWND hWnd)
675 HDC hDc = GetDC(hWnd);
676 RECT rect;
677 SIZE newsize;
679 ShowScrollBar(hWnd, SB_VERT, FALSE);
680 if (!WINHELP_SplitLines(hWnd, NULL))
682 ShowScrollBar(hWnd, SB_VERT, TRUE);
683 GetClientRect(hWnd, &rect);
685 WINHELP_SplitLines(hWnd, &newsize);
686 SetScrollRange(hWnd, SB_VERT, 0, rect.top + newsize.cy - rect.bottom, TRUE);
688 else SetScrollPos(hWnd, SB_VERT, 0, FALSE);
690 ReleaseDC(hWnd, hDc);
693 /***********************************************************************
695 * WINHELP_SplitLines
698 static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE newsize)
700 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
701 HLPFILE_PARAGRAPH *p;
702 WINHELP_LINE **line = &win->first_line;
703 WINHELP_LINE_PART **part = 0;
704 INT line_ascent = 0;
705 SIZE space;
706 RECT rect;
707 HDC hDc;
709 if (newsize) newsize->cx = newsize->cy = 0;
711 if (!win->page) return TRUE;
713 WINHELP_DeleteLines(win);
715 GetClientRect(hWnd, &rect);
717 rect.top += INTERNAL_BORDER_WIDTH;
718 rect.left += INTERNAL_BORDER_WIDTH;
719 rect.right -= INTERNAL_BORDER_WIDTH;
720 rect.bottom -= INTERNAL_BORDER_WIDTH;
723 space.cy = rect.top;
724 space.cx = rect.left;
726 hDc = GetDC(hWnd);
728 for (p = win->page->first_paragraph; p; p = p->next)
730 TEXTMETRIC tm;
731 SIZE textsize = {0, 0};
732 LPCSTR text = p->lpszText;
733 UINT len = strlen(text);
734 UINT indent = 0;
736 UINT wFont = (p->wFont < win->fonts_len) ? p->wFont : 0;
737 BOOL bUnderline = p->link && !p->link->bPopup;
738 HFONT hFont = win->fonts[wFont][bUnderline ? 1 : 0];
740 COLORREF color = RGB(0, 0, 0);
741 if (p->link) color = RGB(0, 0x80, 0);
742 if (p->bDebug) color = RGB(0xff, 0, 0);
744 SelectObject(hDc, hFont);
746 GetTextMetrics (hDc, &tm);
748 if (p->wIndent)
750 indent = p->wIndent * 5 * tm.tmAveCharWidth;
751 if (!part)
752 space.cx = rect.left + indent - 2 * tm.tmAveCharWidth;
755 if (p->wVSpace)
757 part = 0;
758 space.cx = rect.left + indent;
759 space.cy += (p->wVSpace - 1) * tm.tmHeight;
762 if (p->wHSpace)
764 space.cx += p->wHSpace * 2 * tm.tmAveCharWidth;
767 while (len)
769 INT free_width = rect.right - (part ? (*line)->rect.right : rect.left) - space.cx;
770 UINT low = 0, curr = len, high = len, textlen = 0;
772 if (free_width > 0)
774 while (1)
776 GetTextExtentPoint(hDc, text, curr, &textsize);
778 if (textsize.cx <= free_width) low = curr;
779 else high = curr;
781 if (high <= low + 1) break;
783 if (textsize.cx) curr = (curr * free_width) / textsize.cx;
784 if (curr <= low) curr = low + 1;
785 else if (curr >= high) curr = high - 1;
787 textlen = low;
788 while (textlen && text[textlen] && text[textlen] != ' ') textlen--;
790 if (!part && !textlen) textlen = max(low, 1);
792 if (free_width <= 0 || !textlen)
794 part = 0;
795 space.cx = rect.left + indent;
796 space.cx = min(space.cx, rect.right - rect.left - 1);
797 continue;
800 if (!WINHELP_AppendText(&line, &part, &space, &textsize,
801 &line_ascent, tm.tmAscent,
802 text, textlen, hFont, color, p->link) ||
803 (!newsize && (*line)->rect.bottom > rect.bottom))
805 ReleaseDC(hWnd, hDc);
806 return FALSE;
809 if (newsize)
810 newsize->cx = max(newsize->cx, (*line)->rect.right + INTERNAL_BORDER_WIDTH);
812 len -= textlen;
813 text += textlen;
814 if (text[0] == ' ') text++, len--;
818 if (newsize)
819 newsize->cy = (*line)->rect.bottom + INTERNAL_BORDER_WIDTH;
821 ReleaseDC(hWnd, hDc);
822 return TRUE;
825 /***********************************************************************
827 * WINHELP_AppendText
830 static BOOL WINHELP_AppendText(WINHELP_LINE ***linep, WINHELP_LINE_PART ***partp,
831 LPSIZE space, LPSIZE textsize,
832 INT *line_ascent, INT ascent,
833 LPCSTR text, UINT textlen,
834 HFONT font, COLORREF color, HLPFILE_LINK *link)
836 HGLOBAL handle;
837 WINHELP_LINE *line;
838 WINHELP_LINE_PART *part;
839 LPSTR ptr;
841 if (!*partp) /* New line */
843 *line_ascent = ascent;
845 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE) + textlen +
846 (link ? lstrlen(link->lpszPath) + 1 : 0));
847 if (!handle) return FALSE;
848 line = GlobalLock(handle);
849 line->next = 0;
850 part = &line->first_part;
851 ptr = GlobalLock(handle);
852 ptr += sizeof(WINHELP_LINE);
854 line->rect.top = (**linep ? (**linep)->rect.bottom : 0) + space->cy;
855 line->rect.bottom = line->rect.top;
856 line->rect.left = space->cx;
857 line->rect.right = space->cx;
859 if (**linep) *linep = &(**linep)->next;
860 **linep = line;
861 space->cy = 0;
863 else /* Same line */
865 line = **linep;
867 if (*line_ascent < ascent)
869 WINHELP_LINE_PART *p;
870 for (p = &line->first_part; p; p = p->next)
872 p->rect.top += ascent - *line_ascent;
873 p->rect.bottom += ascent - *line_ascent;
875 line->rect.bottom += ascent - *line_ascent;
876 *line_ascent = ascent;
879 handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE_PART) + textlen +
880 (link ? lstrlen(link->lpszPath) + 1 : 0));
881 if (!handle) return FALSE;
882 part = GlobalLock(handle);
883 **partp = part;
884 ptr = GlobalLock(handle);
885 ptr += sizeof(WINHELP_LINE_PART);
888 memcpy(ptr, text, textlen);
889 part->rect.left = line->rect.right + (*partp ? space->cx : 0);
890 part->rect.right = part->rect.left + textsize->cx;
891 line->rect.right = part->rect.right;
892 part->rect.top =
893 ((*partp) ? line->rect.top : line->rect.bottom) + *line_ascent - ascent;
894 part->rect.bottom = part->rect.top + textsize->cy;
895 line->rect.bottom = max(line->rect.bottom, part->rect.bottom);
896 part->hSelf = handle;
897 part->lpsText = ptr;
898 part->wTextLen = textlen;
899 part->hFont = font;
900 part->color = color;
901 if (link)
903 strcpy(ptr + textlen, link->lpszPath);
904 part->link.lpszPath = ptr + textlen;
905 part->link.lHash = link->lHash;
906 part->link.bPopup = link->bPopup;
908 else part->link.lpszPath = 0;
910 part->next = 0;
911 *partp = &part->next;
913 space->cx = 0;
915 return TRUE;
918 /***********************************************************************
920 * WINHELP_CheckPopup
923 static VOID WINHELP_CheckPopup(UINT msg)
925 if (!Globals.hPopupWnd) return;
927 switch (msg)
929 case WM_COMMAND:
930 case WM_LBUTTONDOWN:
931 case WM_MBUTTONDOWN:
932 case WM_RBUTTONDOWN:
933 case WM_NCLBUTTONDOWN:
934 case WM_NCMBUTTONDOWN:
935 case WM_NCRBUTTONDOWN:
936 DestroyWindow(Globals.hPopupWnd);
937 Globals.hPopupWnd = 0;
941 /***********************************************************************
943 * WINHELP_DeleteLines
946 static VOID WINHELP_DeleteLines(WINHELP_WINDOW *win)
948 WINHELP_LINE *line, *next_line;
949 WINHELP_LINE_PART *part, *next_part;
950 for(line = win->first_line; line; line = next_line)
952 next_line = line->next;
953 for(part = &line->first_part; part; part = next_part)
955 next_part = part->next;
956 GlobalFree(part->hSelf);
959 win->first_line = 0;
962 /***********************************************************************
964 * WINHELP_DeleteWindow
967 static VOID WINHELP_DeleteWindow(WINHELP_WINDOW *win)
969 WINHELP_WINDOW **w;
971 for (w = &Globals.win_list; *w; w = &(*w)->next)
972 if (*w == win)
974 *w = win->next;
975 break;
978 if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
979 HLPFILE_FreeHlpFilePage(win->page);
980 WINHELP_DeleteLines(win);
981 GlobalFree(win->hSelf);
984 /***********************************************************************
986 * WINHELP_InitFonts
989 static VOID WINHELP_InitFonts(HWND hWnd)
991 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
992 LOGFONT logfontlist[] = {
993 {-10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
994 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
995 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
996 {-12, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
997 {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
998 {-10, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
999 { -8, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"}};
1000 #define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
1002 static HFONT fonts[FONTS_LEN][2];
1003 static BOOL init = 0;
1005 win->fonts_len = FONTS_LEN;
1006 win->fonts = fonts;
1008 if (!init)
1010 INT i;
1012 for(i = 0; i < FONTS_LEN; i++)
1014 LOGFONT logfont = logfontlist[i];
1016 fonts[i][0] = CreateFontIndirect(&logfont);
1017 logfont.lfUnderline = 1;
1018 fonts[i][1] = CreateFontIndirect(&logfont);
1021 init = 1;
1025 /***********************************************************************
1027 * WINHELP_MessageBoxIDS
1030 INT WINHELP_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
1032 CHAR text[MAX_STRING_LEN];
1033 CHAR title[MAX_STRING_LEN];
1035 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1036 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1038 return(MessageBox(0, text, title, type));
1041 /***********************************************************************
1043 * MAIN_MessageBoxIDS_s
1046 INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
1048 CHAR text[MAX_STRING_LEN];
1049 CHAR title[MAX_STRING_LEN];
1050 CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
1052 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1053 LoadString(Globals.hInstance, ids_title, title, sizeof(title));
1054 wsprintf(newtext, text, str);
1056 return(MessageBox(0, newtext, title, type));
1059 /* Local Variables: */
1060 /* c-file-style: "GNU" */
1061 /* End: */