2 * Help Viewer Implementation
4 * Copyright 2005 James Hawkins
5 * Copyright 2007 Jacek Caban for CodeWeavers
6 * Copyright 2011 Owen Rudge for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp
);
35 static LRESULT
Help_OnSize(HWND hWnd
);
36 static void ExpandContract(HHInfo
*pHHInfo
);
38 /* Window type defaults */
40 #define WINTYPE_DEFAULT_X 280
41 #define WINTYPE_DEFAULT_Y 100
42 #define WINTYPE_DEFAULT_WIDTH 740
43 #define WINTYPE_DEFAULT_HEIGHT 640
44 #define WINTYPE_DEFAULT_NAVWIDTH 250
46 #define TAB_TOP_PADDING 8
47 #define TAB_RIGHT_PADDING 4
49 #define EDIT_HEIGHT 20
51 struct list window_list
= LIST_INIT(window_list
);
53 static const WCHAR szEmpty
[] = {0};
55 struct html_encoded_symbol
{
56 const char *html_code
;
61 * Table mapping the conversion between HTML encoded symbols and their ANSI code page equivalent.
62 * Note: Add additional entries in proper alphabetical order (a binary search is used on this table).
64 struct html_encoded_symbol html_encoded_symbols
[] =
168 static inline BOOL
navigation_visible(HHInfo
*info
)
170 return ((info
->WinType
.fsWinProperties
& HHWIN_PROP_TRI_PANE
) && !info
->WinType
.fNotExpanded
);
173 /* Loads a string from the resource file */
174 static LPWSTR
HH_LoadString(DWORD dwID
)
176 LPWSTR string
= NULL
;
177 LPCWSTR stringresource
;
180 iSize
= LoadStringW(hhctrl_hinstance
, dwID
, (LPWSTR
)&stringresource
, 0);
182 string
= heap_alloc((iSize
+ 2) * sizeof(WCHAR
)); /* some strings (tab text) needs double-null termination */
183 memcpy(string
, stringresource
, iSize
*sizeof(WCHAR
));
189 static HRESULT
navigate_url(HHInfo
*info
, LPCWSTR surl
)
194 TRACE("%s\n", debugstr_w(surl
));
196 V_VT(&url
) = VT_BSTR
;
197 V_BSTR(&url
) = SysAllocString(surl
);
199 hres
= IWebBrowser2_Navigate2(info
->web_browser
->web_browser
, &url
, 0, 0, 0, 0);
204 TRACE("Navigation failed: %08x\n", hres
);
209 BOOL
NavigateToUrl(HHInfo
*info
, LPCWSTR surl
)
215 static const WCHAR url_indicator
[] = {':', '/', '/', 0};
217 TRACE("%s\n", debugstr_w(surl
));
219 if (strstrW(surl
, url_indicator
)) {
220 hres
= navigate_url(info
, surl
);
223 } /* look up in chm if it doesn't look like a full url */
225 SetChmPath(&chm_path
, info
->pCHMInfo
->szFile
, surl
);
226 ret
= NavigateToChm(info
, chm_path
.chm_file
, chm_path
.chm_index
);
228 heap_free(chm_path
.chm_file
);
229 heap_free(chm_path
.chm_index
);
234 static BOOL
AppendFullPathURL(LPCWSTR file
, LPWSTR buf
, LPCWSTR index
)
236 static const WCHAR url_format
[] =
237 {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0};
238 static const WCHAR slash
[] = {'/',0};
239 static const WCHAR empty
[] = {0};
240 WCHAR full_path
[MAX_PATH
];
242 TRACE("%s %p %s\n", debugstr_w(file
), buf
, debugstr_w(index
));
244 if(!GetFullPathNameW(file
, sizeof(full_path
)/sizeof(full_path
[0]), full_path
, NULL
)) {
245 WARN("GetFullPathName failed: %u\n", GetLastError());
249 wsprintfW(buf
, url_format
, full_path
, (!index
|| index
[0] == '/') ? empty
: slash
, index
);
253 BOOL
NavigateToChm(HHInfo
*info
, LPCWSTR file
, LPCWSTR index
)
255 WCHAR buf
[INTERNET_MAX_URL_LENGTH
];
257 TRACE("%p %s %s\n", info
, debugstr_w(file
), debugstr_w(index
));
259 if ((!info
->web_browser
) || !AppendFullPathURL(file
, buf
, index
))
262 return SUCCEEDED(navigate_url(info
, buf
));
265 static void DoSync(HHInfo
*info
)
267 WCHAR buf
[INTERNET_MAX_URL_LENGTH
];
271 hres
= IWebBrowser2_get_LocationURL(info
->web_browser
->web_browser
, &url
);
275 WARN("get_LocationURL failed: %08x\n", hres
);
279 /* If we're not currently viewing a page in the active .chm file, abort */
280 if ((!AppendFullPathURL(info
->WinType
.pszFile
, buf
, NULL
)) || (lstrlenW(buf
) > lstrlenW(url
)))
286 if (lstrcmpiW(buf
, url
) > 0)
288 static const WCHAR delimW
[] = {':',':','/',0};
291 index
= strstrW(url
, delimW
);
294 ActivateContentTopic(info
->tabs
[TAB_CONTENTS
].hwnd
, index
+ 3, info
->content
); /* skip over ::/ */
302 #define SIZEBAR_WIDTH 4
304 static const WCHAR szSizeBarClass
[] = {
305 'H','H',' ','S','i','z','e','B','a','r',0
308 /* Draw the SizeBar */
309 static void SB_OnPaint(HWND hWnd
)
315 hdc
= BeginPaint(hWnd
, &ps
);
317 GetClientRect(hWnd
, &rc
);
322 FrameRect(hdc
, &rc
, GetStockObject(GRAY_BRUSH
));
324 /* white highlight */
325 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
326 MoveToEx(hdc
, rc
.right
, 1, NULL
);
328 LineTo(hdc
, 1, rc
.bottom
- 1);
331 MoveToEx(hdc
, 0, rc
.bottom
, NULL
);
332 LineTo(hdc
, rc
.right
, rc
.bottom
);
337 static void SB_OnLButtonDown(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
342 static void SB_OnLButtonUp(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
344 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
347 pt
.x
= (short)LOWORD(lParam
);
348 pt
.y
= (short)HIWORD(lParam
);
350 /* update the window sizes */
351 pHHInfo
->WinType
.iNavWidth
+= pt
.x
;
357 static void SB_OnMouseMove(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
359 /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
360 if (!(wParam
& MK_LBUTTON
))
364 static LRESULT CALLBACK
SizeBar_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
369 SB_OnLButtonDown(hWnd
, wParam
, lParam
);
372 SB_OnLButtonUp(hWnd
, wParam
, lParam
);
375 SB_OnMouseMove(hWnd
, wParam
, lParam
);
381 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
387 static void HH_RegisterSizeBarClass(HHInfo
*pHHInfo
)
391 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
393 wcex
.lpfnWndProc
= SizeBar_WndProc
;
395 wcex
.cbWndExtra
= sizeof(LONG_PTR
);
396 wcex
.hInstance
= hhctrl_hinstance
;
397 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
398 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_SIZEWE
);
399 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
400 wcex
.lpszMenuName
= NULL
;
401 wcex
.lpszClassName
= szSizeBarClass
;
402 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
404 RegisterClassExW(&wcex
);
407 static void SB_GetSizeBarRect(HHInfo
*info
, RECT
*rc
)
409 RECT rectWND
, rectTB
, rectNP
;
411 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
412 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
413 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
415 rc
->left
= rectNP
.right
;
416 rc
->top
= rectTB
.bottom
;
417 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
418 rc
->right
= SIZEBAR_WIDTH
;
421 static BOOL
HH_AddSizeBar(HHInfo
*pHHInfo
)
424 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
425 DWORD dwStyles
= WS_CHILDWINDOW
| WS_OVERLAPPED
;
426 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
429 if (navigation_visible(pHHInfo
))
430 dwStyles
|= WS_VISIBLE
;
432 SB_GetSizeBarRect(pHHInfo
, &rc
);
434 hWnd
= CreateWindowExW(dwExStyles
, szSizeBarClass
, szEmpty
, dwStyles
,
435 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
436 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
440 /* store the pointer to the HH info struct */
441 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)pHHInfo
);
443 pHHInfo
->hwndSizeBar
= hWnd
;
449 static const WCHAR szChildClass
[] = {
450 'H','H',' ','C','h','i','l','d',0
453 static LRESULT
Child_OnPaint(HWND hWnd
)
459 hdc
= BeginPaint(hWnd
, &ps
);
461 /* Only paint the Navigation pane, identified by the fact
462 * that it has a child window
464 if (GetWindow(hWnd
, GW_CHILD
))
466 GetClientRect(hWnd
, &rc
);
468 /* set the border color */
469 SelectObject(hdc
, GetStockObject(DC_PEN
));
470 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
472 /* Draw the top border */
473 LineTo(hdc
, rc
.right
, 0);
475 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
476 MoveToEx(hdc
, 0, 1, NULL
);
477 LineTo(hdc
, rc
.right
, 1);
485 static void ResizeTabChild(HHInfo
*info
, int tab
)
487 HWND hwnd
= info
->tabs
[tab
].hwnd
;
492 GetClientRect(info
->WinType
.hwndNavigation
, &rect
);
493 SendMessageW(info
->hwndTabCtrl
, TCM_GETITEMRECT
, 0, (LPARAM
)&tabrc
);
494 cnt
= SendMessageW(info
->hwndTabCtrl
, TCM_GETROWCOUNT
, 0, 0);
496 rect
.left
= TAB_MARGIN
;
497 rect
.top
= TAB_TOP_PADDING
+ cnt
*(tabrc
.bottom
-tabrc
.top
) + TAB_MARGIN
;
498 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
499 rect
.bottom
-= TAB_MARGIN
;
500 width
= rect
.right
-rect
.left
;
501 height
= rect
.bottom
-rect
.top
;
503 SetWindowPos(hwnd
, NULL
, rect
.left
, rect
.top
, width
, height
,
504 SWP_NOZORDER
| SWP_NOACTIVATE
);
509 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
510 int border_width
= GetSystemMetrics(SM_CXBORDER
);
511 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
513 /* Resize the tab widget column to perfectly fit the tab window and
514 * leave sufficient space for the scroll widget.
516 SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_SETCOLUMNWIDTH
, 0,
517 width
-scroll_width
-2*border_width
-2*edge_width
);
522 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
523 int border_width
= GetSystemMetrics(SM_CXBORDER
);
524 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
527 SetWindowPos(info
->search
.hwndEdit
, NULL
, 0, top_pos
, width
,
528 EDIT_HEIGHT
, SWP_NOZORDER
| SWP_NOACTIVATE
);
529 top_pos
+= EDIT_HEIGHT
+ TAB_MARGIN
;
530 SetWindowPos(info
->search
.hwndList
, NULL
, 0, top_pos
, width
,
531 height
-top_pos
, SWP_NOZORDER
| SWP_NOACTIVATE
);
532 /* Resize the tab widget column to perfectly fit the tab window and
533 * leave sufficient space for the scroll widget.
535 SendMessageW(info
->search
.hwndList
, LVM_SETCOLUMNWIDTH
, 0,
536 width
-scroll_width
-2*border_width
-2*edge_width
);
543 static LRESULT
Child_OnSize(HWND hwnd
)
545 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, 0);
548 if(!info
|| hwnd
!= info
->WinType
.hwndNavigation
)
551 GetClientRect(hwnd
, &rect
);
552 SetWindowPos(info
->hwndTabCtrl
, HWND_TOP
, 0, 0,
553 rect
.right
- TAB_RIGHT_PADDING
,
554 rect
.bottom
- TAB_TOP_PADDING
, SWP_NOMOVE
);
556 ResizeTabChild(info
, TAB_CONTENTS
);
557 ResizeTabChild(info
, TAB_INDEX
);
558 ResizeTabChild(info
, TAB_SEARCH
);
562 static LRESULT
OnTabChange(HWND hwnd
)
564 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, 0);
565 int tab_id
, tab_index
, i
;
572 if(info
->tabs
[info
->current_tab
].hwnd
)
573 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_HIDE
);
575 tab_id
= (int) SendMessageW(info
->hwndTabCtrl
, TCM_GETCURSEL
, 0, 0);
576 /* convert the ID of the tab to an index in our tab list */
578 for (i
=0; i
<TAB_NUMTABS
; i
++)
580 if (info
->tabs
[i
].id
== tab_id
)
588 FIXME("Tab ID %d does not correspond to a valid index in the tab list.\n", tab_id
);
591 info
->current_tab
= tab_index
;
593 if(info
->tabs
[info
->current_tab
].hwnd
)
594 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_SHOW
);
599 static LRESULT
OnTopicChange(HHInfo
*info
, void *user_data
)
601 LPCWSTR chmfile
= NULL
, name
= NULL
, local
= NULL
;
606 if(!user_data
|| !info
)
609 switch (info
->current_tab
)
612 citer
= (ContentItem
*) user_data
;
614 local
= citer
->local
;
616 if(citer
->merge
.chm_file
) {
617 chmfile
= citer
->merge
.chm_file
;
620 citer
= citer
->parent
;
624 iiter
= (IndexItem
*) user_data
;
625 if(iiter
->nItems
== 0) {
626 FIXME("No entries for this item!\n");
629 if(iiter
->nItems
> 1) {
633 SendMessageW(info
->popup
.hwndList
, LVM_DELETEALLITEMS
, 0, 0);
634 for(i
=0;i
<iiter
->nItems
;i
++) {
635 IndexSubItem
*item
= &iiter
->items
[i
];
636 WCHAR
*name
= iiter
->keyword
;
639 item
->name
= GetDocumentTitle(info
->pCHMInfo
, item
->local
);
642 memset(&lvi
, 0, sizeof(lvi
));
644 lvi
.mask
= LVIF_TEXT
|LVIF_PARAM
;
645 lvi
.cchTextMax
= strlenW(name
)+1;
647 lvi
.lParam
= (LPARAM
) item
;
648 SendMessageW(info
->popup
.hwndList
, LVM_INSERTITEMW
, 0, (LPARAM
)&lvi
);
650 ShowWindow(info
->popup
.hwndPopup
, SW_SHOW
);
653 name
= iiter
->items
[0].name
;
654 local
= iiter
->items
[0].local
;
655 chmfile
= iiter
->merge
.chm_file
;
658 siter
= (SearchItem
*) user_data
;
659 name
= siter
->filename
;
660 local
= siter
->filename
;
661 chmfile
= info
->pCHMInfo
->szFile
;
664 FIXME("Unhandled operation for this tab!\n");
670 FIXME("No help file found for this item!\n");
674 TRACE("name %s loal %s\n", debugstr_w(name
), debugstr_w(local
));
676 NavigateToChm(info
, chmfile
, local
);
680 /* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */
681 static LRESULT CALLBACK
EditChild_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
683 WNDPROC editWndProc
= (WNDPROC
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
685 if(message
== WM_KEYUP
&& wParam
== VK_RETURN
)
689 nmhdr
.hwndFrom
= hWnd
;
690 nmhdr
.code
= NM_RETURN
;
691 SendMessageW(GetParent(GetParent(hWnd
)), WM_NOTIFY
, wParam
, (LPARAM
)&nmhdr
);
693 return editWndProc(hWnd
, message
, wParam
, lParam
);
696 static LRESULT CALLBACK
Child_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
701 return Child_OnPaint(hWnd
);
703 return Child_OnSize(hWnd
);
705 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
706 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
708 switch(nmhdr
->code
) {
710 return OnTabChange(hWnd
);
711 case TVN_SELCHANGEDW
:
712 return OnTopicChange(info
, (void*)((NMTREEVIEWW
*)lParam
)->itemNew
.lParam
);
713 case TVN_ITEMEXPANDINGW
: {
714 TVITEMW
*item
= &((NMTREEVIEWW
*)lParam
)->itemNew
;
715 HWND hwndTreeView
= info
->tabs
[TAB_CONTENTS
].hwnd
;
717 item
->mask
= TVIF_IMAGE
|TVIF_SELECTEDIMAGE
;
718 if (item
->state
& TVIS_EXPANDED
)
720 item
->iImage
= HHTV_FOLDER
;
721 item
->iSelectedImage
= HHTV_FOLDER
;
725 item
->iImage
= HHTV_OPENFOLDER
;
726 item
->iSelectedImage
= HHTV_OPENFOLDER
;
728 SendMessageW(hwndTreeView
, TVM_SETITEMW
, 0, (LPARAM
)item
);
734 switch(info
->current_tab
)
737 return OnTopicChange(info
, (void*)((NMITEMACTIVATE
*)lParam
)->lParam
);
739 return OnTopicChange(info
, (void*)((NMITEMACTIVATE
*)lParam
)->lParam
);
745 switch(info
->current_tab
) {
747 HWND hwndList
= info
->tabs
[TAB_INDEX
].hwnd
;
750 lvItem
.iItem
= (int) SendMessageW(hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
751 lvItem
.mask
= TVIF_PARAM
;
752 SendMessageW(hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
753 OnTopicChange(info
, (void*) lvItem
.lParam
);
757 if(nmhdr
->hwndFrom
== info
->search
.hwndEdit
) {
761 len
= GetWindowTextA(info
->search
.hwndEdit
, needle
, sizeof(needle
));
764 FIXME("Unable to get search text.\n");
767 /* Convert the requested text for comparison later against the
768 * lower case version of HTML file contents.
771 needle
[i
] = tolower(needle
[i
]);
772 InitSearch(info
, needle
);
774 }else if(nmhdr
->hwndFrom
== info
->search
.hwndList
) {
775 HWND hwndList
= info
->search
.hwndList
;
778 lvItem
.iItem
= (int) SendMessageW(hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
779 lvItem
.mask
= TVIF_PARAM
;
780 SendMessageW(hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
781 OnTopicChange(info
, (void*) lvItem
.lParam
);
792 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
798 static void HH_RegisterChildWndClass(HHInfo
*pHHInfo
)
802 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
804 wcex
.lpfnWndProc
= Child_WndProc
;
806 wcex
.cbWndExtra
= sizeof(LONG_PTR
);
807 wcex
.hInstance
= hhctrl_hinstance
;
808 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
809 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
810 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
811 wcex
.lpszMenuName
= NULL
;
812 wcex
.lpszClassName
= szChildClass
;
813 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
815 RegisterClassExW(&wcex
);
822 static void DisplayPopupMenu(HHInfo
*info
)
825 TBBUTTONINFOW button
;
831 menu
= LoadMenuW(hhctrl_hinstance
, MAKEINTRESOURCEW(MENU_POPUP
));
836 submenu
= GetSubMenu(menu
, 0);
838 /* Update the Show/Hide menu item */
839 item
.cbSize
= sizeof(MENUITEMINFOW
);
840 item
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_STRING
;
841 item
.fType
= MFT_STRING
;
842 item
.fState
= MF_ENABLED
;
844 if (info
->WinType
.fNotExpanded
)
845 item
.dwTypeData
= HH_LoadString(IDS_SHOWTABS
);
847 item
.dwTypeData
= HH_LoadString(IDS_HIDETABS
);
849 SetMenuItemInfoW(submenu
, IDTB_EXPAND
, FALSE
, &item
);
850 heap_free(item
.dwTypeData
);
852 /* Find the index toolbar button */
853 button
.cbSize
= sizeof(TBBUTTONINFOW
);
854 button
.dwMask
= TBIF_COMMAND
;
855 index
= SendMessageW(info
->WinType
.hwndToolBar
, TB_GETBUTTONINFOW
, IDTB_OPTIONS
, (LPARAM
) &button
);
861 SendMessageW(info
->WinType
.hwndToolBar
, TB_GETITEMRECT
, index
, (LPARAM
) &rect
);
863 coords
.x
= rect
.left
;
864 coords
.y
= rect
.bottom
;
866 ClientToScreen(info
->WinType
.hwndToolBar
, &coords
);
867 TrackPopupMenu(submenu
, TPM_LEFTALIGN
| TPM_TOPALIGN
| TPM_LEFTBUTTON
| TPM_NOANIMATION
, coords
.x
, coords
.y
, 0, info
->WinType
.hwndHelp
, NULL
);
870 static void TB_OnClick(HWND hWnd
, DWORD dwID
)
872 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
877 DoPageAction(info
->web_browser
, WB_STOP
);
880 DoPageAction(info
->web_browser
, WB_REFRESH
);
883 DoPageAction(info
->web_browser
, WB_GOBACK
);
886 NavigateToChm(info
, info
->pCHMInfo
->szFile
, info
->WinType
.pszHome
);
889 DoPageAction(info
->web_browser
, WB_GOFORWARD
);
892 DoPageAction(info
->web_browser
, WB_PRINT
);
896 ExpandContract(info
);
902 DisplayPopupMenu(info
);
910 /* These are officially unimplemented as of the Windows 7 SDK */
912 case IDTB_BROWSE_FWD
:
913 case IDTB_BROWSE_BACK
:
924 static void TB_AddButton(TBBUTTON
*pButtons
, DWORD dwIndex
, DWORD dwID
, DWORD dwBitmap
)
926 pButtons
[dwIndex
].iBitmap
= dwBitmap
;
927 pButtons
[dwIndex
].idCommand
= dwID
;
928 pButtons
[dwIndex
].fsState
= TBSTATE_ENABLED
;
929 pButtons
[dwIndex
].fsStyle
= BTNS_BUTTON
;
930 pButtons
[dwIndex
].dwData
= 0;
931 pButtons
[dwIndex
].iString
= 0;
934 static void TB_AddButtonsFromFlags(HHInfo
*pHHInfo
, TBBUTTON
*pButtons
, DWORD dwButtonFlags
, LPDWORD pdwNumButtons
)
936 int nHistBitmaps
= 0, nStdBitmaps
= 0, nHHBitmaps
= 0;
937 HWND hToolbar
= pHHInfo
->WinType
.hwndToolBar
;
942 tbAB
.hInst
= HINST_COMMCTRL
;
943 tbAB
.nID
= IDB_HIST_LARGE_COLOR
;
944 nHistBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbAB
);
945 tbAB
.nID
= IDB_STD_LARGE_COLOR
;
946 nStdBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbAB
);
947 /* hhctrl.ocx bitmaps */
948 tbAB
.hInst
= hhctrl_hinstance
;
949 tbAB
.nID
= IDB_HHTOOLBAR
;
950 nHHBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, HHTB_NUMBITMAPS
, (LPARAM
)&tbAB
);
954 unsupported
= dwButtonFlags
& (HHWIN_BUTTON_BROWSE_FWD
|
955 HHWIN_BUTTON_BROWSE_BCK
| HHWIN_BUTTON_NOTES
| HHWIN_BUTTON_CONTENTS
|
956 HHWIN_BUTTON_INDEX
| HHWIN_BUTTON_SEARCH
| HHWIN_BUTTON_HISTORY
|
957 HHWIN_BUTTON_FAVORITES
| HHWIN_BUTTON_JUMP1
| HHWIN_BUTTON_JUMP2
|
958 HHWIN_BUTTON_ZOOM
| HHWIN_BUTTON_TOC_NEXT
| HHWIN_BUTTON_TOC_PREV
);
960 FIXME("got asked for unsupported buttons: %06x\n", unsupported
);
962 if (dwButtonFlags
& HHWIN_BUTTON_EXPAND
)
964 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_EXPAND
, nHHBitmaps
+ HHTB_EXPAND
);
965 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_CONTRACT
, nHHBitmaps
+ HHTB_CONTRACT
);
967 if (pHHInfo
->WinType
.fNotExpanded
)
968 pButtons
[1].fsState
|= TBSTATE_HIDDEN
;
970 pButtons
[0].fsState
|= TBSTATE_HIDDEN
;
973 if (dwButtonFlags
& HHWIN_BUTTON_BACK
)
974 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_BACK
, nHistBitmaps
+ HIST_BACK
);
976 if (dwButtonFlags
& HHWIN_BUTTON_FORWARD
)
977 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_FORWARD
, nHistBitmaps
+ HIST_FORWARD
);
979 if (dwButtonFlags
& HHWIN_BUTTON_STOP
)
980 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_STOP
, nHHBitmaps
+ HHTB_STOP
);
982 if (dwButtonFlags
& HHWIN_BUTTON_REFRESH
)
983 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_REFRESH
, nHHBitmaps
+ HHTB_REFRESH
);
985 if (dwButtonFlags
& HHWIN_BUTTON_HOME
)
986 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_HOME
, nHHBitmaps
+ HHTB_HOME
);
988 if (dwButtonFlags
& HHWIN_BUTTON_SYNC
)
989 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_SYNC
, nHHBitmaps
+ HHTB_SYNC
);
991 if (dwButtonFlags
& HHWIN_BUTTON_OPTIONS
)
992 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_OPTIONS
, nStdBitmaps
+ STD_PROPERTIES
);
994 if (dwButtonFlags
& HHWIN_BUTTON_PRINT
)
995 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_PRINT
, nStdBitmaps
+ STD_PRINT
);
998 static BOOL
HH_AddToolbar(HHInfo
*pHHInfo
)
1001 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
1003 TBBUTTON buttons
[IDTB_TOC_PREV
- IDTB_EXPAND
];
1004 DWORD dwStyles
, dwExStyles
;
1005 DWORD dwNumButtons
, dwIndex
;
1007 if (pHHInfo
->WinType
.fsWinProperties
& HHWIN_PARAM_TB_FLAGS
)
1008 toolbarFlags
= pHHInfo
->WinType
.fsToolBarFlags
;
1010 toolbarFlags
= HHWIN_DEF_BUTTONS
;
1012 dwStyles
= WS_CHILDWINDOW
| TBSTYLE_FLAT
| TBSTYLE_WRAPABLE
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
;
1013 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
1015 hToolbar
= CreateWindowExW(dwExStyles
, TOOLBARCLASSNAMEW
, NULL
, dwStyles
,
1016 0, 0, 0, 0, hwndParent
, NULL
,
1017 hhctrl_hinstance
, NULL
);
1020 pHHInfo
->WinType
.hwndToolBar
= hToolbar
;
1022 SendMessageW(hToolbar
, TB_SETBITMAPSIZE
, 0, MAKELONG(ICON_SIZE
, ICON_SIZE
));
1023 SendMessageW(hToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1024 SendMessageW(hToolbar
, WM_SETFONT
, (WPARAM
)pHHInfo
->hFont
, TRUE
);
1026 TB_AddButtonsFromFlags(pHHInfo
, buttons
, toolbarFlags
, &dwNumButtons
);
1028 for (dwIndex
= 0; dwIndex
< dwNumButtons
; dwIndex
++)
1030 LPWSTR szBuf
= HH_LoadString(buttons
[dwIndex
].idCommand
);
1031 DWORD dwLen
= strlenW(szBuf
);
1032 szBuf
[dwLen
+ 1] = 0; /* Double-null terminate */
1034 buttons
[dwIndex
].iString
= (DWORD
)SendMessageW(hToolbar
, TB_ADDSTRINGW
, 0, (LPARAM
)szBuf
);
1038 SendMessageW(hToolbar
, TB_ADDBUTTONSW
, dwNumButtons
, (LPARAM
)buttons
);
1039 SendMessageW(hToolbar
, TB_AUTOSIZE
, 0, 0);
1040 if (pHHInfo
->WinType
.fsWinProperties
& HHWIN_PROP_TRI_PANE
)
1041 ShowWindow(hToolbar
, SW_SHOW
);
1046 /* Navigation Pane */
1048 static void NP_GetNavigationRect(HHInfo
*pHHInfo
, RECT
*rc
)
1050 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
1051 HWND hwndToolbar
= pHHInfo
->WinType
.hwndToolBar
;
1052 RECT rectWND
, rectTB
;
1054 GetClientRect(hwndParent
, &rectWND
);
1055 GetClientRect(hwndToolbar
, &rectTB
);
1058 rc
->top
= rectTB
.bottom
;
1059 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
1061 if (!(pHHInfo
->WinType
.fsValidMembers
& HHWIN_PARAM_NAV_WIDTH
) &&
1062 pHHInfo
->WinType
.iNavWidth
== 0)
1064 pHHInfo
->WinType
.iNavWidth
= WINTYPE_DEFAULT_NAVWIDTH
;
1067 rc
->right
= pHHInfo
->WinType
.iNavWidth
;
1070 static DWORD
NP_CreateTab(HINSTANCE hInstance
, HWND hwndTabCtrl
, DWORD index
)
1073 LPWSTR tabText
= HH_LoadString(index
);
1076 tie
.mask
= TCIF_TEXT
;
1077 tie
.pszText
= tabText
;
1079 ret
= SendMessageW( hwndTabCtrl
, TCM_INSERTITEMW
, index
, (LPARAM
)&tie
);
1085 static BOOL
HH_AddNavigationPane(HHInfo
*info
)
1087 HWND hWnd
, hwndTabCtrl
;
1088 HWND hwndParent
= info
->WinType
.hwndHelp
;
1089 DWORD dwStyles
= WS_CHILDWINDOW
;
1090 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
1093 if (navigation_visible(info
))
1094 dwStyles
|= WS_VISIBLE
;
1096 NP_GetNavigationRect(info
, &rc
);
1098 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
1099 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
1100 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
1104 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)info
);
1106 hwndTabCtrl
= CreateWindowExW(dwExStyles
, WC_TABCONTROLW
, szEmpty
, dwStyles
| WS_VISIBLE
,
1108 rc
.right
- TAB_RIGHT_PADDING
,
1109 rc
.bottom
- TAB_TOP_PADDING
,
1110 hWnd
, NULL
, hhctrl_hinstance
, NULL
);
1114 if (*info
->WinType
.pszToc
)
1115 info
->tabs
[TAB_CONTENTS
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_CONTENTS
);
1117 if (*info
->WinType
.pszIndex
)
1118 info
->tabs
[TAB_INDEX
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_INDEX
);
1120 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_SEARCH
)
1121 info
->tabs
[TAB_SEARCH
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_SEARCH
);
1123 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_FAVORITES
)
1124 info
->tabs
[TAB_FAVORITES
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_FAVORITES
);
1126 SendMessageW(hwndTabCtrl
, WM_SETFONT
, (WPARAM
)info
->hFont
, TRUE
);
1128 info
->hwndTabCtrl
= hwndTabCtrl
;
1129 info
->WinType
.hwndNavigation
= hWnd
;
1135 static void HP_GetHTMLRect(HHInfo
*info
, RECT
*rc
)
1137 RECT rectTB
, rectWND
, rectNP
, rectSB
;
1139 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
1140 GetClientRect(info
->hwndSizeBar
, &rectSB
);
1144 if (navigation_visible(info
))
1146 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
1147 rc
->left
+= rectNP
.right
+ rectSB
.right
;
1149 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TRI_PANE
)
1151 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
1152 rc
->top
+= rectTB
.bottom
;
1154 rc
->right
= rectWND
.right
- rc
->left
;
1155 rc
->bottom
= rectWND
.bottom
- rc
->top
;
1158 static BOOL
HH_AddHTMLPane(HHInfo
*pHHInfo
)
1161 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
1162 DWORD dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| WS_CLIPCHILDREN
;
1163 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
| WS_EX_CLIENTEDGE
;
1166 HP_GetHTMLRect(pHHInfo
, &rc
);
1168 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
1169 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
1170 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
1174 if (!InitWebBrowser(pHHInfo
, hWnd
))
1177 /* store the pointer to the HH info struct */
1178 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)pHHInfo
);
1180 ShowWindow(hWnd
, SW_SHOW
);
1183 pHHInfo
->WinType
.hwndHTML
= hWnd
;
1187 static BOOL
AddContentTab(HHInfo
*info
)
1189 HIMAGELIST hImageList
;
1193 if(info
->tabs
[TAB_CONTENTS
].id
== -1)
1194 return TRUE
; /* No "Contents" tab */
1195 hWnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_TREEVIEWW
, szEmpty
, WS_CHILD
| WS_BORDER
| TVS_LINESATROOT
1196 | TVS_SHOWSELALWAYS
| TVS_HASBUTTONS
, 50, 50, 100, 100,
1197 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
1199 ERR("Could not create treeview control\n");
1203 hImageList
= ImageList_Create(16, 16, ILC_COLOR32
, 0, HHTV_NUMBITMAPS
);
1204 hBitmap
= LoadBitmapW(hhctrl_hinstance
, MAKEINTRESOURCEW(IDB_HHTREEVIEW
));
1205 ImageList_Add(hImageList
, hBitmap
, NULL
);
1206 SendMessageW(hWnd
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, (LPARAM
)hImageList
);
1208 info
->contents
.hImageList
= hImageList
;
1209 info
->tabs
[TAB_CONTENTS
].hwnd
= hWnd
;
1210 ResizeTabChild(info
, TAB_CONTENTS
);
1211 ShowWindow(hWnd
, SW_SHOW
);
1216 static BOOL
AddIndexTab(HHInfo
*info
)
1218 char hidden_column
[] = "Column";
1221 if(info
->tabs
[TAB_INDEX
].id
== -1)
1222 return TRUE
; /* No "Index" tab */
1223 info
->tabs
[TAB_INDEX
].hwnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
,
1224 szEmpty
, WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
| LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
1225 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
1226 if(!info
->tabs
[TAB_INDEX
].hwnd
) {
1227 ERR("Could not create ListView control\n");
1230 memset(&lvc
, 0, sizeof(lvc
));
1231 lvc
.mask
= LVCF_TEXT
;
1232 lvc
.pszText
= hidden_column
;
1233 if(SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1235 ERR("Could not create ListView column\n");
1239 ResizeTabChild(info
, TAB_INDEX
);
1240 ShowWindow(info
->tabs
[TAB_INDEX
].hwnd
, SW_HIDE
);
1245 static BOOL
AddSearchTab(HHInfo
*info
)
1247 HWND hwndList
, hwndEdit
, hwndContainer
;
1248 char hidden_column
[] = "Column";
1249 WNDPROC editWndProc
;
1252 if(info
->tabs
[TAB_SEARCH
].id
== -1)
1253 return TRUE
; /* No "Search" tab */
1254 hwndContainer
= CreateWindowExW(WS_EX_CONTROLPARENT
, szChildClass
, szEmpty
,
1255 WS_CHILD
, 0, 0, 0, 0, info
->WinType
.hwndNavigation
,
1256 NULL
, hhctrl_hinstance
, NULL
);
1257 if(!hwndContainer
) {
1258 ERR("Could not create search window container control.\n");
1261 hwndEdit
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_EDITW
, szEmpty
, WS_CHILD
1262 | WS_VISIBLE
| ES_LEFT
| SS_NOTIFY
, 0, 0, 0, 0,
1263 hwndContainer
, NULL
, hhctrl_hinstance
, NULL
);
1265 ERR("Could not create search ListView control.\n");
1268 if(SendMessageW(hwndEdit
, WM_SETFONT
, (WPARAM
) info
->hFont
, (LPARAM
) FALSE
) == -1)
1270 ERR("Could not set font for edit control.\n");
1273 editWndProc
= (WNDPROC
) SetWindowLongPtrW(hwndEdit
, GWLP_WNDPROC
, (LONG_PTR
)EditChild_WndProc
);
1275 ERR("Could not redirect messages for edit control.\n");
1278 SetWindowLongPtrW(hwndEdit
, GWLP_USERDATA
, (LONG_PTR
)editWndProc
);
1279 hwndList
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
, szEmpty
,
1280 WS_CHILD
| WS_VISIBLE
| WS_BORDER
| LVS_SINGLESEL
1281 | LVS_REPORT
| LVS_NOCOLUMNHEADER
, 0, 0, 0, 0,
1282 hwndContainer
, NULL
, hhctrl_hinstance
, NULL
);
1284 ERR("Could not create search ListView control.\n");
1287 memset(&lvc
, 0, sizeof(lvc
));
1288 lvc
.mask
= LVCF_TEXT
;
1289 lvc
.pszText
= hidden_column
;
1290 if(SendMessageW(hwndList
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1292 ERR("Could not create ListView column\n");
1296 info
->search
.hwndEdit
= hwndEdit
;
1297 info
->search
.hwndList
= hwndList
;
1298 info
->search
.hwndContainer
= hwndContainer
;
1299 info
->tabs
[TAB_SEARCH
].hwnd
= hwndContainer
;
1301 SetWindowLongPtrW(hwndContainer
, 0, (LONG_PTR
)info
);
1303 ResizeTabChild(info
, TAB_SEARCH
);
1308 /* The Index tab's sub-topic popup */
1310 static void ResizePopupChild(HHInfo
*info
)
1312 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
1313 int border_width
= GetSystemMetrics(SM_CXBORDER
);
1314 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
1321 GetClientRect(info
->popup
.hwndPopup
, &rect
);
1322 SetWindowPos(info
->popup
.hwndCallback
, HWND_TOP
, 0, 0,
1323 rect
.right
, rect
.bottom
, SWP_NOMOVE
);
1325 rect
.left
= TAB_MARGIN
;
1326 rect
.top
= TAB_TOP_PADDING
+ TAB_MARGIN
;
1327 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
1328 rect
.bottom
-= TAB_MARGIN
;
1329 width
= rect
.right
-rect
.left
;
1330 height
= rect
.bottom
-rect
.top
;
1332 SetWindowPos(info
->popup
.hwndList
, NULL
, rect
.left
, rect
.top
, width
, height
,
1333 SWP_NOZORDER
| SWP_NOACTIVATE
);
1335 SendMessageW(info
->popup
.hwndList
, LVM_SETCOLUMNWIDTH
, 0,
1336 width
-scroll_width
-2*border_width
-2*edge_width
);
1339 static LRESULT CALLBACK
HelpPopup_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1341 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
1346 ResizePopupChild(info
);
1349 DestroyWindow(hWnd
);
1352 ShowWindow(hWnd
, SW_HIDE
);
1356 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1362 static LRESULT CALLBACK
PopupChild_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1367 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1371 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
1374 if(info
== 0 || lParam
== 0)
1376 iter
= (IndexSubItem
*) ((NMITEMACTIVATE
*)lParam
)->lParam
;
1379 NavigateToChm(info
, info
->index
->merge
.chm_file
, iter
->local
);
1380 ShowWindow(info
->popup
.hwndPopup
, SW_HIDE
);
1384 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
1391 lvItem
.iItem
= (int) SendMessageW(info
->popup
.hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
1392 lvItem
.mask
= TVIF_PARAM
;
1393 SendMessageW(info
->popup
.hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
1394 iter
= (IndexSubItem
*) lvItem
.lParam
;
1395 NavigateToChm(info
, info
->index
->merge
.chm_file
, iter
->local
);
1396 ShowWindow(info
->popup
.hwndPopup
, SW_HIDE
);
1403 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1409 static BOOL
AddIndexPopup(HHInfo
*info
)
1411 static const WCHAR szPopupChildClass
[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0};
1412 static const WCHAR windowCaptionW
[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0};
1413 static const WCHAR windowClassW
[] = {'H','H',' ','P','o','p','u','p',0};
1414 HWND hwndList
, hwndPopup
, hwndCallback
;
1415 char hidden_column
[] = "Column";
1419 if(info
->tabs
[TAB_INDEX
].id
== -1)
1420 return TRUE
; /* No "Index" tab */
1422 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1423 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
1424 wcex
.lpfnWndProc
= HelpPopup_WndProc
;
1425 wcex
.cbClsExtra
= 0;
1426 wcex
.cbWndExtra
= sizeof(LONG_PTR
);
1427 wcex
.hInstance
= hhctrl_hinstance
;
1428 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1429 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1430 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
1431 wcex
.lpszMenuName
= NULL
;
1432 wcex
.lpszClassName
= windowClassW
;
1433 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1434 RegisterClassExW(&wcex
);
1436 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1438 wcex
.lpfnWndProc
= PopupChild_WndProc
;
1439 wcex
.cbClsExtra
= 0;
1440 wcex
.cbWndExtra
= sizeof(LONG_PTR
);
1441 wcex
.hInstance
= hhctrl_hinstance
;
1442 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1443 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1444 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1445 wcex
.lpszMenuName
= NULL
;
1446 wcex
.lpszClassName
= szPopupChildClass
;
1447 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1448 RegisterClassExW(&wcex
);
1450 hwndPopup
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
1451 | WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
,
1452 windowClassW
, windowCaptionW
, WS_POPUPWINDOW
1453 | WS_OVERLAPPEDWINDOW
| WS_VISIBLE
1454 | WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
, CW_USEDEFAULT
,
1455 CW_USEDEFAULT
, 300, 200, info
->WinType
.hwndHelp
,
1456 NULL
, hhctrl_hinstance
, NULL
);
1460 hwndCallback
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
,
1461 szPopupChildClass
, szEmpty
, WS_CHILDWINDOW
| WS_VISIBLE
,
1463 hwndPopup
, NULL
, hhctrl_hinstance
, NULL
);
1467 ShowWindow(hwndPopup
, SW_HIDE
);
1468 hwndList
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
, szEmpty
,
1469 WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
1470 | LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
1471 hwndCallback
, NULL
, hhctrl_hinstance
, NULL
);
1473 ERR("Could not create popup ListView control\n");
1476 memset(&lvc
, 0, sizeof(lvc
));
1477 lvc
.mask
= LVCF_TEXT
;
1478 lvc
.pszText
= hidden_column
;
1479 if(SendMessageW(hwndList
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1481 ERR("Could not create popup ListView column\n");
1485 info
->popup
.hwndCallback
= hwndCallback
;
1486 info
->popup
.hwndPopup
= hwndPopup
;
1487 info
->popup
.hwndList
= hwndList
;
1488 SetWindowLongPtrW(hwndPopup
, 0, (LONG_PTR
)info
);
1489 SetWindowLongPtrW(hwndCallback
, 0, (LONG_PTR
)info
);
1491 ResizePopupChild(info
);
1492 ShowWindow(hwndList
, SW_SHOW
);
1499 static void ExpandContract(HHInfo
*pHHInfo
)
1503 pHHInfo
->WinType
.fNotExpanded
= !pHHInfo
->WinType
.fNotExpanded
;
1504 GetWindowRect(pHHInfo
->WinType
.hwndHelp
, &r
);
1505 NP_GetNavigationRect(pHHInfo
, &nav
);
1507 /* hide/show both the nav bar and the size bar */
1508 if (pHHInfo
->WinType
.fNotExpanded
)
1510 ShowWindow(pHHInfo
->WinType
.hwndNavigation
, SW_HIDE
);
1511 ShowWindow(pHHInfo
->hwndSizeBar
, SW_HIDE
);
1512 r
.left
= r
.left
+ nav
.right
;
1514 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_EXPAND
, MAKELPARAM(FALSE
, 0));
1515 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_CONTRACT
, MAKELPARAM(TRUE
, 0));
1519 ShowWindow(pHHInfo
->WinType
.hwndNavigation
, SW_SHOW
);
1520 ShowWindow(pHHInfo
->hwndSizeBar
, SW_SHOW
);
1521 r
.left
= r
.left
- nav
.right
;
1523 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_EXPAND
, MAKELPARAM(TRUE
, 0));
1524 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_CONTRACT
, MAKELPARAM(FALSE
, 0));
1527 MoveWindow(pHHInfo
->WinType
.hwndHelp
, r
.left
, r
.top
, r
.right
-r
.left
, r
.bottom
-r
.top
, TRUE
);
1530 static LRESULT
Help_OnSize(HWND hWnd
)
1532 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, 0);
1539 if (navigation_visible(pHHInfo
))
1541 NP_GetNavigationRect(pHHInfo
, &rc
);
1542 SetWindowPos(pHHInfo
->WinType
.hwndNavigation
, HWND_TOP
, 0, 0,
1543 rc
.right
, rc
.bottom
, SWP_NOMOVE
);
1545 SB_GetSizeBarRect(pHHInfo
, &rc
);
1546 SetWindowPos(pHHInfo
->hwndSizeBar
, HWND_TOP
, rc
.left
, rc
.top
,
1547 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1551 HP_GetHTMLRect(pHHInfo
, &rc
);
1552 SetWindowPos(pHHInfo
->WinType
.hwndHTML
, HWND_TOP
, rc
.left
, rc
.top
,
1553 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1555 /* Resize browser window taking the frame size into account */
1556 dwSize
= GetSystemMetrics(SM_CXFRAME
);
1557 ResizeWebBrowser(pHHInfo
, rc
.right
- dwSize
, rc
.bottom
- dwSize
);
1562 void UpdateHelpWindow(HHInfo
*info
)
1564 if (!info
->WinType
.hwndHelp
)
1567 WARN("Only the size of the window is currently updated.\n");
1568 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_RECT
)
1570 RECT
*rect
= &info
->WinType
.rcWindowPos
;
1571 INT x
, y
, width
, height
;
1575 width
= rect
->right
- x
;
1576 height
= rect
->bottom
- y
;
1577 SetWindowPos(info
->WinType
.hwndHelp
, NULL
, rect
->left
, rect
->top
, width
, height
,
1578 SWP_NOZORDER
| SWP_NOACTIVATE
);
1582 static LRESULT CALLBACK
Help_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1587 if (HIWORD(wParam
) == BN_CLICKED
)
1588 TB_OnClick(hWnd
, LOWORD(wParam
));
1591 return Help_OnSize(hWnd
);
1593 ReleaseHelpViewer((HHInfo
*)GetWindowLongPtrW(hWnd
, 0));
1601 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1607 static BOOL
HH_CreateHelpWindow(HHInfo
*info
)
1609 HWND hWnd
, parent
= 0;
1610 RECT winPos
= info
->WinType
.rcWindowPos
;
1612 DWORD dwStyles
, dwExStyles
;
1613 DWORD x
, y
, width
= 0, height
= 0;
1616 static const WCHAR windowClassW
[] = {
1617 'H','H',' ', 'P','a','r','e','n','t',0
1620 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1621 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
1622 wcex
.lpfnWndProc
= Help_WndProc
;
1623 wcex
.cbClsExtra
= 0;
1624 wcex
.cbWndExtra
= sizeof(LONG_PTR
);
1625 wcex
.hInstance
= hhctrl_hinstance
;
1626 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1627 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1628 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
1629 wcex
.lpszMenuName
= NULL
;
1630 wcex
.lpszClassName
= windowClassW
;
1631 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1633 RegisterClassExW(&wcex
);
1635 /* Read in window parameters if available */
1636 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_STYLES
)
1638 dwStyles
= info
->WinType
.dwStyles
;
1639 if (!(info
->WinType
.dwStyles
& WS_CHILD
))
1640 dwStyles
|= WS_OVERLAPPEDWINDOW
;
1643 dwStyles
= WS_OVERLAPPEDWINDOW
| WS_VISIBLE
|
1644 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1646 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_EXSTYLES
)
1647 dwExStyles
= info
->WinType
.dwExStyles
;
1649 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
|
1650 WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
;
1652 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_RECT
)
1656 width
= winPos
.right
- x
;
1657 height
= winPos
.bottom
- y
;
1659 if (!width
|| !height
)
1661 x
= WINTYPE_DEFAULT_X
;
1662 y
= WINTYPE_DEFAULT_Y
;
1663 width
= WINTYPE_DEFAULT_WIDTH
;
1664 height
= WINTYPE_DEFAULT_HEIGHT
;
1667 if (!(info
->WinType
.fsWinProperties
& HHWIN_PROP_TRI_PANE
) && info
->WinType
.fNotExpanded
)
1669 if (!(info
->WinType
.fsValidMembers
& HHWIN_PARAM_NAV_WIDTH
) &&
1670 info
->WinType
.iNavWidth
== 0)
1672 info
->WinType
.iNavWidth
= WINTYPE_DEFAULT_NAVWIDTH
;
1675 x
+= info
->WinType
.iNavWidth
;
1676 width
-= info
->WinType
.iNavWidth
;
1680 caption
= info
->WinType
.pszCaption
;
1681 if (!*caption
) caption
= info
->pCHMInfo
->defTitle
;
1683 if (info
->WinType
.dwStyles
& WS_CHILD
)
1684 parent
= info
->WinType
.hwndCaller
;
1686 hWnd
= CreateWindowExW(dwExStyles
, windowClassW
, caption
,
1687 dwStyles
, x
, y
, width
, height
, parent
, NULL
, hhctrl_hinstance
, NULL
);
1691 ShowWindow(hWnd
, SW_SHOW
);
1694 /* store the pointer to the HH info struct */
1695 SetWindowLongPtrW(hWnd
, 0, (LONG_PTR
)info
);
1697 info
->WinType
.hwndHelp
= hWnd
;
1701 static void HH_CreateFont(HHInfo
*pHHInfo
)
1705 GetObjectW(GetStockObject(DEFAULT_GUI_FONT
), sizeof(LOGFONTW
), &lf
);
1706 lf
.lfWeight
= FW_NORMAL
;
1707 lf
.lfItalic
= FALSE
;
1708 lf
.lfUnderline
= FALSE
;
1710 pHHInfo
->hFont
= CreateFontIndirectW(&lf
);
1713 static void HH_InitRequiredControls(DWORD dwControls
)
1715 INITCOMMONCONTROLSEX icex
;
1717 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1718 icex
.dwICC
= dwControls
;
1719 InitCommonControlsEx(&icex
);
1722 /* Creates the whole package */
1723 static BOOL
CreateViewer(HHInfo
*pHHInfo
)
1725 HH_CreateFont(pHHInfo
);
1727 if (!HH_CreateHelpWindow(pHHInfo
))
1730 HH_InitRequiredControls(ICC_BAR_CLASSES
);
1732 if (!HH_AddToolbar(pHHInfo
))
1735 HH_RegisterChildWndClass(pHHInfo
);
1737 if (!HH_AddNavigationPane(pHHInfo
))
1740 HH_RegisterSizeBarClass(pHHInfo
);
1742 if (!HH_AddSizeBar(pHHInfo
))
1745 if (!HH_AddHTMLPane(pHHInfo
))
1748 if (!AddContentTab(pHHInfo
))
1751 if (!AddIndexTab(pHHInfo
))
1754 if (!AddIndexPopup(pHHInfo
))
1757 if (!AddSearchTab(pHHInfo
))
1760 InitContent(pHHInfo
);
1763 pHHInfo
->viewer_initialized
= TRUE
;
1767 void wintype_stringsW_free(struct wintype_stringsW
*stringsW
)
1769 heap_free(stringsW
->pszType
);
1770 heap_free(stringsW
->pszCaption
);
1771 heap_free(stringsW
->pszToc
);
1772 heap_free(stringsW
->pszIndex
);
1773 heap_free(stringsW
->pszFile
);
1774 heap_free(stringsW
->pszHome
);
1775 heap_free(stringsW
->pszJump1
);
1776 heap_free(stringsW
->pszJump2
);
1777 heap_free(stringsW
->pszUrlJump1
);
1778 heap_free(stringsW
->pszUrlJump2
);
1781 void wintype_stringsA_free(struct wintype_stringsA
*stringsA
)
1783 heap_free(stringsA
->pszType
);
1784 heap_free(stringsA
->pszCaption
);
1785 heap_free(stringsA
->pszToc
);
1786 heap_free(stringsA
->pszIndex
);
1787 heap_free(stringsA
->pszFile
);
1788 heap_free(stringsA
->pszHome
);
1789 heap_free(stringsA
->pszJump1
);
1790 heap_free(stringsA
->pszJump2
);
1791 heap_free(stringsA
->pszUrlJump1
);
1792 heap_free(stringsA
->pszUrlJump2
);
1793 heap_free(stringsA
->pszCustomTabs
);
1796 void ReleaseHelpViewer(HHInfo
*info
)
1798 TRACE("(%p)\n", info
);
1803 list_remove(&info
->entry
);
1805 wintype_stringsA_free(&info
->stringsA
);
1806 wintype_stringsW_free(&info
->stringsW
);
1809 CloseCHM(info
->pCHMInfo
);
1811 ReleaseWebBrowser(info
);
1812 ReleaseContent(info
);
1814 ReleaseSearch(info
);
1816 if(info
->contents
.hImageList
)
1817 ImageList_Destroy(info
->contents
.hImageList
);
1818 if(info
->WinType
.hwndHelp
)
1819 DestroyWindow(info
->WinType
.hwndHelp
);
1825 HHInfo
*CreateHelpViewer(HHInfo
*info
, LPCWSTR filename
, HWND caller
)
1832 info
= heap_alloc_zero(sizeof(HHInfo
));
1833 list_add_tail(&window_list
, &info
->entry
);
1836 /* Set the invalid tab ID (-1) as the default value for all
1837 * of the tabs, this matches a failed TCM_INSERTITEM call.
1839 for(i
=0;i
<sizeof(info
->tabs
)/sizeof(HHTab
);i
++)
1840 info
->tabs
[i
].id
= -1;
1842 OleInitialize(NULL
);
1844 info
->pCHMInfo
= OpenCHM(filename
);
1845 if(!info
->pCHMInfo
) {
1846 ReleaseHelpViewer(info
);
1850 if (!LoadWinTypeFromCHM(info
)) {
1851 ReleaseHelpViewer(info
);
1854 info
->WinType
.hwndCaller
= caller
;
1856 /* If the window is already open then load the file in that existing window */
1857 if ((tmp_info
= find_window(info
->WinType
.pszType
)) && tmp_info
!= info
)
1859 ReleaseHelpViewer(info
);
1860 return CreateHelpViewer(tmp_info
, filename
, caller
);
1863 if(!info
->viewer_initialized
&& !CreateViewer(info
)) {
1864 ReleaseHelpViewer(info
);
1872 * Search the table of HTML entities and return the corresponding ANSI symbol.
1874 static char find_html_symbol(const char *entity
, int entity_len
)
1876 int max
= sizeof(html_encoded_symbols
)/sizeof(html_encoded_symbols
[0])-1;
1881 int pos
= (min
+max
)/2;
1882 const char *encoded_symbol
= html_encoded_symbols
[pos
].html_code
;
1883 dir
= strncmp(encoded_symbol
, entity
, entity_len
);
1884 if(dir
== 0 && !encoded_symbol
[entity_len
]) return html_encoded_symbols
[pos
].ansi_symbol
;
1894 * Decode a string containing HTML encoded characters into a unicode string.
1896 WCHAR
*decode_html(const char *html_fragment
, int html_fragment_len
, UINT code_page
)
1898 const char *h
= html_fragment
, *amp
, *sem
;
1900 int len
, tmp_len
= 0;
1901 WCHAR
*unicode_text
;
1903 tmp
= heap_alloc(html_fragment_len
+1);
1907 amp
= strchr(h
, '&');
1910 /* Copy the characters prior to the HTML encoded character */
1911 memcpy(&tmp
[tmp_len
], h
, len
);
1913 amp
++; /* skip ampersand */
1914 sem
= strchr(amp
, ';');
1915 /* Require a semicolon after the ampersand */
1919 tmp
[tmp_len
++] = '&';
1922 /* Find the symbol either by using the ANSI character number (prefixed by the pound symbol)
1923 * or by searching the HTML entity table */
1927 char *endnum
= NULL
;
1930 tmp
= (char) strtol(amp
, &endnum
, 10);
1935 symbol
= find_html_symbol(amp
, len
);
1938 FIXME("Failed to translate HTML encoded character '&%.*s;'.\n", len
, amp
);
1940 tmp
[tmp_len
++] = '&';
1943 /* Insert the new symbol */
1945 tmp
[tmp_len
++] = symbol
;
1947 /* Convert any remaining characters */
1948 len
= html_fragment_len
-(h
-html_fragment
);
1949 memcpy(&tmp
[tmp_len
], h
, len
);
1951 tmp
[tmp_len
++] = 0; /* NULL-terminate the string */
1953 len
= MultiByteToWideChar(code_page
, 0, tmp
, tmp_len
, NULL
, 0);
1954 unicode_text
= heap_alloc(len
*sizeof(WCHAR
));
1955 MultiByteToWideChar(code_page
, 0, tmp
, tmp_len
, unicode_text
, len
);
1957 return unicode_text
;
1960 /* Find the HTMLHelp structure for an existing window title */
1961 HHInfo
*find_window(const WCHAR
*window
)
1965 LIST_FOR_EACH_ENTRY(info
, &window_list
, HHInfo
, entry
)
1967 if (strcmpW(info
->WinType
.pszType
, window
) == 0)