hhctrl.ocx: Resize tab control in Child's WM_SIZE handler.
[wine] / dlls / hhctrl.ocx / help.c
1 /*
2  * Help Viewer Implementation
3  *
4  * Copyright 2005 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "hhctrl.h"
22
23 #include "wingdi.h"
24 #include "commctrl.h"
25 #include "wininet.h"
26
27 #include "wine/debug.h"
28
29 #include "resource.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
32
33 static LRESULT Help_OnSize(HWND hWnd);
34
35 /* Window type defaults */
36
37 #define WINTYPE_DEFAULT_X           280
38 #define WINTYPE_DEFAULT_Y           100
39 #define WINTYPE_DEFAULT_WIDTH       740
40 #define WINTYPE_DEFAULT_HEIGHT      640
41 #define WINTYPE_DEFAULT_NAVWIDTH    250
42
43 #define TAB_TOP_PADDING     8
44 #define TAB_RIGHT_PADDING   4
45
46 static const WCHAR szEmpty[] = {0};
47
48 /* Loads a string from the resource file */
49 static LPWSTR HH_LoadString(DWORD dwID)
50 {
51     LPWSTR string = NULL;
52     int iSize;
53
54     iSize = LoadStringW(hhctrl_hinstance, dwID, NULL, 0);
55     iSize += 2; /* some strings (tab text) needs double-null termination */
56
57     string = hhctrl_alloc(iSize * sizeof(WCHAR));
58     LoadStringW(hhctrl_hinstance, dwID, string, iSize);
59
60     return string;
61 }
62
63 BOOL NavigateToUrl(HHInfo *info, LPCWSTR surl)
64 {
65     VARIANT url;
66     HRESULT hres;
67
68     V_VT(&url) = VT_BSTR;
69     V_BSTR(&url) = SysAllocString(surl);
70
71     hres = IWebBrowser2_Navigate2(info->web_browser, &url, 0, 0, 0, 0);
72
73     VariantClear(&url);
74
75     return SUCCEEDED(hres);
76 }
77
78 BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
79 {
80     WCHAR buf[INTERNET_MAX_URL_LENGTH];
81     WCHAR full_path[MAX_PATH];
82     LPWSTR ptr;
83
84     static const WCHAR url_format[] =
85         {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','/','%','s',0};
86
87     TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
88
89     if (!info->web_browser)
90         return FALSE;
91
92     if(!GetFullPathNameW(file, sizeof(full_path), full_path, NULL)) {
93         WARN("GetFullPathName failed: %u\n", GetLastError());
94         return FALSE;
95     }
96
97     wsprintfW(buf, url_format, full_path, index);
98
99     /* FIXME: HACK */
100     if((ptr = strchrW(buf, '#')))
101        *ptr = 0;
102
103     return NavigateToUrl(info, buf);
104 }
105
106 /* Size Bar */
107
108 #define SIZEBAR_WIDTH   4
109
110 static const WCHAR szSizeBarClass[] = {
111     'H','H',' ','S','i','z','e','B','a','r',0
112 };
113
114 /* Draw the SizeBar */
115 static void SB_OnPaint(HWND hWnd)
116 {
117     PAINTSTRUCT ps;
118     HDC hdc;
119     RECT rc;
120     
121     hdc = BeginPaint(hWnd, &ps);
122
123     GetClientRect(hWnd, &rc);
124
125     /* dark frame */
126     rc.right += 1;
127     rc.bottom -= 1;
128     FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH));
129
130     /* white highlight */
131     SelectObject(hdc, GetStockObject(WHITE_PEN));
132     MoveToEx(hdc, rc.right, 1, NULL);
133     LineTo(hdc, 1, 1);
134     LineTo(hdc, 1, rc.bottom - 1);
135
136     
137     MoveToEx(hdc, 0, rc.bottom, NULL);
138     LineTo(hdc, rc.right, rc.bottom);
139
140     EndPaint(hWnd, &ps);
141 }
142
143 static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
144 {
145     SetCapture(hWnd);
146 }
147
148 static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
149 {
150     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
151     POINT pt;
152
153     pt.x = (short)LOWORD(lParam);
154     pt.y = (short)HIWORD(lParam);
155
156     /* update the window sizes */
157     pHHInfo->WinType.iNavWidth += pt.x;
158     Help_OnSize(hWnd);
159
160     ReleaseCapture();
161 }
162
163 static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
164 {
165     /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
166     if (!(wParam & MK_LBUTTON))
167         return;
168 }
169
170 static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
171 {
172     switch (message)
173     {
174         case WM_LBUTTONDOWN:
175             SB_OnLButtonDown(hWnd, wParam, lParam);
176             break;
177         case WM_LBUTTONUP:
178             SB_OnLButtonUp(hWnd, wParam, lParam);
179             break;
180         case WM_MOUSEMOVE:
181             SB_OnMouseMove(hWnd, wParam, lParam);
182             break;
183         case WM_PAINT:
184             SB_OnPaint(hWnd);
185             break;
186         default:
187             return DefWindowProcW(hWnd, message, wParam, lParam);
188     }
189
190     return 0;
191 }
192
193 static void HH_RegisterSizeBarClass(HHInfo *pHHInfo)
194 {
195     WNDCLASSEXW wcex;
196
197     wcex.cbSize         = sizeof(WNDCLASSEXW);
198     wcex.style          = 0;
199     wcex.lpfnWndProc    = SizeBar_WndProc;
200     wcex.cbClsExtra     = 0;
201     wcex.cbWndExtra     = 0;
202     wcex.hInstance      = hhctrl_hinstance;
203     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
204     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE);
205     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
206     wcex.lpszMenuName   = NULL;
207     wcex.lpszClassName  = szSizeBarClass;
208     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
209
210     RegisterClassExW(&wcex);
211 }
212
213 static void SB_GetSizeBarRect(HHInfo *info, RECT *rc)
214 {
215     RECT rectWND, rectTB, rectNP;
216
217     GetClientRect(info->WinType.hwndHelp, &rectWND);
218     GetClientRect(info->WinType.hwndToolBar, &rectTB);
219     GetClientRect(info->WinType.hwndNavigation, &rectNP);
220
221     rc->left = rectNP.right;
222     rc->top = rectTB.bottom;
223     rc->bottom = rectWND.bottom - rectTB.bottom;
224     rc->right = SIZEBAR_WIDTH;
225 }
226
227 static BOOL HH_AddSizeBar(HHInfo *pHHInfo)
228 {
229     HWND hWnd;
230     HWND hwndParent = pHHInfo->WinType.hwndHelp;
231     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_OVERLAPPED;
232     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
233     RECT rc;
234
235     SB_GetSizeBarRect(pHHInfo, &rc);
236
237     hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles,
238                            rc.left, rc.top, rc.right, rc.bottom,
239                            hwndParent, NULL, hhctrl_hinstance, NULL);
240     if (!hWnd)
241         return FALSE;
242
243     /* store the pointer to the HH info struct */
244     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
245
246     pHHInfo->hwndSizeBar = hWnd;
247     return TRUE;
248 }
249
250 /* Child Window */
251
252 static const WCHAR szChildClass[] = {
253     'H','H',' ','C','h','i','l','d',0
254 };
255
256 static LRESULT Child_OnPaint(HWND hWnd)
257 {
258     PAINTSTRUCT ps;
259     HDC hdc;
260     RECT rc;
261
262     hdc = BeginPaint(hWnd, &ps);
263
264     /* Only paint the Navigation pane, identified by the fact
265      * that it has a child window
266      */
267     if (GetWindow(hWnd, GW_CHILD))
268     {
269         GetClientRect(hWnd, &rc);
270
271         /* set the border color */
272         SelectObject(hdc, GetStockObject(DC_PEN));
273         SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
274
275         /* Draw the top border */
276         LineTo(hdc, rc.right, 0);
277
278         SelectObject(hdc, GetStockObject(WHITE_PEN));
279         MoveToEx(hdc, 0, 1, NULL);
280         LineTo(hdc, rc.right, 1);
281     }
282
283     EndPaint(hWnd, &ps);
284
285     return 0;
286 }
287
288 static LRESULT Child_OnSize(HWND hwnd)
289 {
290     HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
291     RECT rect;
292
293     if(!info || hwnd != info->WinType.hwndNavigation)
294         return 0;
295
296     GetClientRect(hwnd, &rect);
297     SetWindowPos(info->hwndTabCtrl, HWND_TOP, 0, 0,
298                  rect.right - TAB_RIGHT_PADDING,
299                  rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
300     return 0;
301 }
302
303 static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
304 {
305     switch (message)
306     {
307     case WM_PAINT:
308         return Child_OnPaint(hWnd);
309     case WM_SIZE:
310         return Child_OnSize(hWnd);
311     default:
312         return DefWindowProcW(hWnd, message, wParam, lParam);
313     }
314
315     return 0;
316 }
317
318 static void HH_RegisterChildWndClass(HHInfo *pHHInfo)
319 {
320     WNDCLASSEXW wcex;
321
322     wcex.cbSize         = sizeof(WNDCLASSEXW);
323     wcex.style          = 0;
324     wcex.lpfnWndProc    = Child_WndProc;
325     wcex.cbClsExtra     = 0;
326     wcex.cbWndExtra     = 0;
327     wcex.hInstance      = hhctrl_hinstance;
328     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
329     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
330     wcex.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
331     wcex.lpszMenuName   = NULL;
332     wcex.lpszClassName  = szChildClass;
333     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
334
335     RegisterClassExW(&wcex);
336 }
337
338 /* Toolbar */
339
340 #define ICON_SIZE   20
341
342 static void TB_OnClick(HWND hWnd, DWORD dwID)
343 {
344     HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
345
346     switch (dwID)
347     {
348         case IDTB_STOP:
349             DoPageAction(info, WB_STOP);
350             break;
351         case IDTB_REFRESH:
352             DoPageAction(info, WB_REFRESH);
353             break;
354         case IDTB_BACK:
355             DoPageAction(info, WB_GOBACK);
356             break;
357         case IDTB_HOME:
358             NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome);
359             break;
360         case IDTB_FORWARD:
361             DoPageAction(info, WB_GOFORWARD);
362             break;
363         case IDTB_EXPAND:
364         case IDTB_CONTRACT:
365         case IDTB_SYNC:
366         case IDTB_PRINT:
367         case IDTB_OPTIONS:
368         case IDTB_BROWSE_FWD:
369         case IDTB_BROWSE_BACK:
370         case IDTB_JUMP1:
371         case IDTB_JUMP2:
372         case IDTB_CUSTOMIZE:
373         case IDTB_ZOOM:
374         case IDTB_TOC_NEXT:
375         case IDTB_TOC_PREV:
376             break;
377     }
378 }
379
380 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
381 {
382     /* FIXME: Load the correct button bitmaps */
383     pButtons[dwIndex].iBitmap = STD_PRINT;
384     pButtons[dwIndex].idCommand = dwID;
385     pButtons[dwIndex].fsState = TBSTATE_ENABLED;
386     pButtons[dwIndex].fsStyle = BTNS_BUTTON;
387     pButtons[dwIndex].dwData = 0;
388     pButtons[dwIndex].iString = 0;
389 }
390
391 static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
392 {
393     *pdwNumButtons = 0;
394
395     if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
396         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
397
398     if (dwButtonFlags & HHWIN_BUTTON_BACK)
399         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
400
401     if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
402         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
403
404     if (dwButtonFlags & HHWIN_BUTTON_STOP)
405         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
406
407     if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
408         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
409
410     if (dwButtonFlags & HHWIN_BUTTON_HOME)
411         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
412
413     if (dwButtonFlags & HHWIN_BUTTON_SYNC)
414         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
415
416     if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
417         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
418
419     if (dwButtonFlags & HHWIN_BUTTON_PRINT)
420         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
421
422     if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
423         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
424
425     if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
426         TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
427
428     if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
429         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
430
431     if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
432         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
433
434     if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
435         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
436 }
437
438 static BOOL HH_AddToolbar(HHInfo *pHHInfo)
439 {
440     HWND hToolbar;
441     HWND hwndParent = pHHInfo->WinType.hwndHelp;
442     DWORD toolbarFlags;
443     TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
444     TBADDBITMAP tbAB;
445     DWORD dwStyles, dwExStyles;
446     DWORD dwNumButtons, dwIndex;
447
448     if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS)
449         toolbarFlags = pHHInfo->WinType.fsToolBarFlags;
450     else
451         toolbarFlags = HHWIN_DEF_BUTTONS;
452
453     TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
454
455     dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
456                TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
457     dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
458
459     hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
460                                0, 0, 0, 0, hwndParent, NULL,
461                                hhctrl_hinstance, NULL);
462     if (!hToolbar)
463         return FALSE;
464
465     SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
466     SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
467     SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
468
469     /* FIXME: Load correct icons for all buttons */
470     tbAB.hInst = HINST_COMMCTRL;
471     tbAB.nID = IDB_STD_LARGE_COLOR;
472     SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
473
474     for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
475     {
476         LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand);
477         DWORD dwLen = strlenW(szBuf);
478         szBuf[dwLen + 2] = 0; /* Double-null terminate */
479
480         buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf);
481         hhctrl_free(szBuf);
482     }
483
484     SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)&buttons);
485     SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
486     ShowWindow(hToolbar, SW_SHOW);
487
488     pHHInfo->WinType.hwndToolBar = hToolbar;
489     return TRUE;
490 }
491
492 /* Navigation Pane */
493
494 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc)
495 {
496     HWND hwndParent = pHHInfo->WinType.hwndHelp;
497     HWND hwndToolbar = pHHInfo->WinType.hwndToolBar;
498     RECT rectWND, rectTB;
499
500     GetClientRect(hwndParent, &rectWND);
501     GetClientRect(hwndToolbar, &rectTB);
502
503     rc->left = 0;
504     rc->top = rectTB.bottom;
505     rc->bottom = rectWND.bottom - rectTB.bottom;
506
507     if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) &&
508           pHHInfo->WinType.iNavWidth == 0)
509     {
510         pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH;
511     }
512
513     rc->right = pHHInfo->WinType.iNavWidth;
514 }
515
516 static void NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD dwStrID, DWORD dwIndex)
517 {
518     TCITEMW tie;
519     LPWSTR tabText = HH_LoadString(dwStrID);
520
521     tie.mask = TCIF_TEXT;
522     tie.pszText = tabText;
523
524     SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, dwIndex, (LPARAM)&tie );
525     hhctrl_free(tabText);
526 }
527
528 static BOOL HH_AddNavigationPane(HHInfo *info)
529 {
530     HWND hWnd, hwndTabCtrl;
531     HWND hwndParent = info->WinType.hwndHelp;
532     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
533     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
534     DWORD dwIndex = 0;
535     RECT rc;
536
537     NP_GetNavigationRect(info, &rc);
538
539     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
540                            rc.left, rc.top, rc.right, rc.bottom,
541                            hwndParent, NULL, hhctrl_hinstance, NULL);
542     if (!hWnd)
543         return FALSE;
544
545     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
546
547     hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
548                                   0, TAB_TOP_PADDING,
549                                   rc.right - TAB_RIGHT_PADDING,
550                                   rc.bottom - TAB_TOP_PADDING,
551                                   hWnd, NULL, hhctrl_hinstance, NULL);
552     if (!hwndTabCtrl)
553         return FALSE;
554
555     if (*info->WinType.pszToc)
556         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS, dwIndex++);
557
558     if (*info->WinType.pszIndex)
559         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX, dwIndex++);
560
561     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH)
562         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH, dwIndex++);
563
564     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES)
565         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES, dwIndex++);
566
567     SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE);
568
569     info->hwndTabCtrl = hwndTabCtrl;
570     info->WinType.hwndNavigation = hWnd;
571     return TRUE;
572 }
573
574 /* HTML Pane */
575
576 static void HP_GetHTMLRect(HHInfo *info, RECT *rc)
577 {
578     RECT rectTB, rectWND, rectNP, rectSB;
579
580     GetClientRect(info->WinType.hwndHelp, &rectWND);
581     GetClientRect(info->WinType.hwndToolBar, &rectTB);
582     GetClientRect(info->WinType.hwndNavigation, &rectNP);
583     GetClientRect(info->hwndSizeBar, &rectSB);
584
585     rc->left = rectNP.right + rectSB.right;
586     rc->top = rectTB.bottom;
587     rc->right = rectWND.right - rc->left;
588     rc->bottom = rectWND.bottom - rectTB.bottom;
589 }
590
591 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
592 {
593     HWND hWnd;
594     HWND hwndParent = pHHInfo->WinType.hwndHelp;
595     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
596     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE;
597     RECT rc;
598
599     HP_GetHTMLRect(pHHInfo, &rc);
600
601     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
602                            rc.left, rc.top, rc.right, rc.bottom,
603                            hwndParent, NULL, hhctrl_hinstance, NULL);
604     if (!hWnd)
605         return FALSE;
606
607     if (!InitWebBrowser(pHHInfo, hWnd))
608         return FALSE;
609
610     /* store the pointer to the HH info struct */
611     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
612
613     ShowWindow(hWnd, SW_SHOW);
614     UpdateWindow(hWnd);
615
616     pHHInfo->WinType.hwndHTML = hWnd;
617     return TRUE;
618 }
619
620 /* Viewer Window */
621
622 static LRESULT Help_OnSize(HWND hWnd)
623 {
624     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
625     DWORD dwSize;
626     RECT rc;
627
628     if (!pHHInfo)
629         return 0;
630
631     NP_GetNavigationRect(pHHInfo, &rc);
632     SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
633                  rc.right, rc.bottom, SWP_NOMOVE);
634
635     SB_GetSizeBarRect(pHHInfo, &rc);
636     SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
637                  rc.right, rc.bottom, SWP_SHOWWINDOW);
638
639     HP_GetHTMLRect(pHHInfo, &rc);
640     SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top,
641                  rc.right, rc.bottom, SWP_SHOWWINDOW);
642
643     /* Resize browser window taking the frame size into account */
644     dwSize = GetSystemMetrics(SM_CXFRAME);
645     ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize);
646
647     return 0;
648 }
649
650 static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
651 {
652     switch (message)
653     {
654     case WM_COMMAND:
655         if (HIWORD(wParam) == BN_CLICKED)
656             TB_OnClick(hWnd, LOWORD(wParam));
657         break;
658     case WM_SIZE:
659         return Help_OnSize(hWnd);
660     case WM_CLOSE:
661         ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA));
662         return 0;
663     case WM_DESTROY:
664         if(hh_process)
665             PostQuitMessage(0);
666         break;
667
668     default:
669         return DefWindowProcW(hWnd, message, wParam, lParam);
670     }
671
672     return 0;
673 }
674
675 static BOOL HH_CreateHelpWindow(HHInfo *info)
676 {
677     HWND hWnd;
678     RECT winPos = info->WinType.rcWindowPos;
679     WNDCLASSEXW wcex;
680     DWORD dwStyles, dwExStyles;
681     DWORD x, y, width, height;
682
683     static const WCHAR windowClassW[] = {
684         'H','H',' ', 'P','a','r','e','n','t',0
685     };
686
687     wcex.cbSize         = sizeof(WNDCLASSEXW);
688     wcex.style          = CS_HREDRAW | CS_VREDRAW;
689     wcex.lpfnWndProc    = Help_WndProc;
690     wcex.cbClsExtra     = 0;
691     wcex.cbWndExtra     = 0;
692     wcex.hInstance      = hhctrl_hinstance;
693     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
694     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
695     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
696     wcex.lpszMenuName   = NULL;
697     wcex.lpszClassName  = windowClassW;
698     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
699
700     RegisterClassExW(&wcex);
701
702     /* Read in window parameters if available */
703     if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES)
704         dwStyles = info->WinType.dwStyles;
705     else
706         dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE |
707                    WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
708
709     if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES)
710         dwExStyles = info->WinType.dwExStyles;
711     else
712         dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW |
713                      WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR;
714
715     if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT)
716     {
717         x = winPos.left;
718         y = winPos.top;
719         width = winPos.right - x;
720         height = winPos.bottom - y;
721     }
722     else
723     {
724         x = WINTYPE_DEFAULT_X;
725         y = WINTYPE_DEFAULT_Y;
726         width = WINTYPE_DEFAULT_WIDTH;
727         height = WINTYPE_DEFAULT_HEIGHT;
728     }
729
730     hWnd = CreateWindowExW(dwExStyles, windowClassW, info->WinType.pszCaption,
731                            dwStyles, x, y, width, height, NULL, NULL, hhctrl_hinstance, NULL);
732     if (!hWnd)
733         return FALSE;
734
735     ShowWindow(hWnd, SW_SHOW);
736     UpdateWindow(hWnd);
737
738     /* store the pointer to the HH info struct */
739     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
740
741     info->WinType.hwndHelp = hWnd;
742     return TRUE;
743 }
744
745 static void HH_CreateFont(HHInfo *pHHInfo)
746 {
747     LOGFONTW lf;
748
749     GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
750     lf.lfWeight = FW_NORMAL;
751     lf.lfItalic = FALSE;
752     lf.lfUnderline = FALSE;
753
754     pHHInfo->hFont = CreateFontIndirectW(&lf);
755 }
756
757 static void HH_InitRequiredControls(DWORD dwControls)
758 {
759     INITCOMMONCONTROLSEX icex;
760
761     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
762     icex.dwICC = dwControls;
763     InitCommonControlsEx(&icex);
764 }
765
766 /* Creates the whole package */
767 static BOOL CreateViewer(HHInfo *pHHInfo)
768 {
769     HH_CreateFont(pHHInfo);
770
771     if (!HH_CreateHelpWindow(pHHInfo))
772         return FALSE;
773
774     HH_InitRequiredControls(ICC_BAR_CLASSES);
775
776     if (!HH_AddToolbar(pHHInfo))
777         return FALSE;
778
779     HH_RegisterChildWndClass(pHHInfo);
780
781     if (!HH_AddNavigationPane(pHHInfo))
782         return FALSE;
783
784     HH_RegisterSizeBarClass(pHHInfo);
785
786     if (!HH_AddSizeBar(pHHInfo))
787         return FALSE;
788
789     if (!HH_AddHTMLPane(pHHInfo))
790         return FALSE;
791
792     return TRUE;
793 }
794
795 void ReleaseHelpViewer(HHInfo *info)
796 {
797     if (!info)
798         return;
799
800     /* Free allocated strings */
801     hhctrl_free((LPWSTR)info->WinType.pszType);
802     hhctrl_free((LPWSTR)info->WinType.pszCaption);
803     hhctrl_free((LPWSTR)info->WinType.pszToc);
804     hhctrl_free((LPWSTR)info->WinType.pszIndex);
805     hhctrl_free((LPWSTR)info->WinType.pszFile);
806     hhctrl_free((LPWSTR)info->WinType.pszHome);
807     hhctrl_free((LPWSTR)info->WinType.pszJump1);
808     hhctrl_free((LPWSTR)info->WinType.pszJump2);
809     hhctrl_free((LPWSTR)info->WinType.pszUrlJump1);
810     hhctrl_free((LPWSTR)info->WinType.pszUrlJump2);
811
812     if (info->pCHMInfo)
813         CloseCHM(info->pCHMInfo);
814
815     ReleaseWebBrowser(info);
816
817     if(info->WinType.hwndHelp)
818         DestroyWindow(info->WinType.hwndHelp);
819
820     hhctrl_free(info);
821     OleUninitialize();
822 }
823
824 HHInfo *CreateHelpViewer(LPCWSTR filename)
825 {
826     HHInfo *info = hhctrl_alloc_zero(sizeof(HHInfo));
827
828     OleInitialize(NULL);
829
830     info->pCHMInfo = OpenCHM(filename);
831     if(!info->pCHMInfo) {
832         ReleaseHelpViewer(info);
833         return NULL;
834     }
835
836     if (!LoadWinTypeFromCHM(info->pCHMInfo, &info->WinType)) {
837         ReleaseHelpViewer(info);
838         return NULL;
839     }
840
841     if(!CreateViewer(info)) {
842         ReleaseHelpViewer(info);
843         return NULL;
844     }
845
846     return info;
847 }