winealsa.drv: Don't return garbage if can't find active channel.
[wine/multimedia.git] / dlls / hhctrl.ocx / help.c
blobc49d3cff0927eae8cf1fe50849a83dc6133cae37
1 /*
2 * Help Viewer Implementation
4 * Copyright 2005 James Hawkins
5 * Copyright 2007 Jacek Caban for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "hhctrl.h"
24 #include "wingdi.h"
25 #include "commctrl.h"
26 #include "wininet.h"
28 #include "wine/debug.h"
30 #include "resource.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
34 static LRESULT Help_OnSize(HWND hWnd);
36 /* Window type defaults */
38 #define WINTYPE_DEFAULT_X 280
39 #define WINTYPE_DEFAULT_Y 100
40 #define WINTYPE_DEFAULT_WIDTH 740
41 #define WINTYPE_DEFAULT_HEIGHT 640
42 #define WINTYPE_DEFAULT_NAVWIDTH 250
44 #define TAB_TOP_PADDING 8
45 #define TAB_RIGHT_PADDING 4
46 #define TAB_MARGIN 8
48 static const WCHAR szEmpty[] = {0};
50 /* Loads a string from the resource file */
51 static LPWSTR HH_LoadString(DWORD dwID)
53 LPWSTR string = NULL;
54 int iSize;
56 iSize = LoadStringW(hhctrl_hinstance, dwID, NULL, 0);
57 iSize += 2; /* some strings (tab text) needs double-null termination */
59 string = heap_alloc(iSize * sizeof(WCHAR));
60 LoadStringW(hhctrl_hinstance, dwID, string, iSize);
62 return string;
65 static HRESULT navigate_url(HHInfo *info, LPCWSTR surl)
67 VARIANT url;
68 HRESULT hres;
70 TRACE("%s\n", debugstr_w(surl));
72 V_VT(&url) = VT_BSTR;
73 V_BSTR(&url) = SysAllocString(surl);
75 hres = IWebBrowser2_Navigate2(info->web_browser, &url, 0, 0, 0, 0);
77 VariantClear(&url);
79 if(FAILED(hres))
80 TRACE("Navigation failed: %08x\n", hres);
82 return hres;
85 BOOL NavigateToUrl(HHInfo *info, LPCWSTR surl)
87 ChmPath chm_path;
88 BOOL ret;
89 HRESULT hres;
91 hres = navigate_url(info, surl);
92 if(SUCCEEDED(hres))
93 return TRUE;
95 SetChmPath(&chm_path, info->pCHMInfo->szFile, surl);
96 ret = NavigateToChm(info, chm_path.chm_file, chm_path.chm_index);
98 heap_free(chm_path.chm_file);
99 heap_free(chm_path.chm_index);
101 return ret;
104 BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
106 WCHAR buf[INTERNET_MAX_URL_LENGTH];
107 WCHAR full_path[MAX_PATH];
108 LPWSTR ptr;
110 static const WCHAR url_format[] =
111 {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s',0};
113 TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
115 if (!info->web_browser)
116 return FALSE;
118 if(!GetFullPathNameW(file, sizeof(full_path), full_path, NULL)) {
119 WARN("GetFullPathName failed: %u\n", GetLastError());
120 return FALSE;
123 wsprintfW(buf, url_format, full_path, index);
125 /* FIXME: HACK */
126 if((ptr = strchrW(buf, '#')))
127 *ptr = 0;
129 return SUCCEEDED(navigate_url(info, buf));
132 /* Size Bar */
134 #define SIZEBAR_WIDTH 4
136 static const WCHAR szSizeBarClass[] = {
137 'H','H',' ','S','i','z','e','B','a','r',0
140 /* Draw the SizeBar */
141 static void SB_OnPaint(HWND hWnd)
143 PAINTSTRUCT ps;
144 HDC hdc;
145 RECT rc;
147 hdc = BeginPaint(hWnd, &ps);
149 GetClientRect(hWnd, &rc);
151 /* dark frame */
152 rc.right += 1;
153 rc.bottom -= 1;
154 FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH));
156 /* white highlight */
157 SelectObject(hdc, GetStockObject(WHITE_PEN));
158 MoveToEx(hdc, rc.right, 1, NULL);
159 LineTo(hdc, 1, 1);
160 LineTo(hdc, 1, rc.bottom - 1);
163 MoveToEx(hdc, 0, rc.bottom, NULL);
164 LineTo(hdc, rc.right, rc.bottom);
166 EndPaint(hWnd, &ps);
169 static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
171 SetCapture(hWnd);
174 static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
176 HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
177 POINT pt;
179 pt.x = (short)LOWORD(lParam);
180 pt.y = (short)HIWORD(lParam);
182 /* update the window sizes */
183 pHHInfo->WinType.iNavWidth += pt.x;
184 Help_OnSize(hWnd);
186 ReleaseCapture();
189 static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
191 /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
192 if (!(wParam & MK_LBUTTON))
193 return;
196 static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
198 switch (message)
200 case WM_LBUTTONDOWN:
201 SB_OnLButtonDown(hWnd, wParam, lParam);
202 break;
203 case WM_LBUTTONUP:
204 SB_OnLButtonUp(hWnd, wParam, lParam);
205 break;
206 case WM_MOUSEMOVE:
207 SB_OnMouseMove(hWnd, wParam, lParam);
208 break;
209 case WM_PAINT:
210 SB_OnPaint(hWnd);
211 break;
212 default:
213 return DefWindowProcW(hWnd, message, wParam, lParam);
216 return 0;
219 static void HH_RegisterSizeBarClass(HHInfo *pHHInfo)
221 WNDCLASSEXW wcex;
223 wcex.cbSize = sizeof(WNDCLASSEXW);
224 wcex.style = 0;
225 wcex.lpfnWndProc = SizeBar_WndProc;
226 wcex.cbClsExtra = 0;
227 wcex.cbWndExtra = 0;
228 wcex.hInstance = hhctrl_hinstance;
229 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
230 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE);
231 wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
232 wcex.lpszMenuName = NULL;
233 wcex.lpszClassName = szSizeBarClass;
234 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
236 RegisterClassExW(&wcex);
239 static void SB_GetSizeBarRect(HHInfo *info, RECT *rc)
241 RECT rectWND, rectTB, rectNP;
243 GetClientRect(info->WinType.hwndHelp, &rectWND);
244 GetClientRect(info->WinType.hwndToolBar, &rectTB);
245 GetClientRect(info->WinType.hwndNavigation, &rectNP);
247 rc->left = rectNP.right;
248 rc->top = rectTB.bottom;
249 rc->bottom = rectWND.bottom - rectTB.bottom;
250 rc->right = SIZEBAR_WIDTH;
253 static BOOL HH_AddSizeBar(HHInfo *pHHInfo)
255 HWND hWnd;
256 HWND hwndParent = pHHInfo->WinType.hwndHelp;
257 DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_OVERLAPPED;
258 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
259 RECT rc;
261 SB_GetSizeBarRect(pHHInfo, &rc);
263 hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles,
264 rc.left, rc.top, rc.right, rc.bottom,
265 hwndParent, NULL, hhctrl_hinstance, NULL);
266 if (!hWnd)
267 return FALSE;
269 /* store the pointer to the HH info struct */
270 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
272 pHHInfo->hwndSizeBar = hWnd;
273 return TRUE;
276 /* Child Window */
278 static const WCHAR szChildClass[] = {
279 'H','H',' ','C','h','i','l','d',0
282 static LRESULT Child_OnPaint(HWND hWnd)
284 PAINTSTRUCT ps;
285 HDC hdc;
286 RECT rc;
288 hdc = BeginPaint(hWnd, &ps);
290 /* Only paint the Navigation pane, identified by the fact
291 * that it has a child window
293 if (GetWindow(hWnd, GW_CHILD))
295 GetClientRect(hWnd, &rc);
297 /* set the border color */
298 SelectObject(hdc, GetStockObject(DC_PEN));
299 SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
301 /* Draw the top border */
302 LineTo(hdc, rc.right, 0);
304 SelectObject(hdc, GetStockObject(WHITE_PEN));
305 MoveToEx(hdc, 0, 1, NULL);
306 LineTo(hdc, rc.right, 1);
309 EndPaint(hWnd, &ps);
311 return 0;
314 static void ResizeTabChild(HHInfo *info, HWND hwnd)
316 RECT rect, tabrc;
317 DWORD cnt;
319 GetClientRect(info->WinType.hwndNavigation, &rect);
320 SendMessageW(info->hwndTabCtrl, TCM_GETITEMRECT, 0, (LPARAM)&tabrc);
321 cnt = SendMessageW(info->hwndTabCtrl, TCM_GETROWCOUNT, 0, 0);
323 rect.left = TAB_MARGIN;
324 rect.top = TAB_TOP_PADDING + cnt*(tabrc.bottom-tabrc.top) + TAB_MARGIN;
325 rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN;
326 rect.bottom -= TAB_MARGIN;
328 SetWindowPos(hwnd, NULL, rect.left, rect.top, rect.right-rect.left,
329 rect.bottom-rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
332 static LRESULT Child_OnSize(HWND hwnd)
334 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
335 RECT rect;
337 if(!info || hwnd != info->WinType.hwndNavigation)
338 return 0;
340 GetClientRect(hwnd, &rect);
341 SetWindowPos(info->hwndTabCtrl, HWND_TOP, 0, 0,
342 rect.right - TAB_RIGHT_PADDING,
343 rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
345 ResizeTabChild(info, info->tabs[TAB_CONTENTS].hwnd);
346 return 0;
349 static LRESULT OnTabChange(HWND hwnd)
351 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
353 TRACE("%p\n", hwnd);
355 if (!info)
356 return 0;
358 if(info->tabs[info->current_tab].hwnd)
359 ShowWindow(info->tabs[info->current_tab].hwnd, SW_HIDE);
361 info->current_tab = SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0);
363 if(info->tabs[info->current_tab].hwnd)
364 ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW);
366 return 0;
369 static LRESULT OnTopicChange(HWND hwnd, ContentItem *item)
371 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
372 LPCWSTR chmfile = NULL;
373 ContentItem *iter = item;
375 if(!item || !info)
376 return 0;
378 TRACE("name %s loal %s\n", debugstr_w(item->name), debugstr_w(item->local));
380 while(iter) {
381 if(iter->merge.chm_file) {
382 chmfile = iter->merge.chm_file;
383 break;
385 iter = iter->parent;
388 NavigateToChm(info, chmfile, item->local);
389 return 0;
392 static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
394 switch (message)
396 case WM_PAINT:
397 return Child_OnPaint(hWnd);
398 case WM_SIZE:
399 return Child_OnSize(hWnd);
400 case WM_NOTIFY: {
401 NMHDR *nmhdr = (NMHDR*)lParam;
402 switch(nmhdr->code) {
403 case TCN_SELCHANGE:
404 return OnTabChange(hWnd);
405 case TVN_SELCHANGEDW:
406 return OnTopicChange(hWnd, (ContentItem*)((NMTREEVIEWW *)lParam)->itemNew.lParam);
408 break;
410 default:
411 return DefWindowProcW(hWnd, message, wParam, lParam);
414 return 0;
417 static void HH_RegisterChildWndClass(HHInfo *pHHInfo)
419 WNDCLASSEXW wcex;
421 wcex.cbSize = sizeof(WNDCLASSEXW);
422 wcex.style = 0;
423 wcex.lpfnWndProc = Child_WndProc;
424 wcex.cbClsExtra = 0;
425 wcex.cbWndExtra = 0;
426 wcex.hInstance = hhctrl_hinstance;
427 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
428 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
429 wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
430 wcex.lpszMenuName = NULL;
431 wcex.lpszClassName = szChildClass;
432 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
434 RegisterClassExW(&wcex);
437 /* Toolbar */
439 #define ICON_SIZE 20
441 static void TB_OnClick(HWND hWnd, DWORD dwID)
443 HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
445 switch (dwID)
447 case IDTB_STOP:
448 DoPageAction(info, WB_STOP);
449 break;
450 case IDTB_REFRESH:
451 DoPageAction(info, WB_REFRESH);
452 break;
453 case IDTB_BACK:
454 DoPageAction(info, WB_GOBACK);
455 break;
456 case IDTB_HOME:
457 NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome);
458 break;
459 case IDTB_FORWARD:
460 DoPageAction(info, WB_GOFORWARD);
461 break;
462 case IDTB_EXPAND:
463 case IDTB_CONTRACT:
464 case IDTB_SYNC:
465 case IDTB_PRINT:
466 case IDTB_OPTIONS:
467 case IDTB_BROWSE_FWD:
468 case IDTB_BROWSE_BACK:
469 case IDTB_JUMP1:
470 case IDTB_JUMP2:
471 case IDTB_CUSTOMIZE:
472 case IDTB_ZOOM:
473 case IDTB_TOC_NEXT:
474 case IDTB_TOC_PREV:
475 break;
479 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
481 /* FIXME: Load the correct button bitmaps */
482 pButtons[dwIndex].iBitmap = STD_PRINT;
483 pButtons[dwIndex].idCommand = dwID;
484 pButtons[dwIndex].fsState = TBSTATE_ENABLED;
485 pButtons[dwIndex].fsStyle = BTNS_BUTTON;
486 pButtons[dwIndex].dwData = 0;
487 pButtons[dwIndex].iString = 0;
490 static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
492 *pdwNumButtons = 0;
494 if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
495 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
497 if (dwButtonFlags & HHWIN_BUTTON_BACK)
498 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
500 if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
501 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
503 if (dwButtonFlags & HHWIN_BUTTON_STOP)
504 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
506 if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
507 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
509 if (dwButtonFlags & HHWIN_BUTTON_HOME)
510 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
512 if (dwButtonFlags & HHWIN_BUTTON_SYNC)
513 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
515 if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
516 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
518 if (dwButtonFlags & HHWIN_BUTTON_PRINT)
519 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
521 if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
522 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
524 if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
525 TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
527 if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
528 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
530 if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
531 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
533 if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
534 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
537 static BOOL HH_AddToolbar(HHInfo *pHHInfo)
539 HWND hToolbar;
540 HWND hwndParent = pHHInfo->WinType.hwndHelp;
541 DWORD toolbarFlags;
542 TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
543 TBADDBITMAP tbAB;
544 DWORD dwStyles, dwExStyles;
545 DWORD dwNumButtons, dwIndex;
547 if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS)
548 toolbarFlags = pHHInfo->WinType.fsToolBarFlags;
549 else
550 toolbarFlags = HHWIN_DEF_BUTTONS;
552 TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
554 dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
555 TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
556 dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
558 hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
559 0, 0, 0, 0, hwndParent, NULL,
560 hhctrl_hinstance, NULL);
561 if (!hToolbar)
562 return FALSE;
564 SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
565 SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
566 SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
568 /* FIXME: Load correct icons for all buttons */
569 tbAB.hInst = HINST_COMMCTRL;
570 tbAB.nID = IDB_STD_LARGE_COLOR;
571 SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
573 for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
575 LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand);
576 DWORD dwLen = strlenW(szBuf);
577 szBuf[dwLen + 2] = 0; /* Double-null terminate */
579 buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf);
580 heap_free(szBuf);
583 SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)&buttons);
584 SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
585 ShowWindow(hToolbar, SW_SHOW);
587 pHHInfo->WinType.hwndToolBar = hToolbar;
588 return TRUE;
591 /* Navigation Pane */
593 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc)
595 HWND hwndParent = pHHInfo->WinType.hwndHelp;
596 HWND hwndToolbar = pHHInfo->WinType.hwndToolBar;
597 RECT rectWND, rectTB;
599 GetClientRect(hwndParent, &rectWND);
600 GetClientRect(hwndToolbar, &rectTB);
602 rc->left = 0;
603 rc->top = rectTB.bottom;
604 rc->bottom = rectWND.bottom - rectTB.bottom;
606 if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) &&
607 pHHInfo->WinType.iNavWidth == 0)
609 pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH;
612 rc->right = pHHInfo->WinType.iNavWidth;
615 static DWORD NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD index)
617 TCITEMW tie;
618 LPWSTR tabText = HH_LoadString(index);
619 DWORD ret;
621 tie.mask = TCIF_TEXT;
622 tie.pszText = tabText;
624 ret = SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, index, (LPARAM)&tie );
626 heap_free(tabText);
627 return ret;
630 static BOOL HH_AddNavigationPane(HHInfo *info)
632 HWND hWnd, hwndTabCtrl;
633 HWND hwndParent = info->WinType.hwndHelp;
634 DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
635 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
636 RECT rc;
638 NP_GetNavigationRect(info, &rc);
640 hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
641 rc.left, rc.top, rc.right, rc.bottom,
642 hwndParent, NULL, hhctrl_hinstance, NULL);
643 if (!hWnd)
644 return FALSE;
646 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
648 hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
649 0, TAB_TOP_PADDING,
650 rc.right - TAB_RIGHT_PADDING,
651 rc.bottom - TAB_TOP_PADDING,
652 hWnd, NULL, hhctrl_hinstance, NULL);
653 if (!hwndTabCtrl)
654 return FALSE;
656 if (*info->WinType.pszToc)
657 info->tabs[TAB_CONTENTS].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS);
659 if (*info->WinType.pszIndex)
660 info->tabs[TAB_INDEX].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX);
662 if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH)
663 info->tabs[TAB_SEARCH].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH);
665 if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES)
666 info->tabs[TAB_FAVORITES].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES);
668 SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE);
670 info->hwndTabCtrl = hwndTabCtrl;
671 info->WinType.hwndNavigation = hWnd;
672 return TRUE;
675 /* HTML Pane */
677 static void HP_GetHTMLRect(HHInfo *info, RECT *rc)
679 RECT rectTB, rectWND, rectNP, rectSB;
681 GetClientRect(info->WinType.hwndHelp, &rectWND);
682 GetClientRect(info->WinType.hwndToolBar, &rectTB);
683 GetClientRect(info->WinType.hwndNavigation, &rectNP);
684 GetClientRect(info->hwndSizeBar, &rectSB);
686 rc->left = rectNP.right + rectSB.right;
687 rc->top = rectTB.bottom;
688 rc->right = rectWND.right - rc->left;
689 rc->bottom = rectWND.bottom - rectTB.bottom;
692 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
694 HWND hWnd;
695 HWND hwndParent = pHHInfo->WinType.hwndHelp;
696 DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
697 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE;
698 RECT rc;
700 HP_GetHTMLRect(pHHInfo, &rc);
702 hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
703 rc.left, rc.top, rc.right, rc.bottom,
704 hwndParent, NULL, hhctrl_hinstance, NULL);
705 if (!hWnd)
706 return FALSE;
708 if (!InitWebBrowser(pHHInfo, hWnd))
709 return FALSE;
711 /* store the pointer to the HH info struct */
712 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
714 ShowWindow(hWnd, SW_SHOW);
715 UpdateWindow(hWnd);
717 pHHInfo->WinType.hwndHTML = hWnd;
718 return TRUE;
721 static BOOL AddContentTab(HHInfo *info)
723 info->tabs[TAB_CONTENTS].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW,
724 szEmpty, WS_CHILD | WS_BORDER | 0x25, 50, 50, 100, 100,
725 info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
726 if(!info->tabs[TAB_CONTENTS].hwnd) {
727 ERR("Could not create treeview control\n");
728 return FALSE;
731 ResizeTabChild(info, info->tabs[TAB_CONTENTS].hwnd);
732 ShowWindow(info->tabs[TAB_CONTENTS].hwnd, SW_SHOW);
734 return TRUE;
737 /* Viewer Window */
739 static LRESULT Help_OnSize(HWND hWnd)
741 HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
742 DWORD dwSize;
743 RECT rc;
745 if (!pHHInfo)
746 return 0;
748 NP_GetNavigationRect(pHHInfo, &rc);
749 SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
750 rc.right, rc.bottom, SWP_NOMOVE);
752 SB_GetSizeBarRect(pHHInfo, &rc);
753 SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
754 rc.right, rc.bottom, SWP_SHOWWINDOW);
756 HP_GetHTMLRect(pHHInfo, &rc);
757 SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top,
758 rc.right, rc.bottom, SWP_SHOWWINDOW);
760 /* Resize browser window taking the frame size into account */
761 dwSize = GetSystemMetrics(SM_CXFRAME);
762 ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize);
764 return 0;
767 static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
769 switch (message)
771 case WM_COMMAND:
772 if (HIWORD(wParam) == BN_CLICKED)
773 TB_OnClick(hWnd, LOWORD(wParam));
774 break;
775 case WM_SIZE:
776 return Help_OnSize(hWnd);
777 case WM_CLOSE:
778 ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA));
779 return 0;
780 case WM_DESTROY:
781 if(hh_process)
782 PostQuitMessage(0);
783 break;
785 default:
786 return DefWindowProcW(hWnd, message, wParam, lParam);
789 return 0;
792 static BOOL HH_CreateHelpWindow(HHInfo *info)
794 HWND hWnd;
795 RECT winPos = info->WinType.rcWindowPos;
796 WNDCLASSEXW wcex;
797 DWORD dwStyles, dwExStyles;
798 DWORD x, y, width, height;
800 static const WCHAR windowClassW[] = {
801 'H','H',' ', 'P','a','r','e','n','t',0
804 wcex.cbSize = sizeof(WNDCLASSEXW);
805 wcex.style = CS_HREDRAW | CS_VREDRAW;
806 wcex.lpfnWndProc = Help_WndProc;
807 wcex.cbClsExtra = 0;
808 wcex.cbWndExtra = 0;
809 wcex.hInstance = hhctrl_hinstance;
810 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
811 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
812 wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
813 wcex.lpszMenuName = NULL;
814 wcex.lpszClassName = windowClassW;
815 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
817 RegisterClassExW(&wcex);
819 /* Read in window parameters if available */
820 if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES)
821 dwStyles = info->WinType.dwStyles;
822 else
823 dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE |
824 WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
826 if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES)
827 dwExStyles = info->WinType.dwExStyles;
828 else
829 dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW |
830 WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR;
832 if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT)
834 x = winPos.left;
835 y = winPos.top;
836 width = winPos.right - x;
837 height = winPos.bottom - y;
839 else
841 x = WINTYPE_DEFAULT_X;
842 y = WINTYPE_DEFAULT_Y;
843 width = WINTYPE_DEFAULT_WIDTH;
844 height = WINTYPE_DEFAULT_HEIGHT;
847 hWnd = CreateWindowExW(dwExStyles, windowClassW, info->WinType.pszCaption,
848 dwStyles, x, y, width, height, NULL, NULL, hhctrl_hinstance, NULL);
849 if (!hWnd)
850 return FALSE;
852 ShowWindow(hWnd, SW_SHOW);
853 UpdateWindow(hWnd);
855 /* store the pointer to the HH info struct */
856 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
858 info->WinType.hwndHelp = hWnd;
859 return TRUE;
862 static void HH_CreateFont(HHInfo *pHHInfo)
864 LOGFONTW lf;
866 GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
867 lf.lfWeight = FW_NORMAL;
868 lf.lfItalic = FALSE;
869 lf.lfUnderline = FALSE;
871 pHHInfo->hFont = CreateFontIndirectW(&lf);
874 static void HH_InitRequiredControls(DWORD dwControls)
876 INITCOMMONCONTROLSEX icex;
878 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
879 icex.dwICC = dwControls;
880 InitCommonControlsEx(&icex);
883 /* Creates the whole package */
884 static BOOL CreateViewer(HHInfo *pHHInfo)
886 HH_CreateFont(pHHInfo);
888 if (!HH_CreateHelpWindow(pHHInfo))
889 return FALSE;
891 HH_InitRequiredControls(ICC_BAR_CLASSES);
893 if (!HH_AddToolbar(pHHInfo))
894 return FALSE;
896 HH_RegisterChildWndClass(pHHInfo);
898 if (!HH_AddNavigationPane(pHHInfo))
899 return FALSE;
901 HH_RegisterSizeBarClass(pHHInfo);
903 if (!HH_AddSizeBar(pHHInfo))
904 return FALSE;
906 if (!HH_AddHTMLPane(pHHInfo))
907 return FALSE;
909 if (!AddContentTab(pHHInfo))
910 return FALSE;
912 InitContent(pHHInfo);
914 return TRUE;
917 void ReleaseHelpViewer(HHInfo *info)
919 TRACE("(%p)\n", info);
921 if (!info)
922 return;
924 /* Free allocated strings */
925 heap_free(info->pszType);
926 heap_free(info->pszCaption);
927 heap_free(info->pszToc);
928 heap_free(info->pszIndex);
929 heap_free(info->pszFile);
930 heap_free(info->pszHome);
931 heap_free(info->pszJump1);
932 heap_free(info->pszJump2);
933 heap_free(info->pszUrlJump1);
934 heap_free(info->pszUrlJump2);
936 if (info->pCHMInfo)
937 CloseCHM(info->pCHMInfo);
939 ReleaseWebBrowser(info);
940 ReleaseContent(info);
942 if(info->WinType.hwndHelp)
943 DestroyWindow(info->WinType.hwndHelp);
945 heap_free(info);
946 OleUninitialize();
949 HHInfo *CreateHelpViewer(LPCWSTR filename)
951 HHInfo *info = heap_alloc_zero(sizeof(HHInfo));
953 OleInitialize(NULL);
955 info->pCHMInfo = OpenCHM(filename);
956 if(!info->pCHMInfo) {
957 ReleaseHelpViewer(info);
958 return NULL;
961 if (!LoadWinTypeFromCHM(info)) {
962 ReleaseHelpViewer(info);
963 return NULL;
966 if(!CreateViewer(info)) {
967 ReleaseHelpViewer(info);
968 return NULL;
971 return info;