ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

help.c
Go to the documentation of this file.
00001 /*
00002  * Help Viewer Implementation
00003  *
00004  * Copyright 2005 James Hawkins
00005  * Copyright 2007 Jacek Caban for CodeWeavers
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "hhctrl.h"
00023 
00024 #include "wingdi.h"
00025 #include "commctrl.h"
00026 #include "wininet.h"
00027 
00028 #include "wine/debug.h"
00029 
00030 #include "resource.h"
00031 
00032 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
00033 
00034 static LRESULT Help_OnSize(HWND hWnd);
00035 
00036 /* Window type defaults */
00037 
00038 #define WINTYPE_DEFAULT_X           280
00039 #define WINTYPE_DEFAULT_Y           100
00040 #define WINTYPE_DEFAULT_WIDTH       740
00041 #define WINTYPE_DEFAULT_HEIGHT      640
00042 #define WINTYPE_DEFAULT_NAVWIDTH    250
00043 
00044 #define TAB_TOP_PADDING     8
00045 #define TAB_RIGHT_PADDING   4
00046 #define TAB_MARGIN  8
00047 #define EDIT_HEIGHT         20
00048 
00049 static const WCHAR szEmpty[] = {0};
00050 
00051 /* Loads a string from the resource file */
00052 static LPWSTR HH_LoadString(DWORD dwID)
00053 {
00054     LPWSTR string = NULL;
00055     LPCWSTR stringresource;
00056     int iSize;
00057 
00058     iSize = LoadStringW(hhctrl_hinstance, dwID, (LPWSTR)&stringresource, 0);
00059 
00060     string = heap_alloc((iSize + 2) * sizeof(WCHAR)); /* some strings (tab text) needs double-null termination */
00061     memcpy(string, stringresource, iSize*sizeof(WCHAR));
00062     string[iSize] = 0;
00063 
00064     return string;
00065 }
00066 
00067 static HRESULT navigate_url(HHInfo *info, LPCWSTR surl)
00068 {
00069     VARIANT url;
00070     HRESULT hres;
00071 
00072     TRACE("%s\n", debugstr_w(surl));
00073 
00074     V_VT(&url) = VT_BSTR;
00075     V_BSTR(&url) = SysAllocString(surl);
00076 
00077     hres = IWebBrowser2_Navigate2(info->web_browser, &url, 0, 0, 0, 0);
00078 
00079     VariantClear(&url);
00080 
00081     if(FAILED(hres))
00082         TRACE("Navigation failed: %08x\n", hres);
00083 
00084     return hres;
00085 }
00086 
00087 BOOL NavigateToUrl(HHInfo *info, LPCWSTR surl)
00088 {
00089     ChmPath chm_path;
00090     BOOL ret;
00091     HRESULT hres;
00092 
00093     static const WCHAR url_indicator[] = {':', '/', '/', 0};
00094 
00095     TRACE("%s\n", debugstr_w(surl));
00096 
00097     if (strstrW(surl, url_indicator)) {
00098         hres = navigate_url(info, surl);
00099         if(SUCCEEDED(hres))
00100             return TRUE;
00101     } /* look up in chm if it doesn't look like a full url */
00102 
00103     SetChmPath(&chm_path, info->pCHMInfo->szFile, surl);
00104     ret = NavigateToChm(info, chm_path.chm_file, chm_path.chm_index);
00105 
00106     heap_free(chm_path.chm_file);
00107     heap_free(chm_path.chm_index);
00108 
00109     return ret;
00110 }
00111 
00112 BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
00113 {
00114     WCHAR buf[INTERNET_MAX_URL_LENGTH];
00115     WCHAR full_path[MAX_PATH];
00116     LPWSTR ptr;
00117 
00118     static const WCHAR url_format[] =
00119         {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0};
00120     static const WCHAR slash[] = {'/',0};
00121     static const WCHAR empty[] = {0};
00122 
00123     TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
00124 
00125     if (!info->web_browser)
00126         return FALSE;
00127 
00128     if(!GetFullPathNameW(file, sizeof(full_path)/sizeof(full_path[0]), full_path, NULL)) {
00129         WARN("GetFullPathName failed: %u\n", GetLastError());
00130         return FALSE;
00131     }
00132 
00133     wsprintfW(buf, url_format, full_path, (!index || index[0] == '/') ? empty : slash, index);
00134 
00135     /* FIXME: HACK */
00136     if((ptr = strchrW(buf, '#')))
00137        *ptr = 0;
00138 
00139     return SUCCEEDED(navigate_url(info, buf));
00140 }
00141 
00142 /* Size Bar */
00143 
00144 #define SIZEBAR_WIDTH   4
00145 
00146 static const WCHAR szSizeBarClass[] = {
00147     'H','H',' ','S','i','z','e','B','a','r',0
00148 };
00149 
00150 /* Draw the SizeBar */
00151 static void SB_OnPaint(HWND hWnd)
00152 {
00153     PAINTSTRUCT ps;
00154     HDC hdc;
00155     RECT rc;
00156     
00157     hdc = BeginPaint(hWnd, &ps);
00158 
00159     GetClientRect(hWnd, &rc);
00160 
00161     /* dark frame */
00162     rc.right += 1;
00163     rc.bottom -= 1;
00164     FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH));
00165 
00166     /* white highlight */
00167     SelectObject(hdc, GetStockObject(WHITE_PEN));
00168     MoveToEx(hdc, rc.right, 1, NULL);
00169     LineTo(hdc, 1, 1);
00170     LineTo(hdc, 1, rc.bottom - 1);
00171 
00172     
00173     MoveToEx(hdc, 0, rc.bottom, NULL);
00174     LineTo(hdc, rc.right, rc.bottom);
00175 
00176     EndPaint(hWnd, &ps);
00177 }
00178 
00179 static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
00180 {
00181     SetCapture(hWnd);
00182 }
00183 
00184 static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
00185 {
00186     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
00187     POINT pt;
00188 
00189     pt.x = (short)LOWORD(lParam);
00190     pt.y = (short)HIWORD(lParam);
00191 
00192     /* update the window sizes */
00193     pHHInfo->WinType.iNavWidth += pt.x;
00194     Help_OnSize(hWnd);
00195 
00196     ReleaseCapture();
00197 }
00198 
00199 static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
00200 {
00201     /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
00202     if (!(wParam & MK_LBUTTON))
00203         return;
00204 }
00205 
00206 static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
00207 {
00208     switch (message)
00209     {
00210         case WM_LBUTTONDOWN:
00211             SB_OnLButtonDown(hWnd, wParam, lParam);
00212             break;
00213         case WM_LBUTTONUP:
00214             SB_OnLButtonUp(hWnd, wParam, lParam);
00215             break;
00216         case WM_MOUSEMOVE:
00217             SB_OnMouseMove(hWnd, wParam, lParam);
00218             break;
00219         case WM_PAINT:
00220             SB_OnPaint(hWnd);
00221             break;
00222         default:
00223             return DefWindowProcW(hWnd, message, wParam, lParam);
00224     }
00225 
00226     return 0;
00227 }
00228 
00229 static void HH_RegisterSizeBarClass(HHInfo *pHHInfo)
00230 {
00231     WNDCLASSEXW wcex;
00232 
00233     wcex.cbSize         = sizeof(WNDCLASSEXW);
00234     wcex.style          = 0;
00235     wcex.lpfnWndProc    = SizeBar_WndProc;
00236     wcex.cbClsExtra     = 0;
00237     wcex.cbWndExtra     = 0;
00238     wcex.hInstance      = hhctrl_hinstance;
00239     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
00240     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE);
00241     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
00242     wcex.lpszMenuName   = NULL;
00243     wcex.lpszClassName  = szSizeBarClass;
00244     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
00245 
00246     RegisterClassExW(&wcex);
00247 }
00248 
00249 static void SB_GetSizeBarRect(HHInfo *info, RECT *rc)
00250 {
00251     RECT rectWND, rectTB, rectNP;
00252 
00253     GetClientRect(info->WinType.hwndHelp, &rectWND);
00254     GetClientRect(info->WinType.hwndToolBar, &rectTB);
00255     GetClientRect(info->WinType.hwndNavigation, &rectNP);
00256 
00257     rc->left = rectNP.right;
00258     rc->top = rectTB.bottom;
00259     rc->bottom = rectWND.bottom - rectTB.bottom;
00260     rc->right = SIZEBAR_WIDTH;
00261 }
00262 
00263 static BOOL HH_AddSizeBar(HHInfo *pHHInfo)
00264 {
00265     HWND hWnd;
00266     HWND hwndParent = pHHInfo->WinType.hwndHelp;
00267     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_OVERLAPPED;
00268     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
00269     RECT rc;
00270 
00271     SB_GetSizeBarRect(pHHInfo, &rc);
00272 
00273     hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles,
00274                            rc.left, rc.top, rc.right, rc.bottom,
00275                            hwndParent, NULL, hhctrl_hinstance, NULL);
00276     if (!hWnd)
00277         return FALSE;
00278 
00279     /* store the pointer to the HH info struct */
00280     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
00281 
00282     pHHInfo->hwndSizeBar = hWnd;
00283     return TRUE;
00284 }
00285 
00286 /* Child Window */
00287 
00288 static const WCHAR szChildClass[] = {
00289     'H','H',' ','C','h','i','l','d',0
00290 };
00291 
00292 static LRESULT Child_OnPaint(HWND hWnd)
00293 {
00294     PAINTSTRUCT ps;
00295     HDC hdc;
00296     RECT rc;
00297 
00298     hdc = BeginPaint(hWnd, &ps);
00299 
00300     /* Only paint the Navigation pane, identified by the fact
00301      * that it has a child window
00302      */
00303     if (GetWindow(hWnd, GW_CHILD))
00304     {
00305         GetClientRect(hWnd, &rc);
00306 
00307         /* set the border color */
00308         SelectObject(hdc, GetStockObject(DC_PEN));
00309         SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
00310 
00311         /* Draw the top border */
00312         LineTo(hdc, rc.right, 0);
00313 
00314         SelectObject(hdc, GetStockObject(WHITE_PEN));
00315         MoveToEx(hdc, 0, 1, NULL);
00316         LineTo(hdc, rc.right, 1);
00317     }
00318 
00319     EndPaint(hWnd, &ps);
00320 
00321     return 0;
00322 }
00323 
00324 static void ResizeTabChild(HHInfo *info, int tab)
00325 {
00326     HWND hwnd = info->tabs[tab].hwnd;
00327     INT width, height;
00328     RECT rect, tabrc;
00329     DWORD cnt;
00330 
00331     GetClientRect(info->WinType.hwndNavigation, &rect);
00332     SendMessageW(info->hwndTabCtrl, TCM_GETITEMRECT, 0, (LPARAM)&tabrc);
00333     cnt = SendMessageW(info->hwndTabCtrl, TCM_GETROWCOUNT, 0, 0);
00334 
00335     rect.left = TAB_MARGIN;
00336     rect.top = TAB_TOP_PADDING + cnt*(tabrc.bottom-tabrc.top) + TAB_MARGIN;
00337     rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN;
00338     rect.bottom -= TAB_MARGIN;
00339     width = rect.right-rect.left;
00340     height = rect.bottom-rect.top;
00341 
00342     SetWindowPos(hwnd, NULL, rect.left, rect.top, width, height,
00343                  SWP_NOZORDER | SWP_NOACTIVATE);
00344 
00345     switch (tab)
00346     {
00347     case TAB_INDEX: {
00348         int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
00349         int border_width = GetSystemMetrics(SM_CXBORDER);
00350         int edge_width = GetSystemMetrics(SM_CXEDGE);
00351 
00352         /* Resize the tab widget column to perfectly fit the tab window and
00353          * leave sufficient space for the scroll widget.
00354          */
00355         SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_SETCOLUMNWIDTH, 0,
00356                      width-scroll_width-2*border_width-2*edge_width);
00357 
00358         break;
00359     }
00360     case TAB_SEARCH: {
00361         int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
00362         int border_width = GetSystemMetrics(SM_CXBORDER);
00363         int edge_width = GetSystemMetrics(SM_CXEDGE);
00364         int top_pos = 0;
00365 
00366         SetWindowPos(info->search.hwndEdit, NULL, 0, top_pos, width,
00367                       EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
00368         top_pos += EDIT_HEIGHT + TAB_MARGIN;
00369         SetWindowPos(info->search.hwndList, NULL, 0, top_pos, width,
00370                       height-top_pos, SWP_NOZORDER | SWP_NOACTIVATE);
00371         /* Resize the tab widget column to perfectly fit the tab window and
00372          * leave sufficient space for the scroll widget.
00373          */
00374         SendMessageW(info->search.hwndList, LVM_SETCOLUMNWIDTH, 0,
00375                      width-scroll_width-2*border_width-2*edge_width);
00376 
00377         break;
00378     }
00379     }
00380 }
00381 
00382 static LRESULT Child_OnSize(HWND hwnd)
00383 {
00384     HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
00385     RECT rect;
00386 
00387     if(!info || hwnd != info->WinType.hwndNavigation)
00388         return 0;
00389 
00390     GetClientRect(hwnd, &rect);
00391     SetWindowPos(info->hwndTabCtrl, HWND_TOP, 0, 0,
00392                  rect.right - TAB_RIGHT_PADDING,
00393                  rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
00394 
00395     ResizeTabChild(info, TAB_CONTENTS);
00396     ResizeTabChild(info, TAB_INDEX);
00397     return 0;
00398 }
00399 
00400 static LRESULT OnTabChange(HWND hwnd)
00401 {
00402     HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
00403 
00404     TRACE("%p\n", hwnd);
00405 
00406     if (!info)
00407         return 0;
00408 
00409     if(info->tabs[info->current_tab].hwnd)
00410         ShowWindow(info->tabs[info->current_tab].hwnd, SW_HIDE);
00411 
00412     info->current_tab = SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0);
00413 
00414     if(info->tabs[info->current_tab].hwnd)
00415         ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW);
00416 
00417     return 0;
00418 }
00419 
00420 static LRESULT OnTopicChange(HHInfo *info, void *user_data)
00421 {
00422     LPCWSTR chmfile = NULL, name = NULL, local = NULL;
00423     ContentItem *citer;
00424     SearchItem *siter;
00425     IndexItem *iiter;
00426 
00427     if(!user_data || !info)
00428         return 0;
00429 
00430     switch (info->current_tab)
00431     {
00432     case TAB_CONTENTS:
00433         citer = (ContentItem *) user_data;
00434         name = citer->name;
00435         local = citer->local;
00436         while(citer) {
00437             if(citer->merge.chm_file) {
00438                 chmfile = citer->merge.chm_file;
00439                 break;
00440             }
00441             citer = citer->parent;
00442         }
00443         break;
00444     case TAB_INDEX:
00445         iiter = (IndexItem *) user_data;
00446         if(iiter->nItems == 0) {
00447             FIXME("No entries for this item!\n");
00448             return 0;
00449         }
00450         if(iiter->nItems > 1) {
00451             int i = 0;
00452             LVITEMW lvi;
00453 
00454             SendMessageW(info->popup.hwndList, LVM_DELETEALLITEMS, 0, 0);
00455             for(i=0;i<iiter->nItems;i++) {
00456                 IndexSubItem *item = &iiter->items[i];
00457                 WCHAR *name = iiter->keyword;
00458 
00459                 if(item->name)
00460                     name = item->name;
00461                 memset(&lvi, 0, sizeof(lvi));
00462                 lvi.iItem = i;
00463                 lvi.mask = LVIF_TEXT|LVIF_PARAM;
00464                 lvi.cchTextMax = strlenW(name)+1;
00465                 lvi.pszText = name;
00466                 lvi.lParam = (LPARAM) item;
00467                 SendMessageW(info->popup.hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
00468             }
00469             ShowWindow(info->popup.hwndPopup, SW_SHOW);
00470             return 0;
00471         }
00472         name = iiter->items[0].name;
00473         local = iiter->items[0].local;
00474         chmfile = iiter->merge.chm_file;
00475         break;
00476     case TAB_SEARCH:
00477         siter = (SearchItem *) user_data;
00478         name = siter->filename;
00479         local = siter->filename;
00480         chmfile = info->pCHMInfo->szFile;
00481         break;
00482     default:
00483         FIXME("Unhandled operation for this tab!\n");
00484         return 0;
00485     }
00486 
00487     if(!chmfile)
00488     {
00489         FIXME("No help file found for this item!\n");
00490         return 0;
00491     }
00492 
00493     TRACE("name %s loal %s\n", debugstr_w(name), debugstr_w(local));
00494 
00495     NavigateToChm(info, chmfile, local);
00496     return 0;
00497 }
00498 
00499 /* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */
00500 static LRESULT CALLBACK EditChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
00501 {
00502     WNDPROC editWndProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
00503 
00504     if(message == WM_KEYUP && wParam == VK_RETURN)
00505     {
00506         NMHDR nmhdr;
00507 
00508         nmhdr.hwndFrom = hWnd;
00509         nmhdr.code = NM_RETURN;
00510         SendMessageW(GetParent(GetParent(hWnd)), WM_NOTIFY, wParam, (LPARAM)&nmhdr);
00511     }
00512     return editWndProc(hWnd, message, wParam, lParam);
00513 }
00514 
00515 static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
00516 {
00517     switch (message)
00518     {
00519     case WM_PAINT:
00520         return Child_OnPaint(hWnd);
00521     case WM_SIZE:
00522         return Child_OnSize(hWnd);
00523     case WM_NOTIFY: {
00524         HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
00525         NMHDR *nmhdr = (NMHDR*)lParam;
00526 
00527         switch(nmhdr->code) {
00528         case TCN_SELCHANGE:
00529             return OnTabChange(hWnd);
00530         case TVN_SELCHANGEDW:
00531             return OnTopicChange(info, (void*)((NMTREEVIEWW *)lParam)->itemNew.lParam);
00532         case NM_DBLCLK:
00533             if(!info)
00534                 return 0;
00535             switch(info->current_tab)
00536             {
00537             case TAB_INDEX:
00538                 return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam);
00539             case TAB_SEARCH:
00540                 return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam);
00541             }
00542             break;
00543         case NM_RETURN:
00544             if(!info)
00545                 return 0;
00546             switch(info->current_tab) {
00547             case TAB_INDEX: {
00548                 HWND hwndList = info->tabs[TAB_INDEX].hwnd;
00549                 LVITEMW lvItem;
00550 
00551                 lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0);
00552                 lvItem.mask = TVIF_PARAM;
00553                 SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
00554                 OnTopicChange(info, (void*) lvItem.lParam);
00555                 return 0;
00556             }
00557             case TAB_SEARCH: {
00558                 if(nmhdr->hwndFrom == info->search.hwndEdit) {
00559                     char needle[100];
00560                     DWORD i, len;
00561 
00562                     len = GetWindowTextA(info->search.hwndEdit, needle, sizeof(needle));
00563                     if(!len)
00564                     {
00565                         FIXME("Unable to get search text.\n");
00566                         return 0;
00567                     }
00568                     /* Convert the requested text for comparison later against the
00569                      * lower case version of HTML file contents.
00570                      */
00571                     for(i=0;i<len;i++)
00572                         needle[i] = tolower(needle[i]);
00573                     InitSearch(info, needle);
00574                     return 0;
00575                 }else if(nmhdr->hwndFrom == info->search.hwndList) {
00576                     HWND hwndList = info->search.hwndList;
00577                     LVITEMW lvItem;
00578 
00579                     lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0);
00580                     lvItem.mask = TVIF_PARAM;
00581                     SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
00582                     OnTopicChange(info, (void*) lvItem.lParam);
00583                     return 0;
00584                 }
00585                 break;
00586             }
00587             }
00588             break;
00589         }
00590         break;
00591     }
00592     default:
00593         return DefWindowProcW(hWnd, message, wParam, lParam);
00594     }
00595 
00596     return 0;
00597 }
00598 
00599 static void HH_RegisterChildWndClass(HHInfo *pHHInfo)
00600 {
00601     WNDCLASSEXW wcex;
00602 
00603     wcex.cbSize         = sizeof(WNDCLASSEXW);
00604     wcex.style          = 0;
00605     wcex.lpfnWndProc    = Child_WndProc;
00606     wcex.cbClsExtra     = 0;
00607     wcex.cbWndExtra     = 0;
00608     wcex.hInstance      = hhctrl_hinstance;
00609     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
00610     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
00611     wcex.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
00612     wcex.lpszMenuName   = NULL;
00613     wcex.lpszClassName  = szChildClass;
00614     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
00615 
00616     RegisterClassExW(&wcex);
00617 }
00618 
00619 /* Toolbar */
00620 
00621 #define ICON_SIZE   20
00622 
00623 static void TB_OnClick(HWND hWnd, DWORD dwID)
00624 {
00625     HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
00626 
00627     switch (dwID)
00628     {
00629         case IDTB_STOP:
00630             DoPageAction(info, WB_STOP);
00631             break;
00632         case IDTB_REFRESH:
00633             DoPageAction(info, WB_REFRESH);
00634             break;
00635         case IDTB_BACK:
00636             DoPageAction(info, WB_GOBACK);
00637             break;
00638         case IDTB_HOME:
00639             NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome);
00640             break;
00641         case IDTB_FORWARD:
00642             DoPageAction(info, WB_GOFORWARD);
00643             break;
00644         case IDTB_EXPAND:
00645         case IDTB_CONTRACT:
00646         case IDTB_SYNC:
00647         case IDTB_PRINT:
00648         case IDTB_OPTIONS:
00649         case IDTB_BROWSE_FWD:
00650         case IDTB_BROWSE_BACK:
00651         case IDTB_JUMP1:
00652         case IDTB_JUMP2:
00653         case IDTB_CUSTOMIZE:
00654         case IDTB_ZOOM:
00655         case IDTB_TOC_NEXT:
00656         case IDTB_TOC_PREV:
00657             break;
00658     }
00659 }
00660 
00661 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
00662 {
00663     /* FIXME: Load the correct button bitmaps */
00664     pButtons[dwIndex].iBitmap = STD_PRINT;
00665     pButtons[dwIndex].idCommand = dwID;
00666     pButtons[dwIndex].fsState = TBSTATE_ENABLED;
00667     pButtons[dwIndex].fsStyle = BTNS_BUTTON;
00668     pButtons[dwIndex].dwData = 0;
00669     pButtons[dwIndex].iString = 0;
00670 }
00671 
00672 static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
00673 {
00674     *pdwNumButtons = 0;
00675 
00676     if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
00677         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
00678 
00679     if (dwButtonFlags & HHWIN_BUTTON_BACK)
00680         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
00681 
00682     if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
00683         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
00684 
00685     if (dwButtonFlags & HHWIN_BUTTON_STOP)
00686         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
00687 
00688     if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
00689         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
00690 
00691     if (dwButtonFlags & HHWIN_BUTTON_HOME)
00692         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
00693 
00694     if (dwButtonFlags & HHWIN_BUTTON_SYNC)
00695         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
00696 
00697     if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
00698         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
00699 
00700     if (dwButtonFlags & HHWIN_BUTTON_PRINT)
00701         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
00702 
00703     if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
00704         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
00705 
00706     if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
00707         TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
00708 
00709     if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
00710         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
00711 
00712     if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
00713         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
00714 
00715     if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
00716         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
00717 }
00718 
00719 static BOOL HH_AddToolbar(HHInfo *pHHInfo)
00720 {
00721     HWND hToolbar;
00722     HWND hwndParent = pHHInfo->WinType.hwndHelp;
00723     DWORD toolbarFlags;
00724     TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
00725     TBADDBITMAP tbAB;
00726     DWORD dwStyles, dwExStyles;
00727     DWORD dwNumButtons, dwIndex;
00728 
00729     if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS)
00730         toolbarFlags = pHHInfo->WinType.fsToolBarFlags;
00731     else
00732         toolbarFlags = HHWIN_DEF_BUTTONS;
00733 
00734     TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
00735 
00736     dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
00737                TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
00738     dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
00739 
00740     hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
00741                                0, 0, 0, 0, hwndParent, NULL,
00742                                hhctrl_hinstance, NULL);
00743     if (!hToolbar)
00744         return FALSE;
00745 
00746     SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
00747     SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
00748     SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
00749 
00750     /* FIXME: Load correct icons for all buttons */
00751     tbAB.hInst = HINST_COMMCTRL;
00752     tbAB.nID = IDB_STD_LARGE_COLOR;
00753     SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
00754 
00755     for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
00756     {
00757         LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand);
00758         DWORD dwLen = strlenW(szBuf);
00759         szBuf[dwLen + 1] = 0; /* Double-null terminate */
00760 
00761         buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf);
00762         heap_free(szBuf);
00763     }
00764 
00765     SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)buttons);
00766     SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
00767     ShowWindow(hToolbar, SW_SHOW);
00768 
00769     pHHInfo->WinType.hwndToolBar = hToolbar;
00770     return TRUE;
00771 }
00772 
00773 /* Navigation Pane */
00774 
00775 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc)
00776 {
00777     HWND hwndParent = pHHInfo->WinType.hwndHelp;
00778     HWND hwndToolbar = pHHInfo->WinType.hwndToolBar;
00779     RECT rectWND, rectTB;
00780 
00781     GetClientRect(hwndParent, &rectWND);
00782     GetClientRect(hwndToolbar, &rectTB);
00783 
00784     rc->left = 0;
00785     rc->top = rectTB.bottom;
00786     rc->bottom = rectWND.bottom - rectTB.bottom;
00787 
00788     if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) &&
00789           pHHInfo->WinType.iNavWidth == 0)
00790     {
00791         pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH;
00792     }
00793 
00794     rc->right = pHHInfo->WinType.iNavWidth;
00795 }
00796 
00797 static DWORD NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD index)
00798 {
00799     TCITEMW tie;
00800     LPWSTR tabText = HH_LoadString(index);
00801     DWORD ret;
00802 
00803     tie.mask = TCIF_TEXT;
00804     tie.pszText = tabText;
00805 
00806     ret = SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, index, (LPARAM)&tie );
00807 
00808     heap_free(tabText);
00809     return ret;
00810 }
00811 
00812 static BOOL HH_AddNavigationPane(HHInfo *info)
00813 {
00814     HWND hWnd, hwndTabCtrl;
00815     HWND hwndParent = info->WinType.hwndHelp;
00816     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
00817     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
00818     RECT rc;
00819 
00820     NP_GetNavigationRect(info, &rc);
00821 
00822     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
00823                            rc.left, rc.top, rc.right, rc.bottom,
00824                            hwndParent, NULL, hhctrl_hinstance, NULL);
00825     if (!hWnd)
00826         return FALSE;
00827 
00828     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
00829 
00830     hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
00831                                   0, TAB_TOP_PADDING,
00832                                   rc.right - TAB_RIGHT_PADDING,
00833                                   rc.bottom - TAB_TOP_PADDING,
00834                                   hWnd, NULL, hhctrl_hinstance, NULL);
00835     if (!hwndTabCtrl)
00836         return FALSE;
00837 
00838     if (*info->WinType.pszToc)
00839         info->tabs[TAB_CONTENTS].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS);
00840 
00841     if (*info->WinType.pszIndex)
00842         info->tabs[TAB_INDEX].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX);
00843 
00844     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH)
00845         info->tabs[TAB_SEARCH].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH);
00846 
00847     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES)
00848         info->tabs[TAB_FAVORITES].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES);
00849 
00850     SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE);
00851 
00852     info->hwndTabCtrl = hwndTabCtrl;
00853     info->WinType.hwndNavigation = hWnd;
00854     return TRUE;
00855 }
00856 
00857 /* HTML Pane */
00858 
00859 static void HP_GetHTMLRect(HHInfo *info, RECT *rc)
00860 {
00861     RECT rectTB, rectWND, rectNP, rectSB;
00862 
00863     GetClientRect(info->WinType.hwndHelp, &rectWND);
00864     GetClientRect(info->WinType.hwndToolBar, &rectTB);
00865     GetClientRect(info->WinType.hwndNavigation, &rectNP);
00866     GetClientRect(info->hwndSizeBar, &rectSB);
00867 
00868     rc->left = rectNP.right + rectSB.right;
00869     rc->top = rectTB.bottom;
00870     rc->right = rectWND.right - rc->left;
00871     rc->bottom = rectWND.bottom - rectTB.bottom;
00872 }
00873 
00874 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
00875 {
00876     HWND hWnd;
00877     HWND hwndParent = pHHInfo->WinType.hwndHelp;
00878     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
00879     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE;
00880     RECT rc;
00881 
00882     HP_GetHTMLRect(pHHInfo, &rc);
00883 
00884     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
00885                            rc.left, rc.top, rc.right, rc.bottom,
00886                            hwndParent, NULL, hhctrl_hinstance, NULL);
00887     if (!hWnd)
00888         return FALSE;
00889 
00890     if (!InitWebBrowser(pHHInfo, hWnd))
00891         return FALSE;
00892 
00893     /* store the pointer to the HH info struct */
00894     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
00895 
00896     ShowWindow(hWnd, SW_SHOW);
00897     UpdateWindow(hWnd);
00898 
00899     pHHInfo->WinType.hwndHTML = hWnd;
00900     return TRUE;
00901 }
00902 
00903 static BOOL AddContentTab(HHInfo *info)
00904 {
00905     if(info->tabs[TAB_CONTENTS].id == -1)
00906         return TRUE; /* No "Contents" tab */
00907     info->tabs[TAB_CONTENTS].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW,
00908            szEmpty, WS_CHILD | WS_BORDER | 0x25, 50, 50, 100, 100,
00909            info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
00910     if(!info->tabs[TAB_CONTENTS].hwnd) {
00911         ERR("Could not create treeview control\n");
00912         return FALSE;
00913     }
00914 
00915     ResizeTabChild(info, TAB_CONTENTS);
00916     ShowWindow(info->tabs[TAB_CONTENTS].hwnd, SW_SHOW);
00917 
00918     return TRUE;
00919 }
00920 
00921 static BOOL AddIndexTab(HHInfo *info)
00922 {
00923     char hidden_column[] = "Column";
00924     LVCOLUMNA lvc;
00925 
00926     if(info->tabs[TAB_INDEX].id == -1)
00927         return TRUE; /* No "Index" tab */
00928     info->tabs[TAB_INDEX].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW,
00929            szEmpty, WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 50, 50, 100, 100,
00930            info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
00931     if(!info->tabs[TAB_INDEX].hwnd) {
00932         ERR("Could not create ListView control\n");
00933         return FALSE;
00934     }
00935     memset(&lvc, 0, sizeof(lvc));
00936     lvc.mask = LVCF_TEXT;
00937     lvc.pszText = hidden_column;
00938     if(SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
00939     {
00940         ERR("Could not create ListView column\n");
00941         return FALSE;
00942     }
00943 
00944     ResizeTabChild(info, TAB_INDEX);
00945     ShowWindow(info->tabs[TAB_INDEX].hwnd, SW_HIDE);
00946 
00947     return TRUE;
00948 }
00949 
00950 static BOOL AddSearchTab(HHInfo *info)
00951 {
00952     HWND hwndList, hwndEdit, hwndContainer;
00953     char hidden_column[] = "Column";
00954     WNDPROC editWndProc;
00955     LVCOLUMNA lvc;
00956 
00957     if(info->tabs[TAB_SEARCH].id == -1)
00958         return TRUE; /* No "Search" tab */
00959     hwndContainer = CreateWindowExW(WS_EX_CONTROLPARENT, szChildClass, szEmpty,
00960                                     WS_CHILD, 0, 0, 0, 0, info->WinType.hwndNavigation,
00961                                     NULL, hhctrl_hinstance, NULL);
00962     if(!hwndContainer) {
00963         ERR("Could not create search window container control.\n");
00964         return FALSE;
00965     }
00966     hwndEdit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, szEmpty, WS_CHILD
00967                                 | WS_VISIBLE | ES_LEFT | SS_NOTIFY, 0, 0, 0, 0,
00968                                hwndContainer, NULL, hhctrl_hinstance, NULL);
00969     if(!hwndEdit) {
00970         ERR("Could not create search ListView control.\n");
00971         return FALSE;
00972     }
00973     if(SendMessageW(hwndEdit, WM_SETFONT, (WPARAM) info->hFont, (LPARAM) FALSE) == -1)
00974     {
00975         ERR("Could not set font for edit control.\n");
00976         return FALSE;
00977     }
00978     editWndProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditChild_WndProc);
00979     if(!editWndProc) {
00980         ERR("Could not redirect messages for edit control.\n");
00981         return FALSE;
00982     }
00983     SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)editWndProc);
00984     hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty,
00985                                WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_SINGLESEL
00986                                 | LVS_REPORT | LVS_NOCOLUMNHEADER, 0, 0, 0, 0,
00987                                hwndContainer, NULL, hhctrl_hinstance, NULL);
00988     if(!hwndList) {
00989         ERR("Could not create search ListView control.\n");
00990         return FALSE;
00991     }
00992     memset(&lvc, 0, sizeof(lvc));
00993     lvc.mask = LVCF_TEXT;
00994     lvc.pszText = hidden_column;
00995     if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
00996     {
00997         ERR("Could not create ListView column\n");
00998         return FALSE;
00999     }
01000 
01001     info->search.hwndEdit = hwndEdit;
01002     info->search.hwndList = hwndList;
01003     info->search.hwndContainer = hwndContainer;
01004     info->tabs[TAB_SEARCH].hwnd = hwndContainer;
01005 
01006     SetWindowLongPtrW(hwndContainer, GWLP_USERDATA, (LONG_PTR)info);
01007 
01008     ResizeTabChild(info, TAB_SEARCH);
01009 
01010     return TRUE;
01011 }
01012 
01013 /* The Index tab's sub-topic popup */
01014 
01015 static void ResizePopupChild(HHInfo *info)
01016 {
01017     int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
01018     int border_width = GetSystemMetrics(SM_CXBORDER);
01019     int edge_width = GetSystemMetrics(SM_CXEDGE);
01020     INT width, height;
01021     RECT rect;
01022 
01023     if(!info)
01024         return;
01025 
01026     GetClientRect(info->popup.hwndPopup, &rect);
01027     SetWindowPos(info->popup.hwndCallback, HWND_TOP, 0, 0,
01028                  rect.right, rect.bottom, SWP_NOMOVE);
01029 
01030     rect.left = TAB_MARGIN;
01031     rect.top = TAB_TOP_PADDING + TAB_MARGIN;
01032     rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN;
01033     rect.bottom -= TAB_MARGIN;
01034     width = rect.right-rect.left;
01035     height = rect.bottom-rect.top;
01036 
01037     SetWindowPos(info->popup.hwndList, NULL, rect.left, rect.top, width, height,
01038                  SWP_NOZORDER | SWP_NOACTIVATE);
01039 
01040     SendMessageW(info->popup.hwndList, LVM_SETCOLUMNWIDTH, 0,
01041                  width-scroll_width-2*border_width-2*edge_width);
01042 }
01043 
01044 static LRESULT CALLBACK HelpPopup_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
01045 {
01046     HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
01047 
01048     switch (message)
01049     {
01050     case WM_SIZE:
01051         ResizePopupChild(info);
01052         return 0;
01053     case WM_DESTROY:
01054         DestroyWindow(hWnd);
01055         return 0;
01056     case WM_CLOSE:
01057         ShowWindow(hWnd, SW_HIDE);
01058         return 0;
01059 
01060     default:
01061         return DefWindowProcW(hWnd, message, wParam, lParam);
01062     }
01063 
01064     return 0;
01065 }
01066 
01067 static LRESULT CALLBACK PopupChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
01068 {
01069     switch (message)
01070     {
01071     case WM_NOTIFY: {
01072         NMHDR *nmhdr = (NMHDR*)lParam;
01073         switch(nmhdr->code)
01074         {
01075         case NM_DBLCLK: {
01076             HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
01077             IndexSubItem *iter;
01078 
01079             if(info == 0 || lParam == 0)
01080                 return 0;
01081             iter = (IndexSubItem*) ((NMITEMACTIVATE *)lParam)->lParam;
01082             if(iter == 0)
01083                 return 0;
01084             NavigateToChm(info, info->index->merge.chm_file, iter->local);
01085             ShowWindow(info->popup.hwndPopup, SW_HIDE);
01086             return 0;
01087         }
01088         case NM_RETURN: {
01089             HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
01090             IndexSubItem *iter;
01091             LVITEMW lvItem;
01092 
01093             if(info == 0)
01094                 return 0;
01095 
01096             lvItem.iItem = (int) SendMessageW(info->popup.hwndList, LVM_GETSELECTIONMARK, 0, 0);
01097             lvItem.mask = TVIF_PARAM;
01098             SendMessageW(info->popup.hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
01099             iter = (IndexSubItem*) lvItem.lParam;
01100             NavigateToChm(info, info->index->merge.chm_file, iter->local);
01101             ShowWindow(info->popup.hwndPopup, SW_HIDE);
01102             return 0;
01103         }
01104         }
01105         break;
01106     }
01107     default:
01108         return DefWindowProcW(hWnd, message, wParam, lParam);
01109     }
01110 
01111     return 0;
01112 }
01113 
01114 static BOOL AddIndexPopup(HHInfo *info)
01115 {
01116     static const WCHAR szPopupChildClass[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0};
01117     static const WCHAR windowCaptionW[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0};
01118     static const WCHAR windowClassW[] = {'H','H',' ','P','o','p','u','p',0};
01119     HWND hwndList, hwndPopup, hwndCallback;
01120     char hidden_column[] = "Column";
01121     WNDCLASSEXW wcex;
01122     LVCOLUMNA lvc;
01123 
01124     if(info->tabs[TAB_INDEX].id == -1)
01125         return TRUE; /* No "Index" tab */
01126 
01127     wcex.cbSize         = sizeof(WNDCLASSEXW);
01128     wcex.style          = CS_HREDRAW | CS_VREDRAW;
01129     wcex.lpfnWndProc    = HelpPopup_WndProc;
01130     wcex.cbClsExtra     = 0;
01131     wcex.cbWndExtra     = 0;
01132     wcex.hInstance      = hhctrl_hinstance;
01133     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01134     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
01135     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
01136     wcex.lpszMenuName   = NULL;
01137     wcex.lpszClassName  = windowClassW;
01138     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01139     RegisterClassExW(&wcex);
01140 
01141     wcex.cbSize         = sizeof(WNDCLASSEXW);
01142     wcex.style          = 0;
01143     wcex.lpfnWndProc    = PopupChild_WndProc;
01144     wcex.cbClsExtra     = 0;
01145     wcex.cbWndExtra     = 0;
01146     wcex.hInstance      = hhctrl_hinstance;
01147     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01148     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
01149     wcex.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
01150     wcex.lpszMenuName   = NULL;
01151     wcex.lpszClassName  = szPopupChildClass;
01152     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01153     RegisterClassExW(&wcex);
01154 
01155     hwndPopup = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW
01156                                  | WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR,
01157                                 windowClassW, windowCaptionW, WS_POPUPWINDOW
01158                                  | WS_OVERLAPPEDWINDOW | WS_VISIBLE
01159                                  | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT,
01160                                 CW_USEDEFAULT, 300, 200, info->WinType.hwndHelp,
01161                                 NULL, hhctrl_hinstance, NULL);
01162     if (!hwndPopup)
01163         return FALSE;
01164 
01165     hwndCallback = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
01166                                    szPopupChildClass, szEmpty, WS_CHILDWINDOW | WS_VISIBLE,
01167                                    0, 0, 0, 0,
01168                                    hwndPopup, NULL, hhctrl_hinstance, NULL);
01169     if (!hwndCallback)
01170         return FALSE;
01171 
01172     ShowWindow(hwndPopup, SW_HIDE);
01173     hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty,
01174                                WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT
01175                                 | LVS_NOCOLUMNHEADER, 50, 50, 100, 100,
01176                                hwndCallback, NULL, hhctrl_hinstance, NULL);
01177     if(!hwndList) {
01178         ERR("Could not create popup ListView control\n");
01179         return FALSE;
01180     }
01181     memset(&lvc, 0, sizeof(lvc));
01182     lvc.mask = LVCF_TEXT;
01183     lvc.pszText = hidden_column;
01184     if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
01185     {
01186         ERR("Could not create popup ListView column\n");
01187         return FALSE;
01188     }
01189 
01190     info->popup.hwndCallback = hwndCallback;
01191     info->popup.hwndPopup = hwndPopup;
01192     info->popup.hwndList = hwndList;
01193     SetWindowLongPtrW(hwndPopup, GWLP_USERDATA, (LONG_PTR)info);
01194     SetWindowLongPtrW(hwndCallback, GWLP_USERDATA, (LONG_PTR)info);
01195 
01196     ResizePopupChild(info);
01197     ShowWindow(hwndList, SW_SHOW);
01198 
01199     return TRUE;
01200 }
01201 
01202 /* Viewer Window */
01203 
01204 static LRESULT Help_OnSize(HWND hWnd)
01205 {
01206     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
01207     DWORD dwSize;
01208     RECT rc;
01209 
01210     if (!pHHInfo)
01211         return 0;
01212 
01213     NP_GetNavigationRect(pHHInfo, &rc);
01214     SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
01215                  rc.right, rc.bottom, SWP_NOMOVE);
01216 
01217     SB_GetSizeBarRect(pHHInfo, &rc);
01218     SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
01219                  rc.right, rc.bottom, SWP_SHOWWINDOW);
01220 
01221     HP_GetHTMLRect(pHHInfo, &rc);
01222     SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top,
01223                  rc.right, rc.bottom, SWP_SHOWWINDOW);
01224 
01225     /* Resize browser window taking the frame size into account */
01226     dwSize = GetSystemMetrics(SM_CXFRAME);
01227     ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize);
01228 
01229     return 0;
01230 }
01231 
01232 static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
01233 {
01234     switch (message)
01235     {
01236     case WM_COMMAND:
01237         if (HIWORD(wParam) == BN_CLICKED)
01238             TB_OnClick(hWnd, LOWORD(wParam));
01239         break;
01240     case WM_SIZE:
01241         return Help_OnSize(hWnd);
01242     case WM_CLOSE:
01243         ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA));
01244         return 0;
01245     case WM_DESTROY:
01246         if(hh_process)
01247             PostQuitMessage(0);
01248         break;
01249 
01250     default:
01251         return DefWindowProcW(hWnd, message, wParam, lParam);
01252     }
01253 
01254     return 0;
01255 }
01256 
01257 static BOOL HH_CreateHelpWindow(HHInfo *info)
01258 {
01259     HWND hWnd;
01260     RECT winPos = info->WinType.rcWindowPos;
01261     WNDCLASSEXW wcex;
01262     DWORD dwStyles, dwExStyles;
01263     DWORD x, y, width = 0, height = 0;
01264     LPCWSTR caption;
01265 
01266     static const WCHAR windowClassW[] = {
01267         'H','H',' ', 'P','a','r','e','n','t',0
01268     };
01269 
01270     wcex.cbSize         = sizeof(WNDCLASSEXW);
01271     wcex.style          = CS_HREDRAW | CS_VREDRAW;
01272     wcex.lpfnWndProc    = Help_WndProc;
01273     wcex.cbClsExtra     = 0;
01274     wcex.cbWndExtra     = 0;
01275     wcex.hInstance      = hhctrl_hinstance;
01276     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01277     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
01278     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
01279     wcex.lpszMenuName   = NULL;
01280     wcex.lpszClassName  = windowClassW;
01281     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
01282 
01283     RegisterClassExW(&wcex);
01284 
01285     /* Read in window parameters if available */
01286     if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES)
01287         dwStyles = info->WinType.dwStyles | WS_OVERLAPPEDWINDOW;
01288     else
01289         dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE |
01290                    WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
01291 
01292     if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES)
01293         dwExStyles = info->WinType.dwExStyles;
01294     else
01295         dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW |
01296                      WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR;
01297 
01298     if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT)
01299     {
01300         x = winPos.left;
01301         y = winPos.top;
01302         width = winPos.right - x;
01303         height = winPos.bottom - y;
01304     }
01305     if (!width || !height)
01306     {
01307         x = WINTYPE_DEFAULT_X;
01308         y = WINTYPE_DEFAULT_Y;
01309         width = WINTYPE_DEFAULT_WIDTH;
01310         height = WINTYPE_DEFAULT_HEIGHT;
01311     }
01312 
01313     caption = info->WinType.pszCaption;
01314     if (!*caption) caption = info->pCHMInfo->defTitle;
01315 
01316     hWnd = CreateWindowExW(dwExStyles, windowClassW, caption,
01317                            dwStyles, x, y, width, height, NULL, NULL, hhctrl_hinstance, NULL);
01318     if (!hWnd)
01319         return FALSE;
01320 
01321     ShowWindow(hWnd, SW_SHOW);
01322     UpdateWindow(hWnd);
01323 
01324     /* store the pointer to the HH info struct */
01325     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
01326 
01327     info->WinType.hwndHelp = hWnd;
01328     return TRUE;
01329 }
01330 
01331 static void HH_CreateFont(HHInfo *pHHInfo)
01332 {
01333     LOGFONTW lf;
01334 
01335     GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
01336     lf.lfWeight = FW_NORMAL;
01337     lf.lfItalic = FALSE;
01338     lf.lfUnderline = FALSE;
01339 
01340     pHHInfo->hFont = CreateFontIndirectW(&lf);
01341 }
01342 
01343 static void HH_InitRequiredControls(DWORD dwControls)
01344 {
01345     INITCOMMONCONTROLSEX icex;
01346 
01347     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
01348     icex.dwICC = dwControls;
01349     InitCommonControlsEx(&icex);
01350 }
01351 
01352 /* Creates the whole package */
01353 static BOOL CreateViewer(HHInfo *pHHInfo)
01354 {
01355     HH_CreateFont(pHHInfo);
01356 
01357     if (!HH_CreateHelpWindow(pHHInfo))
01358         return FALSE;
01359 
01360     HH_InitRequiredControls(ICC_BAR_CLASSES);
01361 
01362     if (!HH_AddToolbar(pHHInfo))
01363         return FALSE;
01364 
01365     HH_RegisterChildWndClass(pHHInfo);
01366 
01367     if (!HH_AddNavigationPane(pHHInfo))
01368         return FALSE;
01369 
01370     HH_RegisterSizeBarClass(pHHInfo);
01371 
01372     if (!HH_AddSizeBar(pHHInfo))
01373         return FALSE;
01374 
01375     if (!HH_AddHTMLPane(pHHInfo))
01376         return FALSE;
01377 
01378     if (!AddContentTab(pHHInfo))
01379         return FALSE;
01380 
01381     if (!AddIndexTab(pHHInfo))
01382         return FALSE;
01383 
01384     if (!AddIndexPopup(pHHInfo))
01385         return FALSE;
01386 
01387     if (!AddSearchTab(pHHInfo))
01388         return FALSE;
01389 
01390     InitContent(pHHInfo);
01391     InitIndex(pHHInfo);
01392 
01393     return TRUE;
01394 }
01395 
01396 void ReleaseHelpViewer(HHInfo *info)
01397 {
01398     TRACE("(%p)\n", info);
01399 
01400     if (!info)
01401         return;
01402 
01403     /* Free allocated strings */
01404     heap_free(info->pszType);
01405     heap_free(info->pszCaption);
01406     heap_free(info->pszToc);
01407     heap_free(info->pszIndex);
01408     heap_free(info->pszFile);
01409     heap_free(info->pszHome);
01410     heap_free(info->pszJump1);
01411     heap_free(info->pszJump2);
01412     heap_free(info->pszUrlJump1);
01413     heap_free(info->pszUrlJump2);
01414 
01415     if (info->pCHMInfo)
01416         CloseCHM(info->pCHMInfo);
01417 
01418     ReleaseWebBrowser(info);
01419     ReleaseContent(info);
01420     ReleaseIndex(info);
01421     ReleaseSearch(info);
01422 
01423     if(info->WinType.hwndHelp)
01424         DestroyWindow(info->WinType.hwndHelp);
01425 
01426     heap_free(info);
01427     OleUninitialize();
01428 }
01429 
01430 HHInfo *CreateHelpViewer(LPCWSTR filename)
01431 {
01432     HHInfo *info = heap_alloc_zero(sizeof(HHInfo));
01433     int i;
01434 
01435     /* Set the invalid tab ID (-1) as the default value for all
01436      * of the tabs, this matches a failed TCM_INSERTITEM call.
01437      */
01438     for(i=0;i<sizeof(info->tabs)/sizeof(HHTab);i++)
01439         info->tabs[i].id = -1;
01440 
01441     OleInitialize(NULL);
01442 
01443     info->pCHMInfo = OpenCHM(filename);
01444     if(!info->pCHMInfo) {
01445         ReleaseHelpViewer(info);
01446         return NULL;
01447     }
01448 
01449     if (!LoadWinTypeFromCHM(info)) {
01450         ReleaseHelpViewer(info);
01451         return NULL;
01452     }
01453 
01454     if(!CreateViewer(info)) {
01455         ReleaseHelpViewer(info);
01456         return NULL;
01457     }
01458 
01459     return info;
01460 }

Generated on Sun May 27 2012 04:16:34 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.