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 static const WCHAR szEmpty
[] = {0};
53 /* Loads a string from the resource file */
54 static LPWSTR
HH_LoadString(DWORD dwID
)
57 LPCWSTR stringresource
;
60 iSize
= LoadStringW(hhctrl_hinstance
, dwID
, (LPWSTR
)&stringresource
, 0);
62 string
= heap_alloc((iSize
+ 2) * sizeof(WCHAR
)); /* some strings (tab text) needs double-null termination */
63 memcpy(string
, stringresource
, iSize
*sizeof(WCHAR
));
69 static HRESULT
navigate_url(HHInfo
*info
, LPCWSTR surl
)
74 TRACE("%s\n", debugstr_w(surl
));
77 V_BSTR(&url
) = SysAllocString(surl
);
79 hres
= IWebBrowser2_Navigate2(info
->web_browser
, &url
, 0, 0, 0, 0);
84 TRACE("Navigation failed: %08x\n", hres
);
89 BOOL
NavigateToUrl(HHInfo
*info
, LPCWSTR surl
)
95 static const WCHAR url_indicator
[] = {':', '/', '/', 0};
97 TRACE("%s\n", debugstr_w(surl
));
99 if (strstrW(surl
, url_indicator
)) {
100 hres
= navigate_url(info
, surl
);
103 } /* look up in chm if it doesn't look like a full url */
105 SetChmPath(&chm_path
, info
->pCHMInfo
->szFile
, surl
);
106 ret
= NavigateToChm(info
, chm_path
.chm_file
, chm_path
.chm_index
);
108 heap_free(chm_path
.chm_file
);
109 heap_free(chm_path
.chm_index
);
114 static BOOL
AppendFullPathURL(LPCWSTR file
, LPWSTR buf
, LPCWSTR index
)
116 static const WCHAR url_format
[] =
117 {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0};
118 static const WCHAR slash
[] = {'/',0};
119 static const WCHAR empty
[] = {0};
120 WCHAR full_path
[MAX_PATH
];
122 TRACE("%s %p %s\n", debugstr_w(file
), buf
, debugstr_w(index
));
124 if(!GetFullPathNameW(file
, sizeof(full_path
)/sizeof(full_path
[0]), full_path
, NULL
)) {
125 WARN("GetFullPathName failed: %u\n", GetLastError());
129 wsprintfW(buf
, url_format
, full_path
, (!index
|| index
[0] == '/') ? empty
: slash
, index
);
133 BOOL
NavigateToChm(HHInfo
*info
, LPCWSTR file
, LPCWSTR index
)
135 WCHAR buf
[INTERNET_MAX_URL_LENGTH
];
138 TRACE("%p %s %s\n", info
, debugstr_w(file
), debugstr_w(index
));
140 if ((!info
->web_browser
) || !AppendFullPathURL(file
, buf
, index
))
144 if((ptr
= strchrW(buf
, '#')))
147 return SUCCEEDED(navigate_url(info
, buf
));
150 static void DoSync(HHInfo
*info
)
152 WCHAR buf
[INTERNET_MAX_URL_LENGTH
];
157 hres
= IWebBrowser2_get_LocationURL(info
->web_browser
, &url
);
161 WARN("get_LocationURL failed: %08x\n", hres
);
165 /* If we're not currently viewing a page in the active .chm file, abort */
166 if ((!AppendFullPathURL(info
->pszFile
, buf
, NULL
)) || (len
= lstrlenW(buf
) > lstrlenW(url
)))
172 if (lstrcmpiW(buf
, url
) > 0)
174 static const WCHAR delimW
[] = {':',':','/',0};
177 index
= strstrW(url
, delimW
);
180 ActivateContentTopic(info
->tabs
[TAB_CONTENTS
].hwnd
, index
+ 3, info
->content
); /* skip over ::/ */
188 #define SIZEBAR_WIDTH 4
190 static const WCHAR szSizeBarClass
[] = {
191 'H','H',' ','S','i','z','e','B','a','r',0
194 /* Draw the SizeBar */
195 static void SB_OnPaint(HWND hWnd
)
201 hdc
= BeginPaint(hWnd
, &ps
);
203 GetClientRect(hWnd
, &rc
);
208 FrameRect(hdc
, &rc
, GetStockObject(GRAY_BRUSH
));
210 /* white highlight */
211 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
212 MoveToEx(hdc
, rc
.right
, 1, NULL
);
214 LineTo(hdc
, 1, rc
.bottom
- 1);
217 MoveToEx(hdc
, 0, rc
.bottom
, NULL
);
218 LineTo(hdc
, rc
.right
, rc
.bottom
);
223 static void SB_OnLButtonDown(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
228 static void SB_OnLButtonUp(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
230 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
233 pt
.x
= (short)LOWORD(lParam
);
234 pt
.y
= (short)HIWORD(lParam
);
236 /* update the window sizes */
237 pHHInfo
->WinType
.iNavWidth
+= pt
.x
;
243 static void SB_OnMouseMove(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
245 /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
246 if (!(wParam
& MK_LBUTTON
))
250 static LRESULT CALLBACK
SizeBar_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
255 SB_OnLButtonDown(hWnd
, wParam
, lParam
);
258 SB_OnLButtonUp(hWnd
, wParam
, lParam
);
261 SB_OnMouseMove(hWnd
, wParam
, lParam
);
267 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
273 static void HH_RegisterSizeBarClass(HHInfo
*pHHInfo
)
277 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
279 wcex
.lpfnWndProc
= SizeBar_WndProc
;
282 wcex
.hInstance
= hhctrl_hinstance
;
283 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
284 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_SIZEWE
);
285 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
286 wcex
.lpszMenuName
= NULL
;
287 wcex
.lpszClassName
= szSizeBarClass
;
288 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
290 RegisterClassExW(&wcex
);
293 static void SB_GetSizeBarRect(HHInfo
*info
, RECT
*rc
)
295 RECT rectWND
, rectTB
, rectNP
;
297 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
298 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
299 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
301 rc
->left
= rectNP
.right
;
302 rc
->top
= rectTB
.bottom
;
303 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
304 rc
->right
= SIZEBAR_WIDTH
;
307 static BOOL
HH_AddSizeBar(HHInfo
*pHHInfo
)
310 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
311 DWORD dwStyles
= WS_CHILDWINDOW
| WS_OVERLAPPED
;
312 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
315 if (!pHHInfo
->WinType
.fNotExpanded
)
316 dwStyles
|= WS_VISIBLE
;
318 SB_GetSizeBarRect(pHHInfo
, &rc
);
320 hWnd
= CreateWindowExW(dwExStyles
, szSizeBarClass
, szEmpty
, dwStyles
,
321 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
322 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
326 /* store the pointer to the HH info struct */
327 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)pHHInfo
);
329 pHHInfo
->hwndSizeBar
= hWnd
;
335 static const WCHAR szChildClass
[] = {
336 'H','H',' ','C','h','i','l','d',0
339 static LRESULT
Child_OnPaint(HWND hWnd
)
345 hdc
= BeginPaint(hWnd
, &ps
);
347 /* Only paint the Navigation pane, identified by the fact
348 * that it has a child window
350 if (GetWindow(hWnd
, GW_CHILD
))
352 GetClientRect(hWnd
, &rc
);
354 /* set the border color */
355 SelectObject(hdc
, GetStockObject(DC_PEN
));
356 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
358 /* Draw the top border */
359 LineTo(hdc
, rc
.right
, 0);
361 SelectObject(hdc
, GetStockObject(WHITE_PEN
));
362 MoveToEx(hdc
, 0, 1, NULL
);
363 LineTo(hdc
, rc
.right
, 1);
371 static void ResizeTabChild(HHInfo
*info
, int tab
)
373 HWND hwnd
= info
->tabs
[tab
].hwnd
;
378 GetClientRect(info
->WinType
.hwndNavigation
, &rect
);
379 SendMessageW(info
->hwndTabCtrl
, TCM_GETITEMRECT
, 0, (LPARAM
)&tabrc
);
380 cnt
= SendMessageW(info
->hwndTabCtrl
, TCM_GETROWCOUNT
, 0, 0);
382 rect
.left
= TAB_MARGIN
;
383 rect
.top
= TAB_TOP_PADDING
+ cnt
*(tabrc
.bottom
-tabrc
.top
) + TAB_MARGIN
;
384 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
385 rect
.bottom
-= TAB_MARGIN
;
386 width
= rect
.right
-rect
.left
;
387 height
= rect
.bottom
-rect
.top
;
389 SetWindowPos(hwnd
, NULL
, rect
.left
, rect
.top
, width
, height
,
390 SWP_NOZORDER
| SWP_NOACTIVATE
);
395 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
396 int border_width
= GetSystemMetrics(SM_CXBORDER
);
397 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
399 /* Resize the tab widget column to perfectly fit the tab window and
400 * leave sufficient space for the scroll widget.
402 SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_SETCOLUMNWIDTH
, 0,
403 width
-scroll_width
-2*border_width
-2*edge_width
);
408 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
409 int border_width
= GetSystemMetrics(SM_CXBORDER
);
410 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
413 SetWindowPos(info
->search
.hwndEdit
, NULL
, 0, top_pos
, width
,
414 EDIT_HEIGHT
, SWP_NOZORDER
| SWP_NOACTIVATE
);
415 top_pos
+= EDIT_HEIGHT
+ TAB_MARGIN
;
416 SetWindowPos(info
->search
.hwndList
, NULL
, 0, top_pos
, width
,
417 height
-top_pos
, SWP_NOZORDER
| SWP_NOACTIVATE
);
418 /* Resize the tab widget column to perfectly fit the tab window and
419 * leave sufficient space for the scroll widget.
421 SendMessageW(info
->search
.hwndList
, LVM_SETCOLUMNWIDTH
, 0,
422 width
-scroll_width
-2*border_width
-2*edge_width
);
429 static LRESULT
Child_OnSize(HWND hwnd
)
431 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
434 if(!info
|| hwnd
!= info
->WinType
.hwndNavigation
)
437 GetClientRect(hwnd
, &rect
);
438 SetWindowPos(info
->hwndTabCtrl
, HWND_TOP
, 0, 0,
439 rect
.right
- TAB_RIGHT_PADDING
,
440 rect
.bottom
- TAB_TOP_PADDING
, SWP_NOMOVE
);
442 ResizeTabChild(info
, TAB_CONTENTS
);
443 ResizeTabChild(info
, TAB_INDEX
);
444 ResizeTabChild(info
, TAB_SEARCH
);
448 static LRESULT
OnTabChange(HWND hwnd
)
450 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
451 int tab_id
, tab_index
, i
;
458 if(info
->tabs
[info
->current_tab
].hwnd
)
459 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_HIDE
);
461 tab_id
= (int) SendMessageW(info
->hwndTabCtrl
, TCM_GETCURSEL
, 0, 0);
462 /* convert the ID of the tab to an index in our tab list */
464 for (i
=0; i
<TAB_NUMTABS
; i
++)
466 if (info
->tabs
[i
].id
== tab_id
)
474 FIXME("Tab ID %d does not correspond to a valid index in the tab list.\n", tab_id
);
477 info
->current_tab
= tab_index
;
479 if(info
->tabs
[info
->current_tab
].hwnd
)
480 ShowWindow(info
->tabs
[info
->current_tab
].hwnd
, SW_SHOW
);
485 static LRESULT
OnTopicChange(HHInfo
*info
, void *user_data
)
487 LPCWSTR chmfile
= NULL
, name
= NULL
, local
= NULL
;
492 if(!user_data
|| !info
)
495 switch (info
->current_tab
)
498 citer
= (ContentItem
*) user_data
;
500 local
= citer
->local
;
502 if(citer
->merge
.chm_file
) {
503 chmfile
= citer
->merge
.chm_file
;
506 citer
= citer
->parent
;
510 iiter
= (IndexItem
*) user_data
;
511 if(iiter
->nItems
== 0) {
512 FIXME("No entries for this item!\n");
515 if(iiter
->nItems
> 1) {
519 SendMessageW(info
->popup
.hwndList
, LVM_DELETEALLITEMS
, 0, 0);
520 for(i
=0;i
<iiter
->nItems
;i
++) {
521 IndexSubItem
*item
= &iiter
->items
[i
];
522 WCHAR
*name
= iiter
->keyword
;
526 memset(&lvi
, 0, sizeof(lvi
));
528 lvi
.mask
= LVIF_TEXT
|LVIF_PARAM
;
529 lvi
.cchTextMax
= strlenW(name
)+1;
531 lvi
.lParam
= (LPARAM
) item
;
532 SendMessageW(info
->popup
.hwndList
, LVM_INSERTITEMW
, 0, (LPARAM
)&lvi
);
534 ShowWindow(info
->popup
.hwndPopup
, SW_SHOW
);
537 name
= iiter
->items
[0].name
;
538 local
= iiter
->items
[0].local
;
539 chmfile
= iiter
->merge
.chm_file
;
542 siter
= (SearchItem
*) user_data
;
543 name
= siter
->filename
;
544 local
= siter
->filename
;
545 chmfile
= info
->pCHMInfo
->szFile
;
548 FIXME("Unhandled operation for this tab!\n");
554 FIXME("No help file found for this item!\n");
558 TRACE("name %s loal %s\n", debugstr_w(name
), debugstr_w(local
));
560 NavigateToChm(info
, chmfile
, local
);
564 /* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */
565 static LRESULT CALLBACK
EditChild_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
567 WNDPROC editWndProc
= (WNDPROC
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
569 if(message
== WM_KEYUP
&& wParam
== VK_RETURN
)
573 nmhdr
.hwndFrom
= hWnd
;
574 nmhdr
.code
= NM_RETURN
;
575 SendMessageW(GetParent(GetParent(hWnd
)), WM_NOTIFY
, wParam
, (LPARAM
)&nmhdr
);
577 return editWndProc(hWnd
, message
, wParam
, lParam
);
580 static LRESULT CALLBACK
Child_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
585 return Child_OnPaint(hWnd
);
587 return Child_OnSize(hWnd
);
589 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
590 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
592 switch(nmhdr
->code
) {
594 return OnTabChange(hWnd
);
595 case TVN_SELCHANGEDW
:
596 return OnTopicChange(info
, (void*)((NMTREEVIEWW
*)lParam
)->itemNew
.lParam
);
600 switch(info
->current_tab
)
603 return OnTopicChange(info
, (void*)((NMITEMACTIVATE
*)lParam
)->lParam
);
605 return OnTopicChange(info
, (void*)((NMITEMACTIVATE
*)lParam
)->lParam
);
611 switch(info
->current_tab
) {
613 HWND hwndList
= info
->tabs
[TAB_INDEX
].hwnd
;
616 lvItem
.iItem
= (int) SendMessageW(hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
617 lvItem
.mask
= TVIF_PARAM
;
618 SendMessageW(hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
619 OnTopicChange(info
, (void*) lvItem
.lParam
);
623 if(nmhdr
->hwndFrom
== info
->search
.hwndEdit
) {
627 len
= GetWindowTextA(info
->search
.hwndEdit
, needle
, sizeof(needle
));
630 FIXME("Unable to get search text.\n");
633 /* Convert the requested text for comparison later against the
634 * lower case version of HTML file contents.
637 needle
[i
] = tolower(needle
[i
]);
638 InitSearch(info
, needle
);
640 }else if(nmhdr
->hwndFrom
== info
->search
.hwndList
) {
641 HWND hwndList
= info
->search
.hwndList
;
644 lvItem
.iItem
= (int) SendMessageW(hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
645 lvItem
.mask
= TVIF_PARAM
;
646 SendMessageW(hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
647 OnTopicChange(info
, (void*) lvItem
.lParam
);
658 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
664 static void HH_RegisterChildWndClass(HHInfo
*pHHInfo
)
668 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
670 wcex
.lpfnWndProc
= Child_WndProc
;
673 wcex
.hInstance
= hhctrl_hinstance
;
674 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
675 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
676 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
677 wcex
.lpszMenuName
= NULL
;
678 wcex
.lpszClassName
= szChildClass
;
679 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
681 RegisterClassExW(&wcex
);
688 static void DisplayPopupMenu(HHInfo
*info
)
691 TBBUTTONINFOW button
;
697 menu
= LoadMenuW(hhctrl_hinstance
, MAKEINTRESOURCEW(MENU_POPUP
));
702 submenu
= GetSubMenu(menu
, 0);
704 /* Update the Show/Hide menu item */
705 item
.cbSize
= sizeof(MENUITEMINFOW
);
706 item
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_STRING
;
707 item
.fType
= MFT_STRING
;
708 item
.fState
= MF_ENABLED
;
710 if (info
->WinType
.fNotExpanded
)
711 item
.dwTypeData
= HH_LoadString(IDS_SHOWTABS
);
713 item
.dwTypeData
= HH_LoadString(IDS_HIDETABS
);
715 SetMenuItemInfoW(submenu
, IDTB_EXPAND
, FALSE
, &item
);
716 heap_free(item
.dwTypeData
);
718 /* Find the index toolbar button */
719 button
.cbSize
= sizeof(TBBUTTONINFOW
);
720 button
.dwMask
= TBIF_COMMAND
;
721 index
= SendMessageW(info
->WinType
.hwndToolBar
, TB_GETBUTTONINFOW
, IDTB_OPTIONS
, (LPARAM
) &button
);
727 SendMessageW(info
->WinType
.hwndToolBar
, TB_GETITEMRECT
, index
, (LPARAM
) &rect
);
729 coords
.x
= rect
.left
;
730 coords
.y
= rect
.bottom
;
732 ClientToScreen(info
->WinType
.hwndToolBar
, &coords
);
733 TrackPopupMenu(submenu
, TPM_LEFTALIGN
| TPM_TOPALIGN
| TPM_LEFTBUTTON
| TPM_NOANIMATION
, coords
.x
, coords
.y
, 0, info
->WinType
.hwndHelp
, NULL
);
736 static void TB_OnClick(HWND hWnd
, DWORD dwID
)
738 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
743 DoPageAction(info
, WB_STOP
);
746 DoPageAction(info
, WB_REFRESH
);
749 DoPageAction(info
, WB_GOBACK
);
752 NavigateToChm(info
, info
->pCHMInfo
->szFile
, info
->WinType
.pszHome
);
755 DoPageAction(info
, WB_GOFORWARD
);
758 DoPageAction(info
, WB_PRINT
);
762 ExpandContract(info
);
768 DisplayPopupMenu(info
);
776 /* These are officially unimplemented as of the Windows 7 SDK */
778 case IDTB_BROWSE_FWD
:
779 case IDTB_BROWSE_BACK
:
790 static void TB_AddButton(TBBUTTON
*pButtons
, DWORD dwIndex
, DWORD dwID
, DWORD dwBitmap
)
792 pButtons
[dwIndex
].iBitmap
= dwBitmap
;
793 pButtons
[dwIndex
].idCommand
= dwID
;
794 pButtons
[dwIndex
].fsState
= TBSTATE_ENABLED
;
795 pButtons
[dwIndex
].fsStyle
= BTNS_BUTTON
;
796 pButtons
[dwIndex
].dwData
= 0;
797 pButtons
[dwIndex
].iString
= 0;
800 static void TB_AddButtonsFromFlags(HHInfo
*pHHInfo
, TBBUTTON
*pButtons
, DWORD dwButtonFlags
, LPDWORD pdwNumButtons
)
802 int nHistBitmaps
= 0, nStdBitmaps
= 0, nHHBitmaps
= 0;
803 HWND hToolbar
= pHHInfo
->WinType
.hwndToolBar
;
808 tbAB
.hInst
= HINST_COMMCTRL
;
809 tbAB
.nID
= IDB_HIST_LARGE_COLOR
;
810 nHistBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbAB
);
811 tbAB
.nID
= IDB_STD_LARGE_COLOR
;
812 nStdBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbAB
);
813 /* hhctrl.ocx bitmaps */
814 tbAB
.hInst
= hhctrl_hinstance
;
815 tbAB
.nID
= IDB_HHTOOLBAR
;
816 nHHBitmaps
= SendMessageW(hToolbar
, TB_ADDBITMAP
, HHTB_NUMBITMAPS
, (LPARAM
)&tbAB
);
820 unsupported
= dwButtonFlags
& (HHWIN_BUTTON_BROWSE_FWD
|
821 HHWIN_BUTTON_BROWSE_BCK
| HHWIN_BUTTON_NOTES
| HHWIN_BUTTON_CONTENTS
|
822 HHWIN_BUTTON_INDEX
| HHWIN_BUTTON_SEARCH
| HHWIN_BUTTON_HISTORY
|
823 HHWIN_BUTTON_FAVORITES
| HHWIN_BUTTON_JUMP1
| HHWIN_BUTTON_JUMP2
|
824 HHWIN_BUTTON_ZOOM
| HHWIN_BUTTON_TOC_NEXT
| HHWIN_BUTTON_TOC_PREV
);
826 FIXME("got asked for unsupported buttons: %06x\n", unsupported
);
828 if (dwButtonFlags
& HHWIN_BUTTON_EXPAND
)
830 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_EXPAND
, nHHBitmaps
+ HHTB_EXPAND
);
831 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_CONTRACT
, nHHBitmaps
+ HHTB_CONTRACT
);
833 if (pHHInfo
->WinType
.fNotExpanded
)
834 pButtons
[1].fsState
|= TBSTATE_HIDDEN
;
836 pButtons
[0].fsState
|= TBSTATE_HIDDEN
;
839 if (dwButtonFlags
& HHWIN_BUTTON_BACK
)
840 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_BACK
, nHistBitmaps
+ HIST_BACK
);
842 if (dwButtonFlags
& HHWIN_BUTTON_FORWARD
)
843 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_FORWARD
, nHistBitmaps
+ HIST_FORWARD
);
845 if (dwButtonFlags
& HHWIN_BUTTON_STOP
)
846 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_STOP
, nHHBitmaps
+ HHTB_STOP
);
848 if (dwButtonFlags
& HHWIN_BUTTON_REFRESH
)
849 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_REFRESH
, nHHBitmaps
+ HHTB_REFRESH
);
851 if (dwButtonFlags
& HHWIN_BUTTON_HOME
)
852 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_HOME
, nHHBitmaps
+ HHTB_HOME
);
854 if (dwButtonFlags
& HHWIN_BUTTON_SYNC
)
855 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_SYNC
, nHHBitmaps
+ HHTB_SYNC
);
857 if (dwButtonFlags
& HHWIN_BUTTON_OPTIONS
)
858 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_OPTIONS
, nStdBitmaps
+ STD_PROPERTIES
);
860 if (dwButtonFlags
& HHWIN_BUTTON_PRINT
)
861 TB_AddButton(pButtons
, (*pdwNumButtons
)++, IDTB_PRINT
, nStdBitmaps
+ STD_PRINT
);
864 static BOOL
HH_AddToolbar(HHInfo
*pHHInfo
)
867 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
869 TBBUTTON buttons
[IDTB_TOC_PREV
- IDTB_EXPAND
];
870 DWORD dwStyles
, dwExStyles
;
871 DWORD dwNumButtons
, dwIndex
;
873 if (pHHInfo
->WinType
.fsWinProperties
& HHWIN_PARAM_TB_FLAGS
)
874 toolbarFlags
= pHHInfo
->WinType
.fsToolBarFlags
;
876 toolbarFlags
= HHWIN_DEF_BUTTONS
;
878 dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| TBSTYLE_FLAT
|
879 TBSTYLE_WRAPABLE
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
;
880 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
882 hToolbar
= CreateWindowExW(dwExStyles
, TOOLBARCLASSNAMEW
, NULL
, dwStyles
,
883 0, 0, 0, 0, hwndParent
, NULL
,
884 hhctrl_hinstance
, NULL
);
887 pHHInfo
->WinType
.hwndToolBar
= hToolbar
;
889 SendMessageW(hToolbar
, TB_SETBITMAPSIZE
, 0, MAKELONG(ICON_SIZE
, ICON_SIZE
));
890 SendMessageW(hToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
891 SendMessageW(hToolbar
, WM_SETFONT
, (WPARAM
)pHHInfo
->hFont
, TRUE
);
893 TB_AddButtonsFromFlags(pHHInfo
, buttons
, toolbarFlags
, &dwNumButtons
);
895 for (dwIndex
= 0; dwIndex
< dwNumButtons
; dwIndex
++)
897 LPWSTR szBuf
= HH_LoadString(buttons
[dwIndex
].idCommand
);
898 DWORD dwLen
= strlenW(szBuf
);
899 szBuf
[dwLen
+ 1] = 0; /* Double-null terminate */
901 buttons
[dwIndex
].iString
= (DWORD
)SendMessageW(hToolbar
, TB_ADDSTRINGW
, 0, (LPARAM
)szBuf
);
905 SendMessageW(hToolbar
, TB_ADDBUTTONSW
, dwNumButtons
, (LPARAM
)buttons
);
906 SendMessageW(hToolbar
, TB_AUTOSIZE
, 0, 0);
907 ShowWindow(hToolbar
, SW_SHOW
);
912 /* Navigation Pane */
914 static void NP_GetNavigationRect(HHInfo
*pHHInfo
, RECT
*rc
)
916 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
917 HWND hwndToolbar
= pHHInfo
->WinType
.hwndToolBar
;
918 RECT rectWND
, rectTB
;
920 GetClientRect(hwndParent
, &rectWND
);
921 GetClientRect(hwndToolbar
, &rectTB
);
924 rc
->top
= rectTB
.bottom
;
925 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
927 if (!(pHHInfo
->WinType
.fsValidMembers
& HHWIN_PARAM_NAV_WIDTH
) &&
928 pHHInfo
->WinType
.iNavWidth
== 0)
930 pHHInfo
->WinType
.iNavWidth
= WINTYPE_DEFAULT_NAVWIDTH
;
933 rc
->right
= pHHInfo
->WinType
.iNavWidth
;
936 static DWORD
NP_CreateTab(HINSTANCE hInstance
, HWND hwndTabCtrl
, DWORD index
)
939 LPWSTR tabText
= HH_LoadString(index
);
942 tie
.mask
= TCIF_TEXT
;
943 tie
.pszText
= tabText
;
945 ret
= SendMessageW( hwndTabCtrl
, TCM_INSERTITEMW
, index
, (LPARAM
)&tie
);
951 static BOOL
HH_AddNavigationPane(HHInfo
*info
)
953 HWND hWnd
, hwndTabCtrl
;
954 HWND hwndParent
= info
->WinType
.hwndHelp
;
955 DWORD dwStyles
= WS_CHILDWINDOW
;
956 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
;
959 if (!info
->WinType
.fNotExpanded
)
960 dwStyles
|= WS_VISIBLE
;
962 NP_GetNavigationRect(info
, &rc
);
964 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
965 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
966 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
970 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
972 hwndTabCtrl
= CreateWindowExW(dwExStyles
, WC_TABCONTROLW
, szEmpty
, dwStyles
| WS_VISIBLE
,
974 rc
.right
- TAB_RIGHT_PADDING
,
975 rc
.bottom
- TAB_TOP_PADDING
,
976 hWnd
, NULL
, hhctrl_hinstance
, NULL
);
980 if (*info
->WinType
.pszToc
)
981 info
->tabs
[TAB_CONTENTS
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_CONTENTS
);
983 if (*info
->WinType
.pszIndex
)
984 info
->tabs
[TAB_INDEX
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_INDEX
);
986 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_SEARCH
)
987 info
->tabs
[TAB_SEARCH
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_SEARCH
);
989 if (info
->WinType
.fsWinProperties
& HHWIN_PROP_TAB_FAVORITES
)
990 info
->tabs
[TAB_FAVORITES
].id
= NP_CreateTab(hhctrl_hinstance
, hwndTabCtrl
, IDS_FAVORITES
);
992 SendMessageW(hwndTabCtrl
, WM_SETFONT
, (WPARAM
)info
->hFont
, TRUE
);
994 info
->hwndTabCtrl
= hwndTabCtrl
;
995 info
->WinType
.hwndNavigation
= hWnd
;
1001 static void HP_GetHTMLRect(HHInfo
*info
, RECT
*rc
)
1003 RECT rectTB
, rectWND
, rectNP
, rectSB
;
1005 GetClientRect(info
->WinType
.hwndHelp
, &rectWND
);
1006 GetClientRect(info
->WinType
.hwndToolBar
, &rectTB
);
1007 GetClientRect(info
->hwndSizeBar
, &rectSB
);
1009 if (info
->WinType
.fNotExpanded
)
1013 GetClientRect(info
->WinType
.hwndNavigation
, &rectNP
);
1014 rc
->left
= rectNP
.right
+ rectSB
.right
;
1017 rc
->top
= rectTB
.bottom
;
1018 rc
->right
= rectWND
.right
- rc
->left
;
1019 rc
->bottom
= rectWND
.bottom
- rectTB
.bottom
;
1022 static BOOL
HH_AddHTMLPane(HHInfo
*pHHInfo
)
1025 HWND hwndParent
= pHHInfo
->WinType
.hwndHelp
;
1026 DWORD dwStyles
= WS_CHILDWINDOW
| WS_VISIBLE
| WS_CLIPCHILDREN
;
1027 DWORD dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
| WS_EX_CLIENTEDGE
;
1030 HP_GetHTMLRect(pHHInfo
, &rc
);
1032 hWnd
= CreateWindowExW(dwExStyles
, szChildClass
, szEmpty
, dwStyles
,
1033 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
,
1034 hwndParent
, NULL
, hhctrl_hinstance
, NULL
);
1038 if (!InitWebBrowser(pHHInfo
, hWnd
))
1041 /* store the pointer to the HH info struct */
1042 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)pHHInfo
);
1044 ShowWindow(hWnd
, SW_SHOW
);
1047 pHHInfo
->WinType
.hwndHTML
= hWnd
;
1051 static BOOL
AddContentTab(HHInfo
*info
)
1053 if(info
->tabs
[TAB_CONTENTS
].id
== -1)
1054 return TRUE
; /* No "Contents" tab */
1055 info
->tabs
[TAB_CONTENTS
].hwnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_TREEVIEWW
,
1056 szEmpty
, WS_CHILD
| WS_BORDER
| 0x25, 50, 50, 100, 100,
1057 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
1058 if(!info
->tabs
[TAB_CONTENTS
].hwnd
) {
1059 ERR("Could not create treeview control\n");
1063 ResizeTabChild(info
, TAB_CONTENTS
);
1064 ShowWindow(info
->tabs
[TAB_CONTENTS
].hwnd
, SW_SHOW
);
1069 static BOOL
AddIndexTab(HHInfo
*info
)
1071 char hidden_column
[] = "Column";
1074 if(info
->tabs
[TAB_INDEX
].id
== -1)
1075 return TRUE
; /* No "Index" tab */
1076 info
->tabs
[TAB_INDEX
].hwnd
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
,
1077 szEmpty
, WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
| LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
1078 info
->WinType
.hwndNavigation
, NULL
, hhctrl_hinstance
, NULL
);
1079 if(!info
->tabs
[TAB_INDEX
].hwnd
) {
1080 ERR("Could not create ListView control\n");
1083 memset(&lvc
, 0, sizeof(lvc
));
1084 lvc
.mask
= LVCF_TEXT
;
1085 lvc
.pszText
= hidden_column
;
1086 if(SendMessageW(info
->tabs
[TAB_INDEX
].hwnd
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1088 ERR("Could not create ListView column\n");
1092 ResizeTabChild(info
, TAB_INDEX
);
1093 ShowWindow(info
->tabs
[TAB_INDEX
].hwnd
, SW_HIDE
);
1098 static BOOL
AddSearchTab(HHInfo
*info
)
1100 HWND hwndList
, hwndEdit
, hwndContainer
;
1101 char hidden_column
[] = "Column";
1102 WNDPROC editWndProc
;
1105 if(info
->tabs
[TAB_SEARCH
].id
== -1)
1106 return TRUE
; /* No "Search" tab */
1107 hwndContainer
= CreateWindowExW(WS_EX_CONTROLPARENT
, szChildClass
, szEmpty
,
1108 WS_CHILD
, 0, 0, 0, 0, info
->WinType
.hwndNavigation
,
1109 NULL
, hhctrl_hinstance
, NULL
);
1110 if(!hwndContainer
) {
1111 ERR("Could not create search window container control.\n");
1114 hwndEdit
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_EDITW
, szEmpty
, WS_CHILD
1115 | WS_VISIBLE
| ES_LEFT
| SS_NOTIFY
, 0, 0, 0, 0,
1116 hwndContainer
, NULL
, hhctrl_hinstance
, NULL
);
1118 ERR("Could not create search ListView control.\n");
1121 if(SendMessageW(hwndEdit
, WM_SETFONT
, (WPARAM
) info
->hFont
, (LPARAM
) FALSE
) == -1)
1123 ERR("Could not set font for edit control.\n");
1126 editWndProc
= (WNDPROC
) SetWindowLongPtrW(hwndEdit
, GWLP_WNDPROC
, (LONG_PTR
)EditChild_WndProc
);
1128 ERR("Could not redirect messages for edit control.\n");
1131 SetWindowLongPtrW(hwndEdit
, GWLP_USERDATA
, (LONG_PTR
)editWndProc
);
1132 hwndList
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
, szEmpty
,
1133 WS_CHILD
| WS_VISIBLE
| WS_BORDER
| LVS_SINGLESEL
1134 | LVS_REPORT
| LVS_NOCOLUMNHEADER
, 0, 0, 0, 0,
1135 hwndContainer
, NULL
, hhctrl_hinstance
, NULL
);
1137 ERR("Could not create search ListView control.\n");
1140 memset(&lvc
, 0, sizeof(lvc
));
1141 lvc
.mask
= LVCF_TEXT
;
1142 lvc
.pszText
= hidden_column
;
1143 if(SendMessageW(hwndList
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1145 ERR("Could not create ListView column\n");
1149 info
->search
.hwndEdit
= hwndEdit
;
1150 info
->search
.hwndList
= hwndList
;
1151 info
->search
.hwndContainer
= hwndContainer
;
1152 info
->tabs
[TAB_SEARCH
].hwnd
= hwndContainer
;
1154 SetWindowLongPtrW(hwndContainer
, GWLP_USERDATA
, (LONG_PTR
)info
);
1156 ResizeTabChild(info
, TAB_SEARCH
);
1161 /* The Index tab's sub-topic popup */
1163 static void ResizePopupChild(HHInfo
*info
)
1165 int scroll_width
= GetSystemMetrics(SM_CXVSCROLL
);
1166 int border_width
= GetSystemMetrics(SM_CXBORDER
);
1167 int edge_width
= GetSystemMetrics(SM_CXEDGE
);
1174 GetClientRect(info
->popup
.hwndPopup
, &rect
);
1175 SetWindowPos(info
->popup
.hwndCallback
, HWND_TOP
, 0, 0,
1176 rect
.right
, rect
.bottom
, SWP_NOMOVE
);
1178 rect
.left
= TAB_MARGIN
;
1179 rect
.top
= TAB_TOP_PADDING
+ TAB_MARGIN
;
1180 rect
.right
-= TAB_RIGHT_PADDING
+ TAB_MARGIN
;
1181 rect
.bottom
-= TAB_MARGIN
;
1182 width
= rect
.right
-rect
.left
;
1183 height
= rect
.bottom
-rect
.top
;
1185 SetWindowPos(info
->popup
.hwndList
, NULL
, rect
.left
, rect
.top
, width
, height
,
1186 SWP_NOZORDER
| SWP_NOACTIVATE
);
1188 SendMessageW(info
->popup
.hwndList
, LVM_SETCOLUMNWIDTH
, 0,
1189 width
-scroll_width
-2*border_width
-2*edge_width
);
1192 static LRESULT CALLBACK
HelpPopup_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1194 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
1199 ResizePopupChild(info
);
1202 DestroyWindow(hWnd
);
1205 ShowWindow(hWnd
, SW_HIDE
);
1209 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1215 static LRESULT CALLBACK
PopupChild_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1220 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1224 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
1227 if(info
== 0 || lParam
== 0)
1229 iter
= (IndexSubItem
*) ((NMITEMACTIVATE
*)lParam
)->lParam
;
1232 NavigateToChm(info
, info
->index
->merge
.chm_file
, iter
->local
);
1233 ShowWindow(info
->popup
.hwndPopup
, SW_HIDE
);
1237 HHInfo
*info
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
1244 lvItem
.iItem
= (int) SendMessageW(info
->popup
.hwndList
, LVM_GETSELECTIONMARK
, 0, 0);
1245 lvItem
.mask
= TVIF_PARAM
;
1246 SendMessageW(info
->popup
.hwndList
, LVM_GETITEMW
, 0, (LPARAM
)&lvItem
);
1247 iter
= (IndexSubItem
*) lvItem
.lParam
;
1248 NavigateToChm(info
, info
->index
->merge
.chm_file
, iter
->local
);
1249 ShowWindow(info
->popup
.hwndPopup
, SW_HIDE
);
1256 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1262 static BOOL
AddIndexPopup(HHInfo
*info
)
1264 static const WCHAR szPopupChildClass
[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0};
1265 static const WCHAR windowCaptionW
[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0};
1266 static const WCHAR windowClassW
[] = {'H','H',' ','P','o','p','u','p',0};
1267 HWND hwndList
, hwndPopup
, hwndCallback
;
1268 char hidden_column
[] = "Column";
1272 if(info
->tabs
[TAB_INDEX
].id
== -1)
1273 return TRUE
; /* No "Index" tab */
1275 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1276 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
1277 wcex
.lpfnWndProc
= HelpPopup_WndProc
;
1278 wcex
.cbClsExtra
= 0;
1279 wcex
.cbWndExtra
= 0;
1280 wcex
.hInstance
= hhctrl_hinstance
;
1281 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1282 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1283 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
1284 wcex
.lpszMenuName
= NULL
;
1285 wcex
.lpszClassName
= windowClassW
;
1286 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1287 RegisterClassExW(&wcex
);
1289 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1291 wcex
.lpfnWndProc
= PopupChild_WndProc
;
1292 wcex
.cbClsExtra
= 0;
1293 wcex
.cbWndExtra
= 0;
1294 wcex
.hInstance
= hhctrl_hinstance
;
1295 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1296 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1297 wcex
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1298 wcex
.lpszMenuName
= NULL
;
1299 wcex
.lpszClassName
= szPopupChildClass
;
1300 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1301 RegisterClassExW(&wcex
);
1303 hwndPopup
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
1304 | WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
,
1305 windowClassW
, windowCaptionW
, WS_POPUPWINDOW
1306 | WS_OVERLAPPEDWINDOW
| WS_VISIBLE
1307 | WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
, CW_USEDEFAULT
,
1308 CW_USEDEFAULT
, 300, 200, info
->WinType
.hwndHelp
,
1309 NULL
, hhctrl_hinstance
, NULL
);
1313 hwndCallback
= CreateWindowExW(WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
,
1314 szPopupChildClass
, szEmpty
, WS_CHILDWINDOW
| WS_VISIBLE
,
1316 hwndPopup
, NULL
, hhctrl_hinstance
, NULL
);
1320 ShowWindow(hwndPopup
, SW_HIDE
);
1321 hwndList
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_LISTVIEWW
, szEmpty
,
1322 WS_CHILD
| WS_BORDER
| LVS_SINGLESEL
| LVS_REPORT
1323 | LVS_NOCOLUMNHEADER
, 50, 50, 100, 100,
1324 hwndCallback
, NULL
, hhctrl_hinstance
, NULL
);
1326 ERR("Could not create popup ListView control\n");
1329 memset(&lvc
, 0, sizeof(lvc
));
1330 lvc
.mask
= LVCF_TEXT
;
1331 lvc
.pszText
= hidden_column
;
1332 if(SendMessageW(hwndList
, LVM_INSERTCOLUMNA
, 0, (LPARAM
) &lvc
) == -1)
1334 ERR("Could not create popup ListView column\n");
1338 info
->popup
.hwndCallback
= hwndCallback
;
1339 info
->popup
.hwndPopup
= hwndPopup
;
1340 info
->popup
.hwndList
= hwndList
;
1341 SetWindowLongPtrW(hwndPopup
, GWLP_USERDATA
, (LONG_PTR
)info
);
1342 SetWindowLongPtrW(hwndCallback
, GWLP_USERDATA
, (LONG_PTR
)info
);
1344 ResizePopupChild(info
);
1345 ShowWindow(hwndList
, SW_SHOW
);
1352 static void ExpandContract(HHInfo
*pHHInfo
)
1356 pHHInfo
->WinType
.fNotExpanded
= !pHHInfo
->WinType
.fNotExpanded
;
1357 GetWindowRect(pHHInfo
->WinType
.hwndHelp
, &r
);
1358 NP_GetNavigationRect(pHHInfo
, &nav
);
1360 /* hide/show both the nav bar and the size bar */
1361 if (pHHInfo
->WinType
.fNotExpanded
)
1363 ShowWindow(pHHInfo
->WinType
.hwndNavigation
, SW_HIDE
);
1364 ShowWindow(pHHInfo
->hwndSizeBar
, SW_HIDE
);
1365 r
.left
= r
.left
+ nav
.right
;
1367 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_EXPAND
, MAKELPARAM(FALSE
, 0));
1368 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_CONTRACT
, MAKELPARAM(TRUE
, 0));
1372 ShowWindow(pHHInfo
->WinType
.hwndNavigation
, SW_SHOW
);
1373 ShowWindow(pHHInfo
->hwndSizeBar
, SW_SHOW
);
1374 r
.left
= r
.left
- nav
.right
;
1376 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_EXPAND
, MAKELPARAM(TRUE
, 0));
1377 SendMessageW(pHHInfo
->WinType
.hwndToolBar
, TB_HIDEBUTTON
, IDTB_CONTRACT
, MAKELPARAM(FALSE
, 0));
1380 MoveWindow(pHHInfo
->WinType
.hwndHelp
, r
.left
, r
.top
, r
.right
-r
.left
, r
.bottom
-r
.top
, TRUE
);
1383 static LRESULT
Help_OnSize(HWND hWnd
)
1385 HHInfo
*pHHInfo
= (HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
1392 if (!pHHInfo
->WinType
.fNotExpanded
)
1394 NP_GetNavigationRect(pHHInfo
, &rc
);
1395 SetWindowPos(pHHInfo
->WinType
.hwndNavigation
, HWND_TOP
, 0, 0,
1396 rc
.right
, rc
.bottom
, SWP_NOMOVE
);
1398 SB_GetSizeBarRect(pHHInfo
, &rc
);
1399 SetWindowPos(pHHInfo
->hwndSizeBar
, HWND_TOP
, rc
.left
, rc
.top
,
1400 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1404 HP_GetHTMLRect(pHHInfo
, &rc
);
1405 SetWindowPos(pHHInfo
->WinType
.hwndHTML
, HWND_TOP
, rc
.left
, rc
.top
,
1406 rc
.right
, rc
.bottom
, SWP_SHOWWINDOW
);
1408 /* Resize browser window taking the frame size into account */
1409 dwSize
= GetSystemMetrics(SM_CXFRAME
);
1410 ResizeWebBrowser(pHHInfo
, rc
.right
- dwSize
, rc
.bottom
- dwSize
);
1415 static LRESULT CALLBACK
Help_WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1420 if (HIWORD(wParam
) == BN_CLICKED
)
1421 TB_OnClick(hWnd
, LOWORD(wParam
));
1424 return Help_OnSize(hWnd
);
1426 ReleaseHelpViewer((HHInfo
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
));
1434 return DefWindowProcW(hWnd
, message
, wParam
, lParam
);
1440 static BOOL
HH_CreateHelpWindow(HHInfo
*info
)
1443 RECT winPos
= info
->WinType
.rcWindowPos
;
1445 DWORD dwStyles
, dwExStyles
;
1446 DWORD x
, y
, width
= 0, height
= 0;
1449 static const WCHAR windowClassW
[] = {
1450 'H','H',' ', 'P','a','r','e','n','t',0
1453 wcex
.cbSize
= sizeof(WNDCLASSEXW
);
1454 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
1455 wcex
.lpfnWndProc
= Help_WndProc
;
1456 wcex
.cbClsExtra
= 0;
1457 wcex
.cbWndExtra
= 0;
1458 wcex
.hInstance
= hhctrl_hinstance
;
1459 wcex
.hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1460 wcex
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
)IDC_ARROW
);
1461 wcex
.hbrBackground
= (HBRUSH
)(COLOR_MENU
+ 1);
1462 wcex
.lpszMenuName
= NULL
;
1463 wcex
.lpszClassName
= windowClassW
;
1464 wcex
.hIconSm
= LoadIconW(NULL
, (LPCWSTR
)IDI_APPLICATION
);
1466 RegisterClassExW(&wcex
);
1468 /* Read in window parameters if available */
1469 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_STYLES
)
1470 dwStyles
= info
->WinType
.dwStyles
| WS_OVERLAPPEDWINDOW
;
1472 dwStyles
= WS_OVERLAPPEDWINDOW
| WS_VISIBLE
|
1473 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1475 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_EXSTYLES
)
1476 dwExStyles
= info
->WinType
.dwExStyles
;
1478 dwExStyles
= WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_APPWINDOW
|
1479 WS_EX_WINDOWEDGE
| WS_EX_RIGHTSCROLLBAR
;
1481 if (info
->WinType
.fsValidMembers
& HHWIN_PARAM_RECT
)
1485 width
= winPos
.right
- x
;
1486 height
= winPos
.bottom
- y
;
1488 if (!width
|| !height
)
1490 x
= WINTYPE_DEFAULT_X
;
1491 y
= WINTYPE_DEFAULT_Y
;
1492 width
= WINTYPE_DEFAULT_WIDTH
;
1493 height
= WINTYPE_DEFAULT_HEIGHT
;
1496 if (info
->WinType
.fNotExpanded
)
1498 if (!(info
->WinType
.fsValidMembers
& HHWIN_PARAM_NAV_WIDTH
) &&
1499 info
->WinType
.iNavWidth
== 0)
1501 info
->WinType
.iNavWidth
= WINTYPE_DEFAULT_NAVWIDTH
;
1504 x
+= info
->WinType
.iNavWidth
;
1505 width
-= info
->WinType
.iNavWidth
;
1509 caption
= info
->WinType
.pszCaption
;
1510 if (!*caption
) caption
= info
->pCHMInfo
->defTitle
;
1512 hWnd
= CreateWindowExW(dwExStyles
, windowClassW
, caption
,
1513 dwStyles
, x
, y
, width
, height
, NULL
, NULL
, hhctrl_hinstance
, NULL
);
1517 ShowWindow(hWnd
, SW_SHOW
);
1520 /* store the pointer to the HH info struct */
1521 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
1523 info
->WinType
.hwndHelp
= hWnd
;
1527 static void HH_CreateFont(HHInfo
*pHHInfo
)
1531 GetObjectW(GetStockObject(DEFAULT_GUI_FONT
), sizeof(LOGFONTW
), &lf
);
1532 lf
.lfWeight
= FW_NORMAL
;
1533 lf
.lfItalic
= FALSE
;
1534 lf
.lfUnderline
= FALSE
;
1536 pHHInfo
->hFont
= CreateFontIndirectW(&lf
);
1539 static void HH_InitRequiredControls(DWORD dwControls
)
1541 INITCOMMONCONTROLSEX icex
;
1543 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1544 icex
.dwICC
= dwControls
;
1545 InitCommonControlsEx(&icex
);
1548 /* Creates the whole package */
1549 static BOOL
CreateViewer(HHInfo
*pHHInfo
)
1551 HH_CreateFont(pHHInfo
);
1553 if (!HH_CreateHelpWindow(pHHInfo
))
1556 HH_InitRequiredControls(ICC_BAR_CLASSES
);
1558 if (!HH_AddToolbar(pHHInfo
))
1561 HH_RegisterChildWndClass(pHHInfo
);
1563 if (!HH_AddNavigationPane(pHHInfo
))
1566 HH_RegisterSizeBarClass(pHHInfo
);
1568 if (!HH_AddSizeBar(pHHInfo
))
1571 if (!HH_AddHTMLPane(pHHInfo
))
1574 if (!AddContentTab(pHHInfo
))
1577 if (!AddIndexTab(pHHInfo
))
1580 if (!AddIndexPopup(pHHInfo
))
1583 if (!AddSearchTab(pHHInfo
))
1586 InitContent(pHHInfo
);
1592 void ReleaseHelpViewer(HHInfo
*info
)
1594 TRACE("(%p)\n", info
);
1599 /* Free allocated strings */
1600 heap_free(info
->pszType
);
1601 heap_free(info
->pszCaption
);
1602 heap_free(info
->pszToc
);
1603 heap_free(info
->pszIndex
);
1604 heap_free(info
->pszFile
);
1605 heap_free(info
->pszHome
);
1606 heap_free(info
->pszJump1
);
1607 heap_free(info
->pszJump2
);
1608 heap_free(info
->pszUrlJump1
);
1609 heap_free(info
->pszUrlJump2
);
1612 CloseCHM(info
->pCHMInfo
);
1614 ReleaseWebBrowser(info
);
1615 ReleaseContent(info
);
1617 ReleaseSearch(info
);
1619 if(info
->WinType
.hwndHelp
)
1620 DestroyWindow(info
->WinType
.hwndHelp
);
1626 HHInfo
*CreateHelpViewer(LPCWSTR filename
)
1628 HHInfo
*info
= heap_alloc_zero(sizeof(HHInfo
));
1631 /* Set the invalid tab ID (-1) as the default value for all
1632 * of the tabs, this matches a failed TCM_INSERTITEM call.
1634 for(i
=0;i
<sizeof(info
->tabs
)/sizeof(HHTab
);i
++)
1635 info
->tabs
[i
].id
= -1;
1637 OleInitialize(NULL
);
1639 info
->pCHMInfo
= OpenCHM(filename
);
1640 if(!info
->pCHMInfo
) {
1641 ReleaseHelpViewer(info
);
1645 if (!LoadWinTypeFromCHM(info
)) {
1646 ReleaseHelpViewer(info
);
1650 if(!CreateViewer(info
)) {
1651 ReleaseHelpViewer(info
);