Something went wrong. Try again.
Reactos
Something went wrong. Try again.
59 kB · 1977 lines
C
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978/* * Help Viewer Implementation * * Copyright 2005 James Hawkins * Copyright 2007 Jacek Caban for CodeWeavers * Copyright 2011 Owen Rudge for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include "hhctrl.h"
#include "wingdi.h"#include "commctrl.h"#include "wininet.h"
#include "wine/debug.h"
#include "resource.h"
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
static LRESULT Help_OnSize(HWND hWnd);static void ExpandContract(HHInfo *pHHInfo);
/* Window type defaults */
#define WINTYPE_DEFAULT_X 280#define WINTYPE_DEFAULT_Y 100#define WINTYPE_DEFAULT_WIDTH 740#define WINTYPE_DEFAULT_HEIGHT 640#define WINTYPE_DEFAULT_NAVWIDTH 250
#define TAB_TOP_PADDING 8#define TAB_RIGHT_PADDING 4#define TAB_MARGIN 8#define EDIT_HEIGHT 20
struct list window_list = LIST_INIT(window_list);
static const WCHAR szEmpty[] = {0};
struct html_encoded_symbol { const char *html_code; char ansi_symbol;};
/* * Table mapping the conversion between HTML encoded symbols and their ANSI code page equivalent. * Note: Add additional entries in proper alphabetical order (a binary search is used on this table). */static struct html_encoded_symbol html_encoded_symbols[] ={ {"AElig", 0xC6}, {"Aacute", 0xC1}, {"Acirc", 0xC2}, {"Agrave", 0xC0}, {"Aring", 0xC5}, {"Atilde", 0xC3}, {"Auml", 0xC4}, {"Ccedil", 0xC7}, {"ETH", 0xD0}, {"Eacute", 0xC9}, {"Ecirc", 0xCA}, {"Egrave", 0xC8}, {"Euml", 0xCB}, {"Iacute", 0xCD}, {"Icirc", 0xCE}, {"Igrave", 0xCC}, {"Iuml", 0xCF}, {"Ntilde", 0xD1}, {"Oacute", 0xD3}, {"Ocirc", 0xD4}, {"Ograve", 0xD2}, {"Oslash", 0xD8}, {"Otilde", 0xD5}, {"Ouml", 0xD6}, {"THORN", 0xDE}, {"Uacute", 0xDA}, {"Ucirc", 0xDB}, {"Ugrave", 0xD9}, {"Uuml", 0xDC}, {"Yacute", 0xDD}, {"aacute", 0xE1}, {"acirc", 0xE2}, {"acute", 0xB4}, {"aelig", 0xE6}, {"agrave", 0xE0}, {"amp", '&'}, {"aring", 0xE5}, {"atilde", 0xE3}, {"auml", 0xE4}, {"brvbar", 0xA6}, {"ccedil", 0xE7}, {"cedil", 0xB8}, {"cent", 0xA2}, {"copy", 0xA9}, {"curren", 0xA4}, {"deg", 0xB0}, {"divide", 0xF7}, {"eacute", 0xE9}, {"ecirc", 0xEA}, {"egrave", 0xE8}, {"eth", 0xF0}, {"euml", 0xEB}, {"frac12", 0xBD}, {"frac14", 0xBC}, {"frac34", 0xBE}, {"gt", '>'}, {"iacute", 0xED}, {"icirc", 0xEE}, {"iexcl", 0xA1}, {"igrave", 0xEC}, {"iquest", 0xBF}, {"iuml", 0xEF}, {"laquo", 0xAB}, {"lt", '<'}, {"macr", 0xAF}, {"micro", 0xB5}, {"middot", 0xB7}, {"nbsp", ' '}, {"not", 0xAC}, {"ntilde", 0xF1}, {"oacute", 0xF3}, {"ocirc", 0xF4}, {"ograve", 0xF2}, {"ordf", 0xAA}, {"ordm", 0xBA}, {"oslash", 0xF8}, {"otilde", 0xF5}, {"ouml", 0xF6}, {"para", 0xB6}, {"plusmn", 0xB1}, {"pound", 0xA3}, {"quot", '"'}, {"raquo", 0xBB}, {"reg", 0xAE}, {"sect", 0xA7}, {"shy", 0xAD}, {"sup1", 0xB9}, {"sup2", 0xB2}, {"sup3", 0xB3}, {"szlig", 0xDF}, {"thorn", 0xFE}, {"times", 0xD7}, {"uacute", 0xFA}, {"ucirc", 0xFB}, {"ugrave", 0xF9}, {"uml", 0xA8}, {"uuml", 0xFC}, {"yacute", 0xFD}, {"yen", 0xA5}, {"yuml", 0xFF}};
static inline BOOL navigation_visible(HHInfo *info){ return ((info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && !info->WinType.fNotExpanded);}
/* Loads a string from the resource file */#ifdef __REACTOS__LPWSTR HH_LoadString(DWORD dwID)#elsestatic LPWSTR HH_LoadString(DWORD dwID)#endif{ LPWSTR string = NULL; LPCWSTR stringresource; int iSize;
iSize = LoadStringW(hhctrl_hinstance, dwID, (LPWSTR)&stringresource, 0);
string = heap_alloc((iSize + 2) * sizeof(WCHAR)); /* some strings (tab text) needs double-null termination */ memcpy(string, stringresource, iSize*sizeof(WCHAR)); string[iSize] = 0;
return string;}
static HRESULT navigate_url(HHInfo *info, LPCWSTR surl){ VARIANT url; HRESULT hres;
TRACE("%s\n", debugstr_w(surl));
V_VT(&url) = VT_BSTR; V_BSTR(&url) = SysAllocString(surl);
hres = IWebBrowser2_Navigate2(info->web_browser->web_browser, &url, 0, 0, 0, 0);
VariantClear(&url);
if(FAILED(hres)) TRACE("Navigation failed: %08x\n", hres);
return hres;}
BOOL NavigateToUrl(HHInfo *info, LPCWSTR surl){ ChmPath chm_path; BOOL ret; HRESULT hres;
static const WCHAR url_indicator[] = {':', '/', '/', 0};
TRACE("%s\n", debugstr_w(surl));
if (wcsstr(surl, url_indicator)) { hres = navigate_url(info, surl); if(SUCCEEDED(hres)) return TRUE; } /* look up in chm if it doesn't look like a full url */
SetChmPath(&chm_path, info->pCHMInfo->szFile, surl); ret = NavigateToChm(info, chm_path.chm_file, chm_path.chm_index);
heap_free(chm_path.chm_file); heap_free(chm_path.chm_index);
return ret;}
static BOOL AppendFullPathURL(LPCWSTR file, LPWSTR buf, LPCWSTR index){ static const WCHAR url_format[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0}; static const WCHAR slash[] = {'/',0}; static const WCHAR empty[] = {0}; WCHAR full_path[MAX_PATH];
TRACE("%s %p %s\n", debugstr_w(file), buf, debugstr_w(index));
if (!GetFullPathNameW(file, ARRAY_SIZE(full_path), full_path, NULL)) { WARN("GetFullPathName failed: %u\n", GetLastError()); return FALSE; }
wsprintfW(buf, url_format, full_path, (!index || index[0] == '/') ? empty : slash, index); return TRUE;}
BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index){ WCHAR buf[INTERNET_MAX_URL_LENGTH];
TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
if ((!info->web_browser) || !AppendFullPathURL(file, buf, index)) return FALSE;
return SUCCEEDED(navigate_url(info, buf));}
static void DoSync(HHInfo *info){ WCHAR buf[INTERNET_MAX_URL_LENGTH]; HRESULT hres; BSTR url;
hres = IWebBrowser2_get_LocationURL(info->web_browser->web_browser, &url);
if (FAILED(hres)) { WARN("get_LocationURL failed: %08x\n", hres); return; }
/* If we're not currently viewing a page in the active .chm file, abort */ if ((!AppendFullPathURL(info->WinType.pszFile, buf, NULL)) || (lstrlenW(buf) > lstrlenW(url))) { SysFreeString(url); return; }
if (lstrcmpiW(buf, url) > 0) { static const WCHAR delimW[] = {':',':','/',0}; const WCHAR *index;
index = wcsstr(url, delimW);
if (index) ActivateContentTopic(info->tabs[TAB_CONTENTS].hwnd, index + 3, info->content); /* skip over ::/ */ }
SysFreeString(url);}
/* Size Bar */
#define SIZEBAR_WIDTH 4
static const WCHAR szSizeBarClass[] = { 'H','H',' ','S','i','z','e','B','a','r',0};
/* Draw the SizeBar */static void SB_OnPaint(HWND hWnd){ PAINTSTRUCT ps; HDC hdc; RECT rc; hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
/* dark frame */ rc.right += 1; rc.bottom -= 1; FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH));
/* white highlight */ SelectObject(hdc, GetStockObject(WHITE_PEN)); MoveToEx(hdc, rc.right, 1, NULL); LineTo(hdc, 1, 1); LineTo(hdc, 1, rc.bottom - 1);
MoveToEx(hdc, 0, rc.bottom, NULL); LineTo(hdc, rc.right, rc.bottom);
EndPaint(hWnd, &ps);}
static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam){ SetCapture(hWnd);}
static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam){ HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0); POINT pt;
pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam);
/* update the window sizes */ pHHInfo->WinType.iNavWidth += pt.x; Help_OnSize(hWnd);
ReleaseCapture();}
static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam){ /* ignore WM_MOUSEMOVE if not dragging the SizeBar */ if (!(wParam & MK_LBUTTON)) return;}
static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_LBUTTONDOWN: SB_OnLButtonDown(hWnd, wParam, lParam); break; case WM_LBUTTONUP: SB_OnLButtonUp(hWnd, wParam, lParam); break; case WM_MOUSEMOVE: SB_OnMouseMove(hWnd, wParam, lParam); break; case WM_PAINT: SB_OnPaint(hWnd); break; default: return DefWindowProcW(hWnd, message, wParam, lParam); }
return 0;}
static void HH_RegisterSizeBarClass(HHInfo *pHHInfo){ WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = 0; wcex.lpfnWndProc = SizeBar_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hhctrl_hinstance; wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE); wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szSizeBarClass; wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
RegisterClassExW(&wcex);}
static void SB_GetSizeBarRect(HHInfo *info, RECT *rc){ RECT rectWND, rectTB, rectNP;
GetClientRect(info->WinType.hwndHelp, &rectWND); GetClientRect(info->WinType.hwndToolBar, &rectTB); GetClientRect(info->WinType.hwndNavigation, &rectNP);
SetRect(rc, rectNP.right, rectTB.bottom, SIZEBAR_WIDTH, rectWND.bottom - rectTB.bottom);}
static BOOL HH_AddSizeBar(HHInfo *pHHInfo){ HWND hWnd; HWND hwndParent = pHHInfo->WinType.hwndHelp; DWORD dwStyles = WS_CHILDWINDOW | WS_OVERLAPPED; DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; RECT rc;
if (navigation_visible(pHHInfo)) dwStyles |= WS_VISIBLE;
SB_GetSizeBarRect(pHHInfo, &rc);
hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles, rc.left, rc.top, rc.right, rc.bottom, hwndParent, NULL, hhctrl_hinstance, NULL); if (!hWnd) return FALSE;
/* store the pointer to the HH info struct */ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo);
pHHInfo->hwndSizeBar = hWnd; return TRUE;}
/* Child Window */
static const WCHAR szChildClass[] = { 'H','H',' ','C','h','i','l','d',0};
static LRESULT Child_OnPaint(HWND hWnd){ PAINTSTRUCT ps; HDC hdc; RECT rc;
hdc = BeginPaint(hWnd, &ps);
/* Only paint the Navigation pane, identified by the fact * that it has a child window */ if (GetWindow(hWnd, GW_CHILD)) { GetClientRect(hWnd, &rc);
/* set the border color */ SelectObject(hdc, GetStockObject(DC_PEN)); SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
/* Draw the top border */ LineTo(hdc, rc.right, 0);
SelectObject(hdc, GetStockObject(WHITE_PEN)); MoveToEx(hdc, 0, 1, NULL); LineTo(hdc, rc.right, 1); }
EndPaint(hWnd, &ps);
return 0;}
static void ResizeTabChild(HHInfo *info, int tab){ HWND hwnd = info->tabs[tab].hwnd; INT width, height; RECT rect, tabrc; DWORD cnt;
GetClientRect(info->WinType.hwndNavigation, &rect); SendMessageW(info->hwndTabCtrl, TCM_GETITEMRECT, 0, (LPARAM)&tabrc); cnt = SendMessageW(info->hwndTabCtrl, TCM_GETROWCOUNT, 0, 0);
rect.left = TAB_MARGIN; rect.top = TAB_TOP_PADDING + cnt*(tabrc.bottom-tabrc.top) + TAB_MARGIN; rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN; rect.bottom -= TAB_MARGIN; width = rect.right-rect.left; height = rect.bottom-rect.top;
SetWindowPos(hwnd, NULL, rect.left, rect.top, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
switch (tab) { case TAB_INDEX: { int scroll_width = GetSystemMetrics(SM_CXVSCROLL); int border_width = GetSystemMetrics(SM_CXBORDER); int edge_width = GetSystemMetrics(SM_CXEDGE);
/* Resize the tab widget column to perfectly fit the tab window and * leave sufficient space for the scroll widget. */ SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_SETCOLUMNWIDTH, 0, width-scroll_width-2*border_width-2*edge_width);
break; } case TAB_SEARCH: { int scroll_width = GetSystemMetrics(SM_CXVSCROLL); int border_width = GetSystemMetrics(SM_CXBORDER); int edge_width = GetSystemMetrics(SM_CXEDGE); int top_pos = 0;
SetWindowPos(info->search.hwndEdit, NULL, 0, top_pos, width, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE); top_pos += EDIT_HEIGHT + TAB_MARGIN; SetWindowPos(info->search.hwndList, NULL, 0, top_pos, width, height-top_pos, SWP_NOZORDER | SWP_NOACTIVATE); /* Resize the tab widget column to perfectly fit the tab window and * leave sufficient space for the scroll widget. */ SendMessageW(info->search.hwndList, LVM_SETCOLUMNWIDTH, 0, width-scroll_width-2*border_width-2*edge_width);
break; } }}
static LRESULT Child_OnSize(HWND hwnd){ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0); RECT rect;
if(!info || hwnd != info->WinType.hwndNavigation) return 0;
GetClientRect(hwnd, &rect); SetWindowPos(info->hwndTabCtrl, HWND_TOP, 0, 0, rect.right - TAB_RIGHT_PADDING, rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
ResizeTabChild(info, TAB_CONTENTS); ResizeTabChild(info, TAB_INDEX); ResizeTabChild(info, TAB_SEARCH); return 0;}
static LRESULT OnTabChange(HWND hwnd){ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0); int tab_id, tab_index, i;
TRACE("%p\n", hwnd);
if (!info) return 0;
if(info->tabs[info->current_tab].hwnd) ShowWindow(info->tabs[info->current_tab].hwnd, SW_HIDE);
tab_id = (int) SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0); /* convert the ID of the tab to an index in our tab list */ tab_index = -1; for (i=0; i<TAB_NUMTABS; i++) { if (info->tabs[i].id == tab_id) { tab_index = i; break; } } if (tab_index == -1) { FIXME("Tab ID %d does not correspond to a valid index in the tab list.\n", tab_id); return 0; } info->current_tab = tab_index;
if(info->tabs[info->current_tab].hwnd) ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW);
return 0;}
static LRESULT OnTopicChange(HHInfo *info, void *user_data){ LPCWSTR chmfile = NULL, name = NULL, local = NULL; ContentItem *citer; SearchItem *siter; IndexItem *iiter;
if(!user_data || !info) return 0;
switch (info->current_tab) { case TAB_CONTENTS: citer = (ContentItem *) user_data; name = citer->name; local = citer->local; while(citer) { if(citer->merge.chm_file) { chmfile = citer->merge.chm_file; break; } citer = citer->parent; } break; case TAB_INDEX: iiter = (IndexItem *) user_data; if(iiter->nItems == 0) { FIXME("No entries for this item!\n"); return 0; } if(iiter->nItems > 1) { int i = 0; LVITEMW lvi;
SendMessageW(info->popup.hwndList, LVM_DELETEALLITEMS, 0, 0); for(i=0;i<iiter->nItems;i++) { IndexSubItem *item = &iiter->items[i]; WCHAR *name = iiter->keyword;
if(!item->name) item->name = GetDocumentTitle(info->pCHMInfo, item->local); if(item->name) name = item->name; memset(&lvi, 0, sizeof(lvi)); lvi.iItem = i; lvi.mask = LVIF_TEXT|LVIF_PARAM; lvi.cchTextMax = lstrlenW(name)+1; lvi.pszText = name; lvi.lParam = (LPARAM) item; SendMessageW(info->popup.hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi); } ShowWindow(info->popup.hwndPopup, SW_SHOW); return 0; } name = iiter->items[0].name; local = iiter->items[0].local; chmfile = iiter->merge.chm_file; break; case TAB_SEARCH: siter = (SearchItem *) user_data; name = siter->filename; local = siter->filename; chmfile = info->pCHMInfo->szFile; break; default: FIXME("Unhandled operation for this tab!\n"); return 0; }
if(!chmfile) { FIXME("No help file found for this item!\n"); return 0; }
TRACE("name %s loal %s\n", debugstr_w(name), debugstr_w(local));
NavigateToChm(info, chmfile, local); return 0;}
/* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */static LRESULT CALLBACK EditChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ WNDPROC editWndProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
if(message == WM_KEYUP && wParam == VK_RETURN) { NMHDR nmhdr;
nmhdr.hwndFrom = hWnd; nmhdr.code = NM_RETURN; SendMessageW(GetParent(GetParent(hWnd)), WM_NOTIFY, wParam, (LPARAM)&nmhdr); } return editWndProc(hWnd, message, wParam, lParam);}
static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_PAINT: return Child_OnPaint(hWnd); case WM_SIZE: return Child_OnSize(hWnd); case WM_NOTIFY: { HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); NMHDR *nmhdr = (NMHDR*)lParam;
switch(nmhdr->code) { case TCN_SELCHANGE: return OnTabChange(hWnd); case TVN_SELCHANGEDW: return OnTopicChange(info, (void*)((NMTREEVIEWW *)lParam)->itemNew.lParam); case TVN_ITEMEXPANDINGW: { TVITEMW *item = &((NMTREEVIEWW *)lParam)->itemNew; HWND hwndTreeView = info->tabs[TAB_CONTENTS].hwnd;
item->mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE; if (item->state & TVIS_EXPANDED) { item->iImage = HHTV_FOLDER; item->iSelectedImage = HHTV_FOLDER; } else { item->iImage = HHTV_OPENFOLDER; item->iSelectedImage = HHTV_OPENFOLDER; } SendMessageW(hwndTreeView, TVM_SETITEMW, 0, (LPARAM)item); return 0; } case NM_DBLCLK: if(!info) return 0; switch(info->current_tab) { case TAB_INDEX: return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam); case TAB_SEARCH: return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam); } break; case NM_RETURN: if(!info) return 0; switch(info->current_tab) { case TAB_INDEX: { HWND hwndList = info->tabs[TAB_INDEX].hwnd; LVITEMW lvItem;
lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0); lvItem.mask = TVIF_PARAM; SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); OnTopicChange(info, (void*) lvItem.lParam); return 0; } case TAB_SEARCH: { if(nmhdr->hwndFrom == info->search.hwndEdit) { char needle[100]; DWORD i, len;
len = GetWindowTextA(info->search.hwndEdit, needle, sizeof(needle)); if(!len) { FIXME("Unable to get search text.\n"); return 0; } /* Convert the requested text for comparison later against the * lower case version of HTML file contents. */ for(i=0;i<len;i++) needle[i] = tolower(needle[i]); InitSearch(info, needle); return 0; }else if(nmhdr->hwndFrom == info->search.hwndList) { HWND hwndList = info->search.hwndList; LVITEMW lvItem;
lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0); lvItem.mask = TVIF_PARAM; SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); OnTopicChange(info, (void*) lvItem.lParam); return 0; } break; } } break; } break; } default: return DefWindowProcW(hWnd, message, wParam, lParam); }
return 0;}
static void HH_RegisterChildWndClass(HHInfo *pHHInfo){ WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = 0; wcex.lpfnWndProc = Child_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hhctrl_hinstance; wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szChildClass; wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
RegisterClassExW(&wcex);}
/* Toolbar */
#define ICON_SIZE 20
static void DisplayPopupMenu(HHInfo *info){ HMENU menu, submenu; TBBUTTONINFOW button; MENUITEMINFOW item; POINT coords; RECT rect; DWORD index;
menu = LoadMenuW(hhctrl_hinstance, MAKEINTRESOURCEW(MENU_POPUP));
if (!menu) return;
submenu = GetSubMenu(menu, 0);
/* Update the Show/Hide menu item */ item.cbSize = sizeof(MENUITEMINFOW); item.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING; item.fType = MFT_STRING; item.fState = MF_ENABLED;
if (info->WinType.fNotExpanded) item.dwTypeData = HH_LoadString(IDS_SHOWTABS); else item.dwTypeData = HH_LoadString(IDS_HIDETABS);
SetMenuItemInfoW(submenu, IDTB_EXPAND, FALSE, &item); heap_free(item.dwTypeData);
/* Find the index toolbar button */ button.cbSize = sizeof(TBBUTTONINFOW); button.dwMask = TBIF_COMMAND; index = SendMessageW(info->WinType.hwndToolBar, TB_GETBUTTONINFOW, IDTB_OPTIONS, (LPARAM) &button);
if (index == -1) return;
/* Get position */ SendMessageW(info->WinType.hwndToolBar, TB_GETITEMRECT, index, (LPARAM) &rect);
coords.x = rect.left; coords.y = rect.bottom;
ClientToScreen(info->WinType.hwndToolBar, &coords); TrackPopupMenu(submenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_NOANIMATION, coords.x, coords.y, 0, info->WinType.hwndHelp, NULL);}
static void TB_OnClick(HWND hWnd, DWORD dwID){ HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
switch (dwID) { case IDTB_STOP: DoPageAction(info->web_browser, WB_STOP); break; case IDTB_REFRESH: DoPageAction(info->web_browser, WB_REFRESH); break; case IDTB_BACK: DoPageAction(info->web_browser, WB_GOBACK); break; case IDTB_HOME: NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome); break; case IDTB_FORWARD: DoPageAction(info->web_browser, WB_GOFORWARD); break; case IDTB_PRINT: DoPageAction(info->web_browser, WB_PRINT); break; case IDTB_EXPAND: case IDTB_CONTRACT: ExpandContract(info); break; case IDTB_SYNC: DoSync(info); break; case IDTB_OPTIONS: DisplayPopupMenu(info); break; case IDTB_NOTES: case IDTB_CONTENTS: case IDTB_INDEX: case IDTB_SEARCH: case IDTB_HISTORY: case IDTB_FAVORITES: /* These are officially unimplemented as of the Windows 7 SDK */ break; case IDTB_BROWSE_FWD: case IDTB_BROWSE_BACK: case IDTB_JUMP1: case IDTB_JUMP2: case IDTB_CUSTOMIZE: case IDTB_ZOOM: case IDTB_TOC_NEXT: case IDTB_TOC_PREV: break; }}
static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID, DWORD dwBitmap){ pButtons[dwIndex].iBitmap = dwBitmap; pButtons[dwIndex].idCommand = dwID; pButtons[dwIndex].fsState = TBSTATE_ENABLED; pButtons[dwIndex].fsStyle = BTNS_BUTTON; pButtons[dwIndex].dwData = 0; pButtons[dwIndex].iString = 0;}
static void TB_AddButtonsFromFlags(HHInfo *pHHInfo, TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons){ int nHistBitmaps = 0, nStdBitmaps = 0, nHHBitmaps = 0; HWND hToolbar = pHHInfo->WinType.hwndToolBar; TBADDBITMAP tbAB; DWORD unsupported;
/* Common bitmaps */ tbAB.hInst = HINST_COMMCTRL; tbAB.nID = IDB_HIST_LARGE_COLOR; nHistBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB); tbAB.nID = IDB_STD_LARGE_COLOR; nStdBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB); /* hhctrl.ocx bitmaps */ tbAB.hInst = hhctrl_hinstance; tbAB.nID = IDB_HHTOOLBAR; nHHBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, HHTB_NUMBITMAPS, (LPARAM)&tbAB);
*pdwNumButtons = 0;
unsupported = dwButtonFlags & (HHWIN_BUTTON_BROWSE_FWD | HHWIN_BUTTON_BROWSE_BCK | HHWIN_BUTTON_NOTES | HHWIN_BUTTON_CONTENTS | HHWIN_BUTTON_INDEX | HHWIN_BUTTON_SEARCH | HHWIN_BUTTON_HISTORY | HHWIN_BUTTON_FAVORITES | HHWIN_BUTTON_JUMP1 | HHWIN_BUTTON_JUMP2 | HHWIN_BUTTON_ZOOM | HHWIN_BUTTON_TOC_NEXT | HHWIN_BUTTON_TOC_PREV); if (unsupported) FIXME("got asked for unsupported buttons: %06x\n", unsupported);
if (dwButtonFlags & HHWIN_BUTTON_EXPAND) { TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND, nHHBitmaps + HHTB_EXPAND); TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_CONTRACT, nHHBitmaps + HHTB_CONTRACT);
if (pHHInfo->WinType.fNotExpanded) pButtons[1].fsState |= TBSTATE_HIDDEN; else pButtons[0].fsState |= TBSTATE_HIDDEN; }
if (dwButtonFlags & HHWIN_BUTTON_BACK) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK, nHistBitmaps + HIST_BACK);
if (dwButtonFlags & HHWIN_BUTTON_FORWARD) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD, nHistBitmaps + HIST_FORWARD);
if (dwButtonFlags & HHWIN_BUTTON_STOP) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP, nHHBitmaps + HHTB_STOP);
if (dwButtonFlags & HHWIN_BUTTON_REFRESH) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH, nHHBitmaps + HHTB_REFRESH);
if (dwButtonFlags & HHWIN_BUTTON_HOME) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME, nHHBitmaps + HHTB_HOME);
if (dwButtonFlags & HHWIN_BUTTON_SYNC) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC, nHHBitmaps + HHTB_SYNC);
if (dwButtonFlags & HHWIN_BUTTON_OPTIONS) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS, nStdBitmaps + STD_PROPERTIES);
if (dwButtonFlags & HHWIN_BUTTON_PRINT) TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT, nStdBitmaps + STD_PRINT);}
static BOOL HH_AddToolbar(HHInfo *pHHInfo){ HWND hToolbar; HWND hwndParent = pHHInfo->WinType.hwndHelp; DWORD toolbarFlags; TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND]; DWORD dwStyles, dwExStyles; DWORD dwNumButtons, dwIndex;
if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS) toolbarFlags = pHHInfo->WinType.fsToolBarFlags; else toolbarFlags = HHWIN_DEF_BUTTONS;
dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER; dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles, 0, 0, 0, 0, hwndParent, NULL, hhctrl_hinstance, NULL); if (!hToolbar) return FALSE; pHHInfo->WinType.hwndToolBar = hToolbar;
SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE)); SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
TB_AddButtonsFromFlags(pHHInfo, buttons, toolbarFlags, &dwNumButtons);
for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++) { LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand); DWORD dwLen = lstrlenW(szBuf); szBuf[dwLen + 1] = 0; /* Double-null terminate */
buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf); heap_free(szBuf); }
SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)buttons); SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0); if (pHHInfo->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) ShowWindow(hToolbar, SW_SHOW);
return TRUE;}
/* Navigation Pane */
static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc){ HWND hwndParent = pHHInfo->WinType.hwndHelp; HWND hwndToolbar = pHHInfo->WinType.hwndToolBar; RECT rectWND, rectTB;
GetClientRect(hwndParent, &rectWND); GetClientRect(hwndToolbar, &rectTB);
rc->left = 0; rc->top = rectTB.bottom; rc->bottom = rectWND.bottom - rectTB.bottom;
if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) && pHHInfo->WinType.iNavWidth == 0) { pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH; }
rc->right = pHHInfo->WinType.iNavWidth;}
static DWORD NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD index){ TCITEMW tie; LPWSTR tabText = HH_LoadString(index); DWORD ret;
tie.mask = TCIF_TEXT; tie.pszText = tabText;
ret = SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, index, (LPARAM)&tie );
heap_free(tabText); return ret;}
static BOOL HH_AddNavigationPane(HHInfo *info){ HWND hWnd, hwndTabCtrl; HWND hwndParent = info->WinType.hwndHelp; DWORD dwStyles = WS_CHILDWINDOW; DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; RECT rc;
if (navigation_visible(info)) dwStyles |= WS_VISIBLE;
NP_GetNavigationRect(info, &rc);
hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles, rc.left, rc.top, rc.right, rc.bottom, hwndParent, NULL, hhctrl_hinstance, NULL); if (!hWnd) return FALSE;
SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info);
hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles | WS_VISIBLE, 0, TAB_TOP_PADDING, rc.right - TAB_RIGHT_PADDING, rc.bottom - TAB_TOP_PADDING, hWnd, NULL, hhctrl_hinstance, NULL); if (!hwndTabCtrl) return FALSE;
if (*info->WinType.pszToc) info->tabs[TAB_CONTENTS].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS);
if (*info->WinType.pszIndex) info->tabs[TAB_INDEX].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX);
if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH) info->tabs[TAB_SEARCH].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH);
if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES) info->tabs[TAB_FAVORITES].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES);
SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE);
info->hwndTabCtrl = hwndTabCtrl; info->WinType.hwndNavigation = hWnd; return TRUE;}
/* HTML Pane */
static void HP_GetHTMLRect(HHInfo *info, RECT *rc){ RECT rectTB, rectWND, rectNP, rectSB;
GetClientRect(info->WinType.hwndHelp, &rectWND); GetClientRect(info->hwndSizeBar, &rectSB);
rc->left = 0; rc->top = 0; if (navigation_visible(info)) { GetClientRect(info->WinType.hwndNavigation, &rectNP); rc->left += rectNP.right + rectSB.right; } if (info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) { GetClientRect(info->WinType.hwndToolBar, &rectTB); rc->top += rectTB.bottom; } rc->right = rectWND.right - rc->left; rc->bottom = rectWND.bottom - rc->top;}
static BOOL HH_AddHTMLPane(HHInfo *pHHInfo){ HWND hWnd; HWND hwndParent = pHHInfo->WinType.hwndHelp; DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN; DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE; RECT rc;
HP_GetHTMLRect(pHHInfo, &rc);
hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles, rc.left, rc.top, rc.right, rc.bottom, hwndParent, NULL, hhctrl_hinstance, NULL); if (!hWnd) return FALSE;
if (!InitWebBrowser(pHHInfo, hWnd)) return FALSE;
/* store the pointer to the HH info struct */ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo);
ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd);
pHHInfo->WinType.hwndHTML = hWnd; return TRUE;}
static BOOL AddContentTab(HHInfo *info){ HIMAGELIST hImageList; HBITMAP hBitmap; HWND hWnd;
if(info->tabs[TAB_CONTENTS].id == -1) return TRUE; /* No "Contents" tab */ hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, szEmpty, WS_CHILD | WS_BORDER | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_HASBUTTONS, 50, 50, 100, 100, info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL); if(!hWnd) { ERR("Could not create treeview control\n"); return FALSE; }
hImageList = ImageList_Create(16, 16, ILC_COLOR32, 0, HHTV_NUMBITMAPS); hBitmap = LoadBitmapW(hhctrl_hinstance, MAKEINTRESOURCEW(IDB_HHTREEVIEW)); ImageList_Add(hImageList, hBitmap, NULL); SendMessageW(hWnd, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList);
info->contents.hImageList = hImageList; info->tabs[TAB_CONTENTS].hwnd = hWnd; ResizeTabChild(info, TAB_CONTENTS); ShowWindow(hWnd, SW_SHOW);
return TRUE;}
static BOOL AddIndexTab(HHInfo *info){ char hidden_column[] = "Column"; LVCOLUMNA lvc;
if(info->tabs[TAB_INDEX].id == -1) return TRUE; /* No "Index" tab */ info->tabs[TAB_INDEX].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty, WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 50, 50, 100, 100, info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL); if(!info->tabs[TAB_INDEX].hwnd) { ERR("Could not create ListView control\n"); return FALSE; } memset(&lvc, 0, sizeof(lvc)); lvc.mask = LVCF_TEXT; lvc.pszText = hidden_column; if(SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) { ERR("Could not create ListView column\n"); return FALSE; }
ResizeTabChild(info, TAB_INDEX); ShowWindow(info->tabs[TAB_INDEX].hwnd, SW_HIDE);
return TRUE;}
static BOOL AddSearchTab(HHInfo *info){ HWND hwndList, hwndEdit, hwndContainer; char hidden_column[] = "Column"; WNDPROC editWndProc; LVCOLUMNA lvc;
if(info->tabs[TAB_SEARCH].id == -1) return TRUE; /* No "Search" tab */ hwndContainer = CreateWindowExW(WS_EX_CONTROLPARENT, szChildClass, szEmpty, WS_CHILD, 0, 0, 0, 0, info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL); if(!hwndContainer) { ERR("Could not create search window container control.\n"); return FALSE; } hwndEdit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, szEmpty, WS_CHILD | WS_VISIBLE | ES_LEFT | SS_NOTIFY, 0, 0, 0, 0, hwndContainer, NULL, hhctrl_hinstance, NULL); if(!hwndEdit) { ERR("Could not create search ListView control.\n"); return FALSE; } if(SendMessageW(hwndEdit, WM_SETFONT, (WPARAM) info->hFont, (LPARAM) FALSE) == -1) { ERR("Could not set font for edit control.\n"); return FALSE; } editWndProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditChild_WndProc); if(!editWndProc) { ERR("Could not redirect messages for edit control.\n"); return FALSE; } SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)editWndProc); hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty, WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 0, 0, 0, 0, hwndContainer, NULL, hhctrl_hinstance, NULL); if(!hwndList) { ERR("Could not create search ListView control.\n"); return FALSE; } memset(&lvc, 0, sizeof(lvc)); lvc.mask = LVCF_TEXT; lvc.pszText = hidden_column; if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) { ERR("Could not create ListView column\n"); return FALSE; }
info->search.hwndEdit = hwndEdit; info->search.hwndList = hwndList; info->search.hwndContainer = hwndContainer; info->tabs[TAB_SEARCH].hwnd = hwndContainer;
SetWindowLongPtrW(hwndContainer, 0, (LONG_PTR)info);
ResizeTabChild(info, TAB_SEARCH);
return TRUE;}
/* The Index tab's sub-topic popup */
static void ResizePopupChild(HHInfo *info){ int scroll_width = GetSystemMetrics(SM_CXVSCROLL); int border_width = GetSystemMetrics(SM_CXBORDER); int edge_width = GetSystemMetrics(SM_CXEDGE); INT width, height; RECT rect;
if(!info) return;
GetClientRect(info->popup.hwndPopup, &rect); SetWindowPos(info->popup.hwndCallback, HWND_TOP, 0, 0, rect.right, rect.bottom, SWP_NOMOVE);
rect.left = TAB_MARGIN; rect.top = TAB_TOP_PADDING + TAB_MARGIN; rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN; rect.bottom -= TAB_MARGIN; width = rect.right-rect.left; height = rect.bottom-rect.top;
SetWindowPos(info->popup.hwndList, NULL, rect.left, rect.top, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
SendMessageW(info->popup.hwndList, LVM_SETCOLUMNWIDTH, 0, width-scroll_width-2*border_width-2*edge_width);}
static LRESULT CALLBACK HelpPopup_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
switch (message) { case WM_SIZE: ResizePopupChild(info); return 0; case WM_DESTROY: DestroyWindow(hWnd); return 0; case WM_CLOSE: ShowWindow(hWnd, SW_HIDE); return 0;
default: return DefWindowProcW(hWnd, message, wParam, lParam); }
return 0;}
static LRESULT CALLBACK PopupChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_NOTIFY: { NMHDR *nmhdr = (NMHDR*)lParam; switch(nmhdr->code) { case NM_DBLCLK: { HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); IndexSubItem *iter;
if(info == 0 || lParam == 0) return 0; iter = (IndexSubItem*) ((NMITEMACTIVATE *)lParam)->lParam; if(iter == 0) return 0; NavigateToChm(info, info->index->merge.chm_file, iter->local); ShowWindow(info->popup.hwndPopup, SW_HIDE); return 0; } case NM_RETURN: { HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); IndexSubItem *iter; LVITEMW lvItem;
if(info == 0) return 0;
lvItem.iItem = (int) SendMessageW(info->popup.hwndList, LVM_GETSELECTIONMARK, 0, 0); lvItem.mask = TVIF_PARAM; SendMessageW(info->popup.hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); iter = (IndexSubItem*) lvItem.lParam; NavigateToChm(info, info->index->merge.chm_file, iter->local); ShowWindow(info->popup.hwndPopup, SW_HIDE); return 0; } } break; } default: return DefWindowProcW(hWnd, message, wParam, lParam); }
return 0;}
static BOOL AddIndexPopup(HHInfo *info){ static const WCHAR szPopupChildClass[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0}; static const WCHAR windowCaptionW[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0}; static const WCHAR windowClassW[] = {'H','H',' ','P','o','p','u','p',0}; HWND hwndList, hwndPopup, hwndCallback; char hidden_column[] = "Column"; WNDCLASSEXW wcex; LVCOLUMNA lvc;
if(info->tabs[TAB_INDEX].id == -1) return TRUE; /* No "Index" tab */
wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = HelpPopup_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hhctrl_hinstance; wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = windowClassW; wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); RegisterClassExW(&wcex);
wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = 0; wcex.lpfnWndProc = PopupChild_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hhctrl_hinstance; wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szPopupChildClass; wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); RegisterClassExW(&wcex);
hwndPopup = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR, windowClassW, windowCaptionW, WS_POPUPWINDOW | WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, info->WinType.hwndHelp, NULL, hhctrl_hinstance, NULL); if (!hwndPopup) return FALSE;
hwndCallback = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, szPopupChildClass, szEmpty, WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hwndPopup, NULL, hhctrl_hinstance, NULL); if (!hwndCallback) return FALSE;
ShowWindow(hwndPopup, SW_HIDE); hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty, WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 50, 50, 100, 100, hwndCallback, NULL, hhctrl_hinstance, NULL); if(!hwndList) { ERR("Could not create popup ListView control\n"); return FALSE; } memset(&lvc, 0, sizeof(lvc)); lvc.mask = LVCF_TEXT; lvc.pszText = hidden_column; if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) { ERR("Could not create popup ListView column\n"); return FALSE; }
info->popup.hwndCallback = hwndCallback; info->popup.hwndPopup = hwndPopup; info->popup.hwndList = hwndList; SetWindowLongPtrW(hwndPopup, 0, (LONG_PTR)info); SetWindowLongPtrW(hwndCallback, 0, (LONG_PTR)info);
ResizePopupChild(info); ShowWindow(hwndList, SW_SHOW);
return TRUE;}
/* Viewer Window */
static void ExpandContract(HHInfo *pHHInfo){ RECT r, nav;
pHHInfo->WinType.fNotExpanded = !pHHInfo->WinType.fNotExpanded; GetWindowRect(pHHInfo->WinType.hwndHelp, &r); NP_GetNavigationRect(pHHInfo, &nav);
/* hide/show both the nav bar and the size bar */ if (pHHInfo->WinType.fNotExpanded) { ShowWindow(pHHInfo->WinType.hwndNavigation, SW_HIDE); ShowWindow(pHHInfo->hwndSizeBar, SW_HIDE); r.left = r.left + nav.right;
SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(FALSE, 0)); SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(TRUE, 0)); } else { ShowWindow(pHHInfo->WinType.hwndNavigation, SW_SHOW); ShowWindow(pHHInfo->hwndSizeBar, SW_SHOW); r.left = r.left - nav.right;
SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(TRUE, 0)); SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(FALSE, 0)); }
MoveWindow(pHHInfo->WinType.hwndHelp, r.left, r.top, r.right-r.left, r.bottom-r.top, TRUE);}
static LRESULT Help_OnSize(HWND hWnd){ HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0); DWORD dwSize; RECT rc;
if (!pHHInfo) return 0;
if (navigation_visible(pHHInfo)) { NP_GetNavigationRect(pHHInfo, &rc); SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0, rc.right, rc.bottom, SWP_NOMOVE);
SB_GetSizeBarRect(pHHInfo, &rc); SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top, rc.right, rc.bottom, SWP_SHOWWINDOW);
}
HP_GetHTMLRect(pHHInfo, &rc); SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top, rc.right, rc.bottom, SWP_SHOWWINDOW);
/* Resize browser window taking the frame size into account */ dwSize = GetSystemMetrics(SM_CXFRAME); ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize);
return 0;}
void UpdateHelpWindow(HHInfo *info){ if (!info->WinType.hwndHelp) return;
WARN("Only the size of the window is currently updated.\n"); if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT) { RECT *rect = &info->WinType.rcWindowPos; INT x, y, width, height;
x = rect->left; y = rect->top; width = rect->right - x; height = rect->bottom - y; SetWindowPos(info->WinType.hwndHelp, NULL, rect->left, rect->top, width, height, SWP_NOZORDER | SWP_NOACTIVATE); }}
static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_COMMAND: if (HIWORD(wParam) == BN_CLICKED) TB_OnClick(hWnd, LOWORD(wParam)); break; case WM_SIZE: return Help_OnSize(hWnd); case WM_CLOSE: ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, 0)); return 0; case WM_DESTROY: if(hh_process) PostQuitMessage(0); break;
default: return DefWindowProcW(hWnd, message, wParam, lParam); }
return 0;}
static BOOL HH_CreateHelpWindow(HHInfo *info){ HWND hWnd; RECT winPos = info->WinType.rcWindowPos; WNDCLASSEXW wcex; DWORD dwStyles, dwExStyles; DWORD x, y, width = 0, height = 0; LPCWSTR caption;
static const WCHAR windowClassW[] = { 'H','H',' ', 'P','a','r','e','n','t',0 };
wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = Help_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hhctrl_hinstance;#ifdef __REACTOS__ wcex.hIcon = LoadIconW(hhctrl_hinstance, MAKEINTRESOURCEW(IDI_HHICON));#else wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);#endif wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = windowClassW;#ifdef __REACTOS__ wcex.hIconSm = NULL;#else wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);#endif
RegisterClassExW(&wcex);
/* Read in window parameters if available */ if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES) { dwStyles = info->WinType.dwStyles; if (!(info->WinType.dwStyles & WS_CHILD)) dwStyles |= WS_OVERLAPPEDWINDOW; } else dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES) dwExStyles = info->WinType.dwExStyles; else dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR;
if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT) { x = winPos.left; y = winPos.top; width = winPos.right - x; height = winPos.bottom - y; } if (!width || !height) { x = WINTYPE_DEFAULT_X; y = WINTYPE_DEFAULT_Y; width = WINTYPE_DEFAULT_WIDTH; height = WINTYPE_DEFAULT_HEIGHT; }
if (!(info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && info->WinType.fNotExpanded) { if (!(info->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) && info->WinType.iNavWidth == 0) { info->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH; }
x += info->WinType.iNavWidth; width -= info->WinType.iNavWidth; }
caption = info->WinType.pszCaption; if (!*caption) caption = info->pCHMInfo->defTitle;
hWnd = CreateWindowExW(dwExStyles, windowClassW, caption, dwStyles, x, y, width, height, info->WinType.hwndCaller, NULL, hhctrl_hinstance, NULL); if (!hWnd) return FALSE;
ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd);
/* store the pointer to the HH info struct */ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info);
info->WinType.hwndHelp = hWnd; return TRUE;}
static void HH_CreateFont(HHInfo *pHHInfo){ LOGFONTW lf;
GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), &lf); lf.lfWeight = FW_NORMAL; lf.lfItalic = FALSE; lf.lfUnderline = FALSE;
pHHInfo->hFont = CreateFontIndirectW(&lf);}
static void HH_InitRequiredControls(DWORD dwControls){ INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = dwControls; InitCommonControlsEx(&icex);}
/* Creates the whole package */static BOOL CreateViewer(HHInfo *pHHInfo){ HH_CreateFont(pHHInfo);
if (!HH_CreateHelpWindow(pHHInfo)) return FALSE;
HH_InitRequiredControls(ICC_BAR_CLASSES);
if (!HH_AddToolbar(pHHInfo)) return FALSE;
HH_RegisterChildWndClass(pHHInfo);
if (!HH_AddNavigationPane(pHHInfo)) return FALSE;
HH_RegisterSizeBarClass(pHHInfo);
if (!HH_AddSizeBar(pHHInfo)) return FALSE;
if (!HH_AddHTMLPane(pHHInfo)) return FALSE;
if (!AddContentTab(pHHInfo)) return FALSE;
if (!AddIndexTab(pHHInfo)) return FALSE;
if (!AddIndexPopup(pHHInfo)) return FALSE;
if (!AddSearchTab(pHHInfo)) return FALSE;
InitContent(pHHInfo); InitIndex(pHHInfo);
pHHInfo->viewer_initialized = TRUE; return TRUE;}
void wintype_stringsW_free(struct wintype_stringsW *stringsW){ heap_free(stringsW->pszType); heap_free(stringsW->pszCaption); heap_free(stringsW->pszToc); heap_free(stringsW->pszIndex); heap_free(stringsW->pszFile); heap_free(stringsW->pszHome); heap_free(stringsW->pszJump1); heap_free(stringsW->pszJump2); heap_free(stringsW->pszUrlJump1); heap_free(stringsW->pszUrlJump2);}
void wintype_stringsA_free(struct wintype_stringsA *stringsA){ heap_free(stringsA->pszType); heap_free(stringsA->pszCaption); heap_free(stringsA->pszToc); heap_free(stringsA->pszIndex); heap_free(stringsA->pszFile); heap_free(stringsA->pszHome); heap_free(stringsA->pszJump1); heap_free(stringsA->pszJump2); heap_free(stringsA->pszUrlJump1); heap_free(stringsA->pszUrlJump2); heap_free(stringsA->pszCustomTabs);}
void ReleaseHelpViewer(HHInfo *info){ TRACE("(%p)\n", info);
if (!info) return;
list_remove(&info->entry);
wintype_stringsA_free(&info->stringsA); wintype_stringsW_free(&info->stringsW);
if (info->pCHMInfo) CloseCHM(info->pCHMInfo);
ReleaseWebBrowser(info); ReleaseContent(info); ReleaseIndex(info); ReleaseSearch(info);
if(info->contents.hImageList) ImageList_Destroy(info->contents.hImageList); if(info->WinType.hwndHelp) DestroyWindow(info->WinType.hwndHelp);
heap_free(info); OleUninitialize();}
HHInfo *CreateHelpViewer(HHInfo *info, LPCWSTR filename, HWND caller){ HHInfo *tmp_info; unsigned int i;
if(!info) { info = heap_alloc_zero(sizeof(HHInfo)); list_add_tail(&window_list, &info->entry); }
/* Set the invalid tab ID (-1) as the default value for all * of the tabs, this matches a failed TCM_INSERTITEM call. */ for (i = 0; i < ARRAY_SIZE(info->tabs); i++) info->tabs[i].id = -1;
OleInitialize(NULL);
info->pCHMInfo = OpenCHM(filename); if(!info->pCHMInfo) { ReleaseHelpViewer(info); return NULL; }
if (!LoadWinTypeFromCHM(info)) { ReleaseHelpViewer(info); return NULL; } info->WinType.hwndCaller = caller;
/* If the window is already open then load the file in that existing window */ if ((tmp_info = find_window(info->WinType.pszType)) && tmp_info != info) { ReleaseHelpViewer(info); return CreateHelpViewer(tmp_info, filename, caller); }
if(!info->viewer_initialized && !CreateViewer(info)) { ReleaseHelpViewer(info); return NULL; }
return info;}
/* * Search the table of HTML entities and return the corresponding ANSI symbol. */static char find_html_symbol(const char *entity, int entity_len){ int max = ARRAY_SIZE(html_encoded_symbols)-1; int min = 0, dir;
while(min <= max) { int pos = (min+max)/2; const char *encoded_symbol = html_encoded_symbols[pos].html_code; dir = strncmp(encoded_symbol, entity, entity_len); if(dir == 0 && !encoded_symbol[entity_len]) return html_encoded_symbols[pos].ansi_symbol; if(dir < 0) min = pos+1; else max = pos-1; } return 0;}
/* * Decode a string containing HTML encoded characters into a unicode string. */WCHAR *decode_html(const char *html_fragment, int html_fragment_len, UINT code_page){ const char *h = html_fragment, *amp, *sem; char symbol, *tmp; int len, tmp_len = 0; WCHAR *unicode_text;
tmp = heap_alloc(html_fragment_len+1); while(1) { symbol = 0; amp = strchr(h, '&'); if(!amp) break; len = amp-h; /* Copy the characters prior to the HTML encoded character */ memcpy(&tmp[tmp_len], h, len); tmp_len += len; amp++; /* skip ampersand */ sem = strchr(amp, ';'); /* Require a semicolon after the ampersand */ if(!sem) { h = amp; tmp[tmp_len++] = '&'; continue; } /* Find the symbol either by using the ANSI character number (prefixed by the pound symbol) * or by searching the HTML entity table */ len = sem-amp; if(amp[0] == '#') { char *endnum = NULL; int tmp;
tmp = (char) strtol(amp, &endnum, 10); if(endnum == sem) symbol = tmp; } else symbol = find_html_symbol(amp, len); if(!symbol) { FIXME("Failed to translate HTML encoded character '&%.*s;'.\n", len, amp); h = amp; tmp[tmp_len++] = '&'; continue; } /* Insert the new symbol */ h = sem+1; tmp[tmp_len++] = symbol; } /* Convert any remaining characters */ len = html_fragment_len-(h-html_fragment); memcpy(&tmp[tmp_len], h, len); tmp_len += len; tmp[tmp_len++] = 0; /* NULL-terminate the string */
len = MultiByteToWideChar(code_page, 0, tmp, tmp_len, NULL, 0); unicode_text = heap_alloc(len*sizeof(WCHAR)); MultiByteToWideChar(code_page, 0, tmp, tmp_len, unicode_text, len); heap_free(tmp); return unicode_text;}
/* Find the HTMLHelp structure for an existing window title */HHInfo *find_window(const WCHAR *window){ HHInfo *info;
LIST_FOR_EACH_ENTRY(info, &window_list, HHInfo, entry) { if (lstrcmpW(info->WinType.pszType, window) == 0) return info; } return NULL;}