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
28 #include "wine/debug.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
48 static const WCHAR szEmpty
[] = {0};
50 /* Loads a string from the resource file */
51 static LPWSTR
HH_LoadString(DWORD dwID
)
54 LPCWSTR stringresource
;
57 iSize
= LoadStringW(hhctrl_hinstance
, dwID
, (LPWSTR
)&stringresource
, 0);
59 string
= heap_alloc((iSize
+ 2) * sizeof(WCHAR
)); /* some strings (tab text) needs double-null termination */
60 memcpy(string
, stringresource
, iSize
*sizeof(WCHAR
));
66 static HRESULT
navigate_url(HHInfo
*info
, LPCWSTR surl
)
71 TRACE("%s\n", debugstr_w(surl
));
74 V_BSTR(&url
) = SysAllocString(surl
);
76 hres
= IWebBrowser2_Navigate2(info
->web_browser
, &url
, 0, 0, 0, 0);
81 TRACE("Navigation failed: %08x\n", hres
);
86 BOOL
NavigateToUrl(HHInfo
*info
, LPCWSTR surl
)
92 static const WCHAR url_indicator
[] = {':', '/', '/', 0};
94 TRACE("%s\n", debugstr_w(surl
));
96 if (strstrW(surl
, url_indicator
)) {
97 hres
= navigate_url(info
, surl
);
100 } /* look up in chm if it doesn't look like a full url */
102 SetChmPath(&chm_path
, info
->pCHMInfo
->szFile
, surl
);
103 ret
= NavigateToChm(info
, chm_path
.chm_file
, chm_path
.chm_index
);
105 heap_free(chm_path
.chm_file
);
106 heap_free(chm_path
.chm_index
);
111 BOOL
NavigateToChm(HHInfo
*info
, LPCWSTR file
, LPCWSTR index
)
113 WCHAR buf
[INTERNET_MAX_URL_LENGTH
];
114 WCHAR full_path
[MAX_PATH
];
117 static const WCHAR url_format
[] =
118 {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0};
119 static const WCHAR slash
[] = {'/',0};
120 static const WCHAR empty
[] = {0};
122 TRACE("%p %s %s\n", info
, debugstr_w(file
), debugstr_w(index
));
124 if (!info
->web_browser
)
127 if(!GetFullPathNameW(file
, sizeof(full_path
)/sizeof(full_path
[0]), full_path
, NULL
)) {
128 WARN("GetFullPathName failed: %u\n", GetLastError());
132 wsprintfW(buf
, url_format
, full_path
, (!index
|| index
[0] == '/') ? empty
: slash
, index
);
135 if((ptr
= strchrW(buf
, '#')))
138 return SUCCEEDED(navigate_url(info
, buf
));
143 #define SIZEBAR_WIDTH 4
145 static const WCHAR szSizeBarClass
[] = {
146 'H','H',' ','S','i','z','e','B','a','r',0
149 /* Draw the SizeBar */
150 static void SB_OnPaint(HWND hWnd
)
156 hdc
= BeginPaint(hWnd
, &ps
);
158 GetClientRect(hWnd
, &rc
);
163 FrameRect(hdc
, &rc
, GetStockObject(GRAY_BRUSH
));
165 /* white highlight */
166 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
167 MoveToEx(hdc
, rc
.right
, 1, NULL
);
169 LineTo(hdc
, 1, rc
.bottom
- 1);
172 MoveToEx(hdc
, 0, rc
.bottom
, NULL
);
173 LineTo(hdc
, rc
.right
, rc
.bottom
);
178 static void SB_OnLButtonDown(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
183 static void SB_OnLButtonUp(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
185 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
188 pt
.x
= (short)LOWORD(lParam
);
189 pt
.y
= (short)HIWORD(lParam
);
191 /* update the window sizes */
192 pHHInfo
->WinType
.iNavWidth
+= pt
.x
;
198 static void SB_OnMouseMove(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
200 /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
201 if (!(wParam
& MK_LBUTTON
))
205 static LRESULT CALLBACK
SizeBar_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
210 SB_OnLButtonDown(hWnd
, wParam
, lParam
);
213 SB_OnLButtonUp(hWnd
, wParam
, lParam
);
216 SB_OnMouseMove(hWnd
, wParam
, lParam
);
222 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
228 static void HH_RegisterSizeBarClass(HHInfo
*pHHInfo
)
232 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
234 wcex
.lpfnWndProc
= SizeBar_WndProc
;
237 wcex
.hInstance
= hhctrl_hinstance
;
238 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
239 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_SIZEWE
);
240 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
241 wcex
.lpszMenuName
= NULL
;
242 wcex
.lpszClassName
= szSizeBarClass
;
243 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
245 RegisterClassExW(&wcex
);
248 static void SB_GetSizeBarRect(HHInfo
*info
, RECT
*rc
)
250 RECT rectWND
, rectTB
, rectNP
;
252 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
253 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
254 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
256 rc
->left
= rectNP
.right
;
257 rc
->top
= rectTB
.bottom
;
258 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
259 rc
->right
= SIZEBAR_WIDTH
;
262 static BOOL
HH_AddSizeBar(HHInfo
*pHHInfo
)
265 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
266 DWORD dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| WS_OVERLAPPED
;
267 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
270 SB_GetSizeBarRect(pHHInfo
, &rc
);
272 hWnd
= CreateWindowExW(dwExStyles
, szSizeBarClass
, szEmpty
, dwStyles
,
273 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
274 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
278 /* store the pointer to the HH info struct */
279 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)pHHInfo
);
281 pHHInfo
->hwndSizeBar
= hWnd
;
287 static const WCHAR szChildClass
[] = {
288 'H','H',' ','C','h','i','l','d',0
291 static LRESULT
Child_OnPaint(HWND hWnd
)
297 hdc
= BeginPaint(hWnd
, &ps
);
299 /* Only paint the Navigation pane, identified by the fact
300 * that it has a child window
302 if (GetWindow(hWnd
, GW_CHILD
))
304 GetClientRect(hWnd
, &rc
);
306 /* set the border color */
307 SelectObject(hdc
, GetStockObject(DC_PEN
));
308 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
310 /* Draw the top border */
311 LineTo(hdc
, rc
.right
, 0);
313 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
314 MoveToEx(hdc
, 0, 1, NULL
);
315 LineTo(hdc
, rc
.right
, 1);
323 static void ResizeTabChild(HHInfo
*info
, int tab
)
325 HWND hwnd
= info
->tabs
[tab
].hwnd
;
330 GetClientRect(info
->WinType
.hwndNavigation
, &rect
);
331 SendMessageW(info
->hwndTabCtrl
, TCM_GETITEMRECT
, 0, (LPARAM
)&tabrc
);
332 cnt
= SendMessageW(info
->hwndTabCtrl
, TCM_GETROWCOUNT
, 0, 0);
334 rect
.left
= TAB_MARGIN
;
335 rect
.top
= TAB_TOP_PADDING
+ cnt
*(tabrc
.bottom
-tabrc
.top
) + TAB_MARGIN
;
336 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
337 rect
.bottom
-= TAB_MARGIN
;
338 width
= rect
.right
-rect
.left
;
339 height
= rect
.bottom
-rect
.top
;
341 SetWindowPos(hwnd
, NULL
, rect
.left
, rect
.top
, width
, height
,
342 SWP_NOZORDER
| SWP_NOACTIVATE
);
344 /* Resize the tab widget column to perfectly fit the tab window and
345 * leave sufficient space for the scroll widget.
350 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
351 int border_width
= GetSystemMetrics(SM_CXBORDER
);
352 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
354 SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_SETCOLUMNWIDTH
, 0,
355 width
-scroll_width
-2*border_width
-2*edge_width
);
362 static LRESULT
Child_OnSize(HWND hwnd
)
364 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
367 if(!info
|| hwnd
!= info
->WinType
.hwndNavigation
)
370 GetClientRect(hwnd
, &rect
);
371 SetWindowPos(info
->hwndTabCtrl
, HWND_TOP
, 0, 0,
372 rect
.right
- TAB_RIGHT_PADDING
,
373 rect
.bottom
- TAB_TOP_PADDING
, SWP_NOMOVE
);
375 ResizeTabChild(info
, TAB_CONTENTS
);
376 ResizeTabChild(info
, TAB_INDEX
);
380 static LRESULT
OnTabChange(HWND hwnd
)
382 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
389 if(info
->tabs
[info
->current_tab
].hwnd
)
390 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_HIDE
);
392 info
->current_tab
= SendMessageW(info
->hwndTabCtrl
, TCM_GETCURSEL
, 0, 0);
394 if(info
->tabs
[info
->current_tab
].hwnd
)
395 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_SHOW
);
400 static LRESULT
OnTopicChange(HHInfo
*info
, void *user_data
)
402 LPCWSTR chmfile
= NULL
, name
= NULL
, local
= NULL
;
406 if(!user_data
|| !info
)
409 switch (info
->current_tab
)
412 citer
= (ContentItem
*) user_data
;
414 local
= citer
->local
;
416 if(citer
->merge
.chm_file
) {
417 chmfile
= citer
->merge
.chm_file
;
420 citer
= citer
->parent
;
424 iiter
= (IndexItem
*) user_data
;
425 if(iiter
->nItems
== 0) {
426 FIXME("No entries for this item!\n");
429 if(iiter
->nItems
> 1) {
433 SendMessageW(info
->popup
.hwndList
, LVM_DELETEALLITEMS
, 0, 0);
434 for(i
=0;i
<iiter
->nItems
;i
++) {
435 IndexSubItem
*item
= &iiter
->items
[i
];
436 WCHAR
*name
= iiter
->keyword
;
440 memset(&lvi
, 0, sizeof(lvi
));
442 lvi
.mask
= LVIF_TEXT
|LVIF_PARAM
;
443 lvi
.cchTextMax
= strlenW(name
)+1;
445 lvi
.lParam
= (LPARAM
) item
;
446 SendMessageW(info
->popup
.hwndList
, LVM_INSERTITEMW
, 0, (LPARAM
)&lvi
);
448 ShowWindow(info
->popup
.hwndPopup
, SW_SHOW
);
451 name
= iiter
->items
[0].name
;
452 local
= iiter
->items
[0].local
;
453 chmfile
= iiter
->merge
.chm_file
;
456 FIXME("Unhandled operation for this tab!\n");
462 FIXME("No help file found for this item!\n");
466 TRACE("name %s loal %s\n", debugstr_w(name
), debugstr_w(local
));
468 NavigateToChm(info
, chmfile
, local
);
472 static LRESULT CALLBACK
Child_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
477 return Child_OnPaint(hWnd
);
479 return Child_OnSize(hWnd
);
481 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
482 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
484 switch(nmhdr
->code
) {
486 return OnTabChange(hWnd
);
487 case TVN_SELCHANGEDW
:
488 return OnTopicChange(info
, (void*)((NMTREEVIEWW
*)lParam
)->itemNew
.lParam
);
490 if(info
->current_tab
== TAB_INDEX
)
491 return OnTopicChange(info
, (void*)((NMITEMACTIVATE
*)lParam
)->lParam
);
496 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
502 static void HH_RegisterChildWndClass(HHInfo
*pHHInfo
)
506 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
508 wcex
.lpfnWndProc
= Child_WndProc
;
511 wcex
.hInstance
= hhctrl_hinstance
;
512 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
513 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
514 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
515 wcex
.lpszMenuName
= NULL
;
516 wcex
.lpszClassName
= szChildClass
;
517 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
519 RegisterClassExW(&wcex
);
526 static void TB_OnClick(HWND hWnd
, DWORD dwID
)
528 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
533 DoPageAction(info
, WB_STOP
);
536 DoPageAction(info
, WB_REFRESH
);
539 DoPageAction(info
, WB_GOBACK
);
542 NavigateToChm(info
, info
->pCHMInfo
->szFile
, info
->WinType
.pszHome
);
545 DoPageAction(info
, WB_GOFORWARD
);
552 case IDTB_BROWSE_FWD
:
553 case IDTB_BROWSE_BACK
:
564 static void TB_AddButton(TBBUTTON
*pButtons
, DWORD dwIndex
, DWORD dwID
)
566 /* FIXME: Load the correct button bitmaps */
567 pButtons
[dwIndex
].iBitmap
= STD_PRINT
;
568 pButtons
[dwIndex
].idCommand
= dwID
;
569 pButtons
[dwIndex
].fsState
= TBSTATE_ENABLED
;
570 pButtons
[dwIndex
].fsStyle
= BTNS_BUTTON
;
571 pButtons
[dwIndex
].dwData
= 0;
572 pButtons
[dwIndex
].iString
= 0;
575 static void TB_AddButtonsFromFlags(TBBUTTON
*pButtons
, DWORD dwButtonFlags
, LPDWORD pdwNumButtons
)
579 if (dwButtonFlags
& HHWIN_BUTTON_EXPAND
)
580 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_EXPAND
);
582 if (dwButtonFlags
& HHWIN_BUTTON_BACK
)
583 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_BACK
);
585 if (dwButtonFlags
& HHWIN_BUTTON_FORWARD
)
586 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_FORWARD
);
588 if (dwButtonFlags
& HHWIN_BUTTON_STOP
)
589 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_STOP
);
591 if (dwButtonFlags
& HHWIN_BUTTON_REFRESH
)
592 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_REFRESH
);
594 if (dwButtonFlags
& HHWIN_BUTTON_HOME
)
595 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_HOME
);
597 if (dwButtonFlags
& HHWIN_BUTTON_SYNC
)
598 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_SYNC
);
600 if (dwButtonFlags
& HHWIN_BUTTON_OPTIONS
)
601 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_OPTIONS
);
603 if (dwButtonFlags
& HHWIN_BUTTON_PRINT
)
604 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_PRINT
);
606 if (dwButtonFlags
& HHWIN_BUTTON_JUMP1
)
607 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_JUMP1
);
609 if (dwButtonFlags
& HHWIN_BUTTON_JUMP2
)
610 TB_AddButton(pButtons
,(*pdwNumButtons
)++, IDTB_JUMP2
);
612 if (dwButtonFlags
& HHWIN_BUTTON_ZOOM
)
613 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_ZOOM
);
615 if (dwButtonFlags
& HHWIN_BUTTON_TOC_NEXT
)
616 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_TOC_NEXT
);
618 if (dwButtonFlags
& HHWIN_BUTTON_TOC_PREV
)
619 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_TOC_PREV
);
622 static BOOL
HH_AddToolbar(HHInfo
*pHHInfo
)
625 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
627 TBBUTTON buttons
[IDTB_TOC_PREV
- IDTB_EXPAND
];
629 DWORD dwStyles
, dwExStyles
;
630 DWORD dwNumButtons
, dwIndex
;
632 if (pHHInfo
->WinType
.fsWinProperties
& HHWIN_PARAM_TB_FLAGS
)
633 toolbarFlags
= pHHInfo
->WinType
.fsToolBarFlags
;
635 toolbarFlags
= HHWIN_DEF_BUTTONS
;
637 TB_AddButtonsFromFlags(buttons
, toolbarFlags
, &dwNumButtons
);
639 dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| TBSTYLE_FLAT
|
640 TBSTYLE_WRAPABLE
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
;
641 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
643 hToolbar
= CreateWindowExW(dwExStyles
, TOOLBARCLASSNAMEW
, NULL
, dwStyles
,
644 0, 0, 0, 0, hwndParent
, NULL
,
645 hhctrl_hinstance
, NULL
);
649 SendMessageW(hToolbar
, TB_SETBITMAPSIZE
, 0, MAKELONG(ICON_SIZE
, ICON_SIZE
));
650 SendMessageW(hToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
651 SendMessageW(hToolbar
, WM_SETFONT
, (WPARAM
)pHHInfo
->hFont
, TRUE
);
653 /* FIXME: Load correct icons for all buttons */
654 tbAB
.hInst
= HINST_COMMCTRL
;
655 tbAB
.nID
= IDB_STD_LARGE_COLOR
;
656 SendMessageW(hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbAB
);
658 for (dwIndex
= 0; dwIndex
< dwNumButtons
; dwIndex
++)
660 LPWSTR szBuf
= HH_LoadString(buttons
[dwIndex
].idCommand
);
661 DWORD dwLen
= strlenW(szBuf
);
662 szBuf
[dwLen
+ 1] = 0; /* Double-null terminate */
664 buttons
[dwIndex
].iString
= (DWORD
)SendMessageW(hToolbar
, TB_ADDSTRINGW
, 0, (LPARAM
)szBuf
);
668 SendMessageW(hToolbar
, TB_ADDBUTTONSW
, dwNumButtons
, (LPARAM
)buttons
);
669 SendMessageW(hToolbar
, TB_AUTOSIZE
, 0, 0);
670 ShowWindow(hToolbar
, SW_SHOW
);
672 pHHInfo
->WinType
.hwndToolBar
= hToolbar
;
676 /* Navigation Pane */
678 static void NP_GetNavigationRect(HHInfo
*pHHInfo
, RECT
*rc
)
680 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
681 HWND hwndToolbar
= pHHInfo
->WinType
.hwndToolBar
;
682 RECT rectWND
, rectTB
;
684 GetClientRect(hwndParent
, &rectWND
);
685 GetClientRect(hwndToolbar
, &rectTB
);
688 rc
->top
= rectTB
.bottom
;
689 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
691 if (!(pHHInfo
->WinType
.fsValidMembers
& HHWIN_PARAM_NAV_WIDTH
) &&
692 pHHInfo
->WinType
.iNavWidth
== 0)
694 pHHInfo
->WinType
.iNavWidth
= WINTYPE_DEFAULT_NAVWIDTH
;
697 rc
->right
= pHHInfo
->WinType
.iNavWidth
;
700 static DWORD
NP_CreateTab(HINSTANCE hInstance
, HWND hwndTabCtrl
, DWORD index
)
703 LPWSTR tabText
= HH_LoadString(index
);
706 tie
.mask
= TCIF_TEXT
;
707 tie
.pszText
= tabText
;
709 ret
= SendMessageW( hwndTabCtrl
, TCM_INSERTITEMW
, index
, (LPARAM
)&tie
);
715 static BOOL
HH_AddNavigationPane(HHInfo
*info
)
717 HWND hWnd
, hwndTabCtrl
;
718 HWND hwndParent
= info
->WinType
.hwndHelp
;
719 DWORD dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
;
720 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
723 NP_GetNavigationRect(info
, &rc
);
725 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
726 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
727 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
731 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
733 hwndTabCtrl
= CreateWindowExW(dwExStyles
, WC_TABCONTROLW
, szEmpty
, dwStyles
,
735 rc
.right
- TAB_RIGHT_PADDING
,
736 rc
.bottom
- TAB_TOP_PADDING
,
737 hWnd
, NULL
, hhctrl_hinstance
, NULL
);
741 if (*info
->WinType
.pszToc
)
742 info
->tabs
[TAB_CONTENTS
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_CONTENTS
);
744 if (*info
->WinType
.pszIndex
)
745 info
->tabs
[TAB_INDEX
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_INDEX
);
747 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_SEARCH
)
748 info
->tabs
[TAB_SEARCH
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_SEARCH
);
750 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_FAVORITES
)
751 info
->tabs
[TAB_FAVORITES
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_FAVORITES
);
753 SendMessageW(hwndTabCtrl
, WM_SETFONT
, (WPARAM
)info
->hFont
, TRUE
);
755 info
->hwndTabCtrl
= hwndTabCtrl
;
756 info
->WinType
.hwndNavigation
= hWnd
;
762 static void HP_GetHTMLRect(HHInfo
*info
, RECT
*rc
)
764 RECT rectTB
, rectWND
, rectNP
, rectSB
;
766 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
767 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
768 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
769 GetClientRect(info
->hwndSizeBar
, &rectSB
);
771 rc
->left
= rectNP
.right
+ rectSB
.right
;
772 rc
->top
= rectTB
.bottom
;
773 rc
->right
= rectWND
.right
- rc
->left
;
774 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
777 static BOOL
HH_AddHTMLPane(HHInfo
*pHHInfo
)
780 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
781 DWORD dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| WS_CLIPCHILDREN
;
782 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
| WS_EX_CLIENTEDGE
;
785 HP_GetHTMLRect(pHHInfo
, &rc
);
787 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
788 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
789 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
793 if (!InitWebBrowser(pHHInfo
, hWnd
))
796 /* store the pointer to the HH info struct */
797 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)pHHInfo
);
799 ShowWindow(hWnd
, SW_SHOW
);
802 pHHInfo
->WinType
.hwndHTML
= hWnd
;
806 static BOOL
AddContentTab(HHInfo
*info
)
808 if(info
->tabs
[TAB_CONTENTS
].id
== -1)
809 return TRUE
; /* No "Contents" tab */
810 info
->tabs
[TAB_CONTENTS
].hwnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_TREEVIEWW
,
811 szEmpty
, WS_CHILD
| WS_BORDER
| 0x25, 50, 50, 100, 100,
812 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
813 if(!info
->tabs
[TAB_CONTENTS
].hwnd
) {
814 ERR("Could not create treeview control\n");
818 ResizeTabChild(info
, TAB_CONTENTS
);
819 ShowWindow(info
->tabs
[TAB_CONTENTS
].hwnd
, SW_SHOW
);
824 static BOOL
AddIndexTab(HHInfo
*info
)
826 char hidden_column
[] = "Column";
829 if(info
->tabs
[TAB_INDEX
].id
== -1)
830 return TRUE
; /* No "Index" tab */
831 info
->tabs
[TAB_INDEX
].hwnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
,
832 szEmpty
, WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
| LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
833 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
834 if(!info
->tabs
[TAB_INDEX
].hwnd
) {
835 ERR("Could not create ListView control\n");
838 memset(&lvc
, 0, sizeof(lvc
));
839 lvc
.mask
= LVCF_TEXT
;
840 lvc
.pszText
= hidden_column
;
841 if(SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
843 ERR("Could not create ListView column\n");
847 ResizeTabChild(info
, TAB_INDEX
);
848 ShowWindow(info
->tabs
[TAB_INDEX
].hwnd
, SW_HIDE
);
853 /* The Index tab's sub-topic popup */
855 static void ResizePopupChild(HHInfo
*info
)
857 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
858 int border_width
= GetSystemMetrics(SM_CXBORDER
);
859 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
866 GetClientRect(info
->popup
.hwndPopup
, &rect
);
867 SetWindowPos(info
->popup
.hwndCallback
, HWND_TOP
, 0, 0,
868 rect
.right
, rect
.bottom
, SWP_NOMOVE
);
870 rect
.left
= TAB_MARGIN
;
871 rect
.top
= TAB_TOP_PADDING
+ TAB_MARGIN
;
872 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
873 rect
.bottom
-= TAB_MARGIN
;
874 width
= rect
.right
-rect
.left
;
875 height
= rect
.bottom
-rect
.top
;
877 SetWindowPos(info
->popup
.hwndList
, NULL
, rect
.left
, rect
.top
, width
, height
,
878 SWP_NOZORDER
| SWP_NOACTIVATE
);
880 SendMessageW(info
->popup
.hwndList
, LVM_SETCOLUMNWIDTH
, 0,
881 width
-scroll_width
-2*border_width
-2*edge_width
);
884 static LRESULT CALLBACK
HelpPopup_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
886 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
891 ResizePopupChild(info
);
897 ShowWindow(hWnd
, SW_HIDE
);
901 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
907 static LRESULT CALLBACK
PopupChild_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
912 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
913 if(nmhdr
->code
== NM_DBLCLK
) {
914 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
917 if(info
== 0 || lParam
== 0)
919 iter
= (IndexSubItem
*) ((NMITEMACTIVATE
*)lParam
)->lParam
;
922 NavigateToChm(info
, info
->index
->merge
.chm_file
, iter
->local
);
923 ShowWindow(info
->popup
.hwndPopup
, SW_HIDE
);
929 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
935 static BOOL
AddIndexPopup(HHInfo
*info
)
937 static const WCHAR szPopupChildClass
[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0};
938 static const WCHAR windowCaptionW
[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0};
939 static const WCHAR windowClassW
[] = {'H','H',' ','P','o','p','u','p',0};
940 HWND hwndList
, hwndPopup
, hwndCallback
;
941 char hidden_column
[] = "Column";
945 if(info
->tabs
[TAB_INDEX
].id
== -1)
946 return TRUE
; /* No "Index" tab */
948 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
949 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
950 wcex
.lpfnWndProc
= HelpPopup_WndProc
;
953 wcex
.hInstance
= hhctrl_hinstance
;
954 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
955 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
956 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
957 wcex
.lpszMenuName
= NULL
;
958 wcex
.lpszClassName
= windowClassW
;
959 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
960 RegisterClassExW(&wcex
);
962 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
964 wcex
.lpfnWndProc
= PopupChild_WndProc
;
967 wcex
.hInstance
= hhctrl_hinstance
;
968 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
969 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
970 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
971 wcex
.lpszMenuName
= NULL
;
972 wcex
.lpszClassName
= szPopupChildClass
;
973 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
974 RegisterClassExW(&wcex
);
976 hwndPopup
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
977 | WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
,
978 windowClassW
, windowCaptionW
, WS_POPUPWINDOW
979 | WS_OVERLAPPEDWINDOW
| WS_VISIBLE
980 | WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
, CW_USEDEFAULT
,
981 CW_USEDEFAULT
, 300, 200, info
->WinType
.hwndHelp
,
982 NULL
, hhctrl_hinstance
, NULL
);
986 hwndCallback
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
,
987 szPopupChildClass
, szEmpty
, WS_CHILDWINDOW
| WS_VISIBLE
,
989 hwndPopup
, NULL
, hhctrl_hinstance
, NULL
);
993 ShowWindow(hwndPopup
, SW_HIDE
);
994 hwndList
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
, szEmpty
,
995 WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
996 | LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
997 hwndCallback
, NULL
, hhctrl_hinstance
, NULL
);
999 ERR("Could not create popup ListView control\n");
1002 memset(&lvc
, 0, sizeof(lvc
));
1003 lvc
.mask
= LVCF_TEXT
;
1004 lvc
.pszText
= hidden_column
;
1005 if(SendMessageW(hwndList
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1007 ERR("Could not create popup ListView column\n");
1011 info
->popup
.hwndCallback
= hwndCallback
;
1012 info
->popup
.hwndPopup
= hwndPopup
;
1013 info
->popup
.hwndList
= hwndList
;
1014 SetWindowLongPtrW(hwndPopup
, GWLP_USERDATA
, (LONG_PTR
)info
);
1015 SetWindowLongPtrW(hwndCallback
, GWLP_USERDATA
, (LONG_PTR
)info
);
1017 ResizePopupChild(info
);
1018 ShowWindow(hwndList
, SW_SHOW
);
1025 static LRESULT
Help_OnSize(HWND hWnd
)
1027 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
1034 NP_GetNavigationRect(pHHInfo
, &rc
);
1035 SetWindowPos(pHHInfo
->WinType
.hwndNavigation
, HWND_TOP
, 0, 0,
1036 rc
.right
, rc
.bottom
, SWP_NOMOVE
);
1038 SB_GetSizeBarRect(pHHInfo
, &rc
);
1039 SetWindowPos(pHHInfo
->hwndSizeBar
, HWND_TOP
, rc
.left
, rc
.top
,
1040 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1042 HP_GetHTMLRect(pHHInfo
, &rc
);
1043 SetWindowPos(pHHInfo
->WinType
.hwndHTML
, HWND_TOP
, rc
.left
, rc
.top
,
1044 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1046 /* Resize browser window taking the frame size into account */
1047 dwSize
= GetSystemMetrics(SM_CXFRAME
);
1048 ResizeWebBrowser(pHHInfo
, rc
.right
- dwSize
, rc
.bottom
- dwSize
);
1053 static LRESULT CALLBACK
Help_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1058 if (HIWORD(wParam
) == BN_CLICKED
)
1059 TB_OnClick(hWnd
, LOWORD(wParam
));
1062 return Help_OnSize(hWnd
);
1064 ReleaseHelpViewer((HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
));
1072 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1078 static BOOL
HH_CreateHelpWindow(HHInfo
*info
)
1081 RECT winPos
= info
->WinType
.rcWindowPos
;
1083 DWORD dwStyles
, dwExStyles
;
1084 DWORD x
, y
, width
, height
;
1086 static const WCHAR windowClassW
[] = {
1087 'H','H',' ', 'P','a','r','e','n','t',0
1090 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1091 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
1092 wcex
.lpfnWndProc
= Help_WndProc
;
1093 wcex
.cbClsExtra
= 0;
1094 wcex
.cbWndExtra
= 0;
1095 wcex
.hInstance
= hhctrl_hinstance
;
1096 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1097 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1098 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
1099 wcex
.lpszMenuName
= NULL
;
1100 wcex
.lpszClassName
= windowClassW
;
1101 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1103 RegisterClassExW(&wcex
);
1105 /* Read in window parameters if available */
1106 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_STYLES
)
1107 dwStyles
= info
->WinType
.dwStyles
| WS_OVERLAPPEDWINDOW
;
1109 dwStyles
= WS_OVERLAPPEDWINDOW
| WS_VISIBLE
|
1110 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1112 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_EXSTYLES
)
1113 dwExStyles
= info
->WinType
.dwExStyles
;
1115 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
|
1116 WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
;
1118 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_RECT
)
1122 width
= winPos
.right
- x
;
1123 height
= winPos
.bottom
- y
;
1127 x
= WINTYPE_DEFAULT_X
;
1128 y
= WINTYPE_DEFAULT_Y
;
1129 width
= WINTYPE_DEFAULT_WIDTH
;
1130 height
= WINTYPE_DEFAULT_HEIGHT
;
1133 hWnd
= CreateWindowExW(dwExStyles
, windowClassW
, info
->WinType
.pszCaption
,
1134 dwStyles
, x
, y
, width
, height
, NULL
, NULL
, hhctrl_hinstance
, NULL
);
1138 ShowWindow(hWnd
, SW_SHOW
);
1141 /* store the pointer to the HH info struct */
1142 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
1144 info
->WinType
.hwndHelp
= hWnd
;
1148 static void HH_CreateFont(HHInfo
*pHHInfo
)
1152 GetObjectW(GetStockObject(ANSI_VAR_FONT
), sizeof(LOGFONTW
), &lf
);
1153 lf
.lfWeight
= FW_NORMAL
;
1154 lf
.lfItalic
= FALSE
;
1155 lf
.lfUnderline
= FALSE
;
1157 pHHInfo
->hFont
= CreateFontIndirectW(&lf
);
1160 static void HH_InitRequiredControls(DWORD dwControls
)
1162 INITCOMMONCONTROLSEX icex
;
1164 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1165 icex
.dwICC
= dwControls
;
1166 InitCommonControlsEx(&icex
);
1169 /* Creates the whole package */
1170 static BOOL
CreateViewer(HHInfo
*pHHInfo
)
1172 HH_CreateFont(pHHInfo
);
1174 if (!HH_CreateHelpWindow(pHHInfo
))
1177 HH_InitRequiredControls(ICC_BAR_CLASSES
);
1179 if (!HH_AddToolbar(pHHInfo
))
1182 HH_RegisterChildWndClass(pHHInfo
);
1184 if (!HH_AddNavigationPane(pHHInfo
))
1187 HH_RegisterSizeBarClass(pHHInfo
);
1189 if (!HH_AddSizeBar(pHHInfo
))
1192 if (!HH_AddHTMLPane(pHHInfo
))
1195 if (!AddContentTab(pHHInfo
))
1198 if (!AddIndexTab(pHHInfo
))
1201 if (!AddIndexPopup(pHHInfo
))
1204 InitContent(pHHInfo
);
1210 void ReleaseHelpViewer(HHInfo
*info
)
1212 TRACE("(%p)\n", info
);
1217 /* Free allocated strings */
1218 heap_free(info
->pszType
);
1219 heap_free(info
->pszCaption
);
1220 heap_free(info
->pszToc
);
1221 heap_free(info
->pszIndex
);
1222 heap_free(info
->pszFile
);
1223 heap_free(info
->pszHome
);
1224 heap_free(info
->pszJump1
);
1225 heap_free(info
->pszJump2
);
1226 heap_free(info
->pszUrlJump1
);
1227 heap_free(info
->pszUrlJump2
);
1230 CloseCHM(info
->pCHMInfo
);
1232 ReleaseWebBrowser(info
);
1233 ReleaseContent(info
);
1236 if(info
->WinType
.hwndHelp
)
1237 DestroyWindow(info
->WinType
.hwndHelp
);
1243 HHInfo
*CreateHelpViewer(LPCWSTR filename
)
1245 HHInfo
*info
= heap_alloc_zero(sizeof(HHInfo
));
1248 /* Set the invalid tab ID (-1) as the default value for all
1249 * of the tabs, this matches a failed TCM_INSERTITEM call.
1251 for(i
=0;i
<sizeof(info
->tabs
)/sizeof(HHTab
);i
++)
1252 info
->tabs
[i
].id
= -1;
1254 OleInitialize(NULL
);
1256 info
->pCHMInfo
= OpenCHM(filename
);
1257 if(!info
->pCHMInfo
) {
1258 ReleaseHelpViewer(info
);
1262 if (!LoadWinTypeFromCHM(info
)) {
1263 ReleaseHelpViewer(info
);
1267 if(!CreateViewer(info
)) {
1268 ReleaseHelpViewer(info
);