/* Miranda IM Help Plugin Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program (Help-License.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" typedef PLUGININFOEX* (__cdecl *pfnMirandaPluginInfo)(DWORD); WORD settingAutoTipDelay; /* auto show help after those milliseconds, 0 if disabled */ extern HINSTANCE hInst; static HANDLE hHookOptInit; static HWND hwndLangOpt; /**************************** LANGUAGE OPTS ***********************/ /* these are only there for a short time to * debug those radio buttons an Win9x */ #define BOX(str) BOX2("%s (err:%i)", str, GetLastError()) #define BOX2(fmt,p1,p2) { char str[256]; mir_snprintf(str, fmt, p1, p2); MessageBoxA(NULL, str, "dbg", 0); } // ImageList_Destroy() the return value // refresh on WM_THEMECHANGED static HIMAGELIST CreateRadioImages(COLORREF clrBk, COLORREF clrText) { /* draw bitmap */ HDC hdcScreen = GetDC(NULL); if (hdcScreen == NULL) return NULL; HIMAGELIST himl = NULL; HDC hdc = CreateCompatibleDC(NULL); // compatible to screen if (hdc != NULL) { SIZE size = { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) }; RECT rc; SetRect(&rc, 0, 0, 2 * size.cx, size.cy); HBITMAP hbm = CreateCompatibleBitmap(hdcScreen, rc.right, rc.bottom); if (hbm != NULL) { HBITMAP hbmPrev = (HBITMAP)SelectObject(hdc, hbm); if (hbmPrev != NULL) { // error on select? HTHEME hTheme = OpenThemeData(NULL, L"Button"); SetRect(&rc, 0, 0, size.cx, size.cy); /* unchecked */ if (!DrawThemeBackground(hTheme, hdc, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL, &rc, NULL)) { /* checked */ OffsetRect(&rc, size.cx, 0); if (!DrawThemeBackground(hTheme, hdc, BP_RADIOBUTTON, RBS_CHECKEDNORMAL, &rc, NULL)) himl = ImageList_Create(size.cx, size.cy, ILC_COLOR32 | ILC_MASK, 3, 0); } CloseThemeData(hTheme); /* the classic way */ if (himl == NULL) { HBRUSH hbrBk = CreateSolidBrush(clrBk); if (hbrBk != NULL) { FillRect(hdc, &rc, hbrBk); DeleteObject(hbrBk); HDC hdcMono = CreateCompatibleDC(hdc); if (hdcMono != NULL) { HBITMAP hbmMono = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL); if (hbmMono != NULL) { HBITMAP hbmPrevMono = (HBITMAP)SelectObject(hdcMono, hbmMono); if (hbmPrevMono != NULL) { /* error on select? */ /* draws a black-and-white mask (see docs) * we need to colorize it using BitBlt with text and background color */ COLORREF clrPrevText = SetTextColor(hdc, clrText); COLORREF clrPrevBk = SetBkColor(hdc, clrBk); /* check mark is slightly smaller than icon size */ RECT rcRadio; SetRect(&rcRadio, 0, 0, GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)); if (rcRadio.right>size.cx) rcRadio.right = size.cx; if (rcRadio.bottom>size.cy) rcRadio.bottom = size.cy; SetRect(&rc, ((size.cx - rcRadio.right) / 2) + 1, ((size.cy - rcRadio.bottom) / 2) + 1, rcRadio.right + 1, rcRadio.bottom + 1); /* unchecked */ if (BitBlt(hdcMono, 0, 0, rcRadio.right, rcRadio.bottom, NULL, 0, 0, WHITENESS)) { /* white back */ if (DrawFrameControl(hdcMono, &rcRadio, DFC_BUTTON, DFCS_BUTTONRADIO | DFCS_FLAT)) { if (BitBlt(hdc, rc.left, rc.top, rcRadio.right, rcRadio.bottom, hdcMono, 0, 0, SRCCOPY | NOMIRRORBITMAP)) { /* checked */ OffsetRect(&rc, size.cx, 0); if (BitBlt(hdcMono, 0, 0, rcRadio.right, rcRadio.bottom, NULL, 0, 0, WHITENESS)) {/* white back */ if (DrawFrameControl(hdcMono, &rcRadio, DFC_BUTTON, DFCS_BUTTONRADIO | DFCS_FLAT | DFCS_CHECKED)) { if (BitBlt(hdc, rc.left, rc.top, rcRadio.right, rcRadio.bottom, hdcMono, 0, 0, SRCCOPY | NOMIRRORBITMAP)) { himl = ImageList_Create(size.cx, size.cy, ILC_COLOR | ILC_MASK, 3, 0); if (himl == NULL) BOX("img list creation failed"); } } else BOX("second DrawFrameControl() failed"); } else BOX("second BitBlt() failed"); } else BOX("intermediate BitBlt() failed"); } else BOX("DrawFrameControl() failed"); } else BOX("first BitBlt() failed"); /* restore */ SetBkColor(hdc, clrPrevBk); SetTextColor(hdc, clrPrevText); SelectObject(hdcMono, hbmPrevMono); } else BOX("hbmPrevMono==NULL"); DeleteObject(hbmMono); } else BOX("hbmMono==NULL"); DeleteDC(hdcMono); } else BOX("hdcMono==NULL"); } } SelectObject(hdc, hbmPrev); /* create imagelist */ if (himl != NULL) { if (ImageList_AddMasked(himl, hbm, clrBk) == -1) BOX("addmasked failed"); } else BOX("Win9x: drawing code not reached"); } DeleteObject(hbm); } DeleteDC(hdc); } ReleaseDC(NULL, hdcScreen); return himl; } static void CleanupPluginName(char *szShortName) { char *p; /* strip-off anything in brackets */ for (p = szShortName; *p != '\0'; ++p) if (*p == '(' || *p == '[') { *p = '\0'; break; } /* remove trailing space */ int len = lstrlenA(szShortName); while (szShortName[0] != '\0' && szShortName[len - 1] == ' ') szShortName[--len] = 0; } static void DisplayNotIncludedPlugins(HWND hwndListBox, const HELPPACK_INFO *pack) { /* enum plugins */ TCHAR szDir[MAX_PATH]; if (GetModuleFileName(NULL, szDir, _countof(szDir))) { TCHAR *p = _tcsrchr(szDir, _T('\\')); if (p != NULL) *p = _T('\0'); TCHAR szSearch[MAX_PATH]; mir_sntprintf(szSearch, L"%s\\Plugins\\*.dll", szDir); WIN32_FIND_DATA wfd; HANDLE hFind = FindFirstFile(szSearch, &wfd); if (hFind != INVALID_HANDLE_VALUE) { DWORD mirandaVersion = CallService(MS_SYSTEM_GETVERSION, 0, 0); SendMessage(hwndListBox, LB_SETLOCALE, Langpack_GetDefaultLocale(), 0); /* for sort order */ SendMessage(hwndListBox, LB_INITSTORAGE, 128, lstrlenA(pack->szPluginsIncluded)); /* speed up */ do { if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) continue; if ((lstrlen(wfd.cFileName) < 4) || (wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))) continue; /* file name */ lstrcpy(szSearch, wfd.cFileName); /* buffer safe */ p = _tcsrchr(szSearch, _T('.')); if (p != NULL) *p = _T('\0'); char cFileNameA[MAX_PATH]; cFileNameA[0] = '\0'; WideCharToMultiByte(CP_ACP, 0, szSearch, -1, cFileNameA, sizeof(cFileNameA), NULL, NULL); if (IsPluginIncluded(pack, cFileNameA)) continue; /* friendly name of the plugin */ mir_sntprintf(szSearch, L"%s\\Plugins\\%s", szDir, wfd.cFileName); HMODULE hModule = GetModuleHandle(szSearch); BOOL fNeedsFree = (hModule == NULL); if (hModule == NULL) { hModule = LoadLibrary(szSearch); if (hModule == NULL) continue; } /* plugin info */ pfnMirandaPluginInfo pFunc = (pfnMirandaPluginInfo)GetProcAddress(hModule, "MirandaPluginInfoEx"); if (pFunc != NULL) { /* both structs have the same header */ PLUGININFOEX *pluginInfo = pFunc(mirandaVersion); if (pluginInfo != NULL && pluginInfo->cbSize >= sizeof(PLUGININFOEX) && pluginInfo->shortName != NULL) { char buf[128]; lstrcpynA(buf, pluginInfo->shortName, sizeof(buf)); /* buffer safe */ CleanupPluginName(buf); TCHAR buf2[128]; mir_sntprintf(buf2, L"%hs (%s)", buf, CharLower(wfd.cFileName)); SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)buf2); } } if (fNeedsFree) FreeLibrary(hModule); } while (FindNextFile(hFind, &wfd)); FindClose(hFind); } } /* all are included? */ if (!SendMessage(hwndListBox, LB_GETCOUNT, 0, 0)) SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)TranslateT("All installed plugins are included.")); } // pack is allowed to be NULL static void DisplayPackInfo(HWND hwndDlg, const HELPPACK_INFO *pack) { /* show/hide controls */ if (IsWindowVisible(GetDlgItem(hwndDlg, IDC_NOPACK)) == (pack != NULL)) { const int controls[] = { IDC_LANGNOTINCLUDEDLABEL, IDC_LANGNOTINCLUDED, IDC_LANGDATELABEL, IDC_LANGDATE, IDC_LANGLOCALELABEL, IDC_LANGLOCALE, IDC_LANGVERSIONLABEL, IDC_LANGVERSION, IDC_LANGMODUSINGLABEL, IDC_LANGMODUSING, IDC_LANGAUTHORSLABEL, IDC_LANGAUTHORS, IDC_LANGEMAILLABEL, IDC_LANGEMAIL }; for (int i = 0; i < _countof(controls); i++) ShowWindow(GetDlgItem(hwndDlg, controls[i]), (pack != NULL) ? SW_SHOW : SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_NOPACK), (pack != NULL) ? SW_HIDE : SW_SHOW); SetDlgItemText(hwndDlg, IDC_LANGINFOFRAME, NULL); } if (pack == NULL) return; /* compute not-included from included list */ SendDlgItemMessage(hwndDlg, IDC_LANGNOTINCLUDED, LB_RESETCONTENT, 0, 0); DisplayNotIncludedPlugins(GetDlgItem(hwndDlg, IDC_LANGNOTINCLUDED), pack); /* locale string */ if (!(pack->flags&HPF_NOLOCALE)) { TCHAR szLocaleName[128]; szLocaleName[0] = _T('\0'); /* can't use LOCALE_SNAME as it is not present on pre WinVista */ if (!GetLocaleInfo(pack->Locale, LOCALE_SISO639LANGNAME, szLocaleName, _countof(szLocaleName))) { /* Win98/NT4+ */ if (!GetLocaleInfo(pack->Locale, LOCALE_SLANGUAGE, szLocaleName, _countof(szLocaleName))) /* not unique! */ szLocaleName[0] = _T('\0'); } else { if (GetLocaleInfo(pack->Locale, LOCALE_SISO3166CTRYNAME, &szLocaleName[3], _countof(szLocaleName) - 3)) /* Win98/NT4+ */ szLocaleName[2] = _T('-'); } /* add some note if its incompatible */ if (szLocaleName[0]) { if (!IsValidLocale(pack->Locale, LCID_INSTALLED)) { TCHAR *pszIncompat; pszIncompat = TranslateT("(incompatible)"); szLocaleName[_countof(szLocaleName) - lstrlen(pszIncompat) - 1] = 0; lstrcat(lstrcat(szLocaleName, L" "), pszIncompat); /* buffer safe */ } SetDlgItemText(hwndDlg, IDC_LANGLOCALE, szLocaleName); } else SetDlgItemText(hwndDlg, IDC_LANGLOCALE, TranslateT("Unknown")); } else SetDlgItemText(hwndDlg, IDC_LANGLOCALE, TranslateT("Current")); /* file date */ { SYSTEMTIME stFileDate; TCHAR szDate[128]; szDate[0] = _T('\0'); if (FileTimeToSystemTime(&pack->ftFileDate, &stFileDate)) GetDateFormat(Langpack_GetDefaultLocale(), DATE_SHORTDATE, &stFileDate, NULL, szDate, _countof(szDate)); SetDlgItemText(hwndDlg, IDC_LANGDATE, szDate); } /* version */ SetDlgItemTextA(hwndDlg, IDC_LANGVERSION, pack->szVersion); if (pack->szVersion[0] && pack->szFLName[0]) { if (!IsWindowVisible(GetDlgItem(hwndDlg, IDC_LANGVERSIONLABEL))) { ShowWindow(GetDlgItem(hwndDlg, IDC_LANGVERSIONLABEL), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_LANGVERSION), SW_SHOW); } } else { ShowWindow(GetDlgItem(hwndDlg, IDC_LANGVERSIONLABEL), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_LANGVERSION), SW_HIDE); } /* general */ SetDlgItemTextA(hwndDlg, IDC_LANGMODUSING, pack->szLastModifiedUsing); SetDlgItemTextA(hwndDlg, IDC_LANGAUTHORS, pack->szAuthors); SetDlgItemTextA(hwndDlg, IDC_LANGEMAIL, pack->szAuthorEmail); SetDlgItemText(hwndDlg, IDC_LANGINFOFRAME, TranslateTS(pack->szLanguage)); } #define M_RELOADLIST (WM_APP+1) #define M_SHOWFILECOL (WM_APP+2) static void DeletePackFile(HWND hwndDlg, HWND hwndList, int iItem, HELPPACK_INFO *pack) { SHFILEOPSTRUCT sfo = { 0 }; sfo.hwnd = hwndDlg; sfo.wFunc = FO_DELETE; sfo.fFlags = FOF_SIMPLEPROGRESS | FOF_SILENT; /* silent = no progress */ /* double zero terminated */ TCHAR szFileName[MAX_PATH]; if (GetPackPath(szFileName, _countof(szFileName) - 1, pack->flags&HPF_ENABLED, pack->szFileName)) { szFileName[lstrlen(szFileName) + 1] = _T('\0'); sfo.pFrom = szFileName; /* ask to delete file */ if (!SHFileOperation(&sfo) && !sfo.fAnyOperationsAborted) { LVITEM lvi; lvi.iItem = iItem; lvi.iSubItem = 0; lvi.mask = LVIF_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED | LVIS_FOCUSED; if (ListView_GetItem(hwndList, &lvi)) { ListView_DeleteItem(hwndList, iItem); /* enable/select next item at same position */ int nCount = ListView_GetItemCount(hwndList); lvi.iItem = (iItem < nCount) ? iItem : iItem - 1; if (lvi.iItem != -1) { ListView_SetItemState(hwndList, lvi.iItem, lvi.state, lvi.stateMask); /* enable pack file */ lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; if (ListView_GetItem(hwndList, &lvi)) EnablePack((HELPPACK_INFO*)lvi.lParam, L"helppack_*.txt"); } else DisplayPackInfo(hwndDlg, NULL); if (nCount == 1) SendMessage(hwndDlg, M_SHOWFILECOL, 0, FALSE); } } } } static INT_PTR CALLBACK InsertPackItemEnumProc(HELPPACK_INFO *pack, WPARAM wParam, LPARAM lParam) { HELPPACK_INFO *pack2 = (HELPPACK_INFO*)mir_alloc(sizeof(HELPPACK_INFO)); if (pack2 == NULL) return FALSE; CopyMemory(pack2, pack, sizeof(HELPPACK_INFO)); /* country flag icon */ LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; if ((HIMAGELIST)lParam != NULL) { HICON hIcon; if (pack->flags&HPF_DEFAULT) /* not really needed, but to be consistent with LangMan */ hIcon = (HICON)CallService(MS_FLAGS_CREATEMERGEDFLAGICON, CTRY_UNITED_STATES, CTRY_UNITED_KINGDOM); else { int countryId = 0xFFFF; /* Unknown */ TCHAR szBuf[6]; /* get country id from locale */ if (!(pack->flags&HPF_NOLOCALE)) if (GetLocaleInfo(pack->Locale, LOCALE_ICOUNTRY, szBuf, _countof(szBuf))) countryId = _ttoi(szBuf); hIcon = (HICON)CallService(MS_FLAGS_LOADFLAGICON, countryId, 0); } lvi.iImage = (hIcon == NULL) ? -1 : ImageList_AddIcon((HIMAGELIST)lParam, hIcon); lvi.mask |= LVIF_IMAGE; } /* insert */ lvi.iItem = lvi.iSubItem = 0; lvi.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED; lvi.state = INDEXTOSTATEIMAGEMASK((pack->flags&HPF_ENABLED) ? 2 : 1); if (pack->flags&HPF_ENABLED) lvi.state |= LVIS_SELECTED | LVIS_FOCUSED; lvi.pszText = TranslateTS(pack->szLanguage); lvi.lParam = (LPARAM)pack2; ListView_InsertItem((HWND)wParam, &lvi); return TRUE; } static int CALLBACK CompareListItem(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int cmp = CompareString((LCID)lParamSort, 0, ((HELPPACK_INFO*)lParam1)->szLanguage, -1, ((HELPPACK_INFO*)lParam2)->szLanguage, -1); if (cmp) cmp -= 2; if (!cmp) { if (((HELPPACK_INFO*)lParam1)->flags&HPF_ENABLED) cmp = -1; else if (((HELPPACK_INFO*)lParam2)->flags&HPF_ENABLED) cmp = 1; } return cmp; } static INT_PTR CALLBACK LangOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { HWND hwndList = GetDlgItem(hwndDlg, IDC_LANGLIST); LVITEM lvi; switch (msg) { case WM_INITDIALOG: { TranslateDialogDefault(hwndDlg); hwndLangOpt = hwndDlg; ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); ListView_SetImageList(hwndList, CreateRadioImages(ListView_GetBkColor(hwndList), ListView_GetTextColor(hwndList)), LVSIL_STATE); /* auto-destroyed */ { LVCOLUMN lvc; lvc.mask = LVCF_TEXT; lvc.pszText = TranslateT("Installed languages"); ListView_InsertColumn(hwndList, 0, &lvc); } if (ServiceExists(MS_FLAGS_LOADFLAGICON)) ListView_SetImageList(hwndList, ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR24, 8, 8), LVSIL_SMALL); CorrectPacks(L"helppack_*.txt", L"helppack_english.txt", FALSE); SendMessage(hwndDlg, M_RELOADLIST, 0, 0); SendMessage(hwndDlg, M_SHOWFILECOL, 0, 1); return TRUE; } case M_RELOADLIST: { /* init list */ ListView_DeleteAllItems(hwndList); ListView_DeleteColumn(hwndList, 1); /* if present */ { HIMAGELIST himl = ListView_GetImageList(hwndList, LVSIL_SMALL); ImageList_RemoveAll(himl); /* enum all packs */ EnumPacks(InsertPackItemEnumProc, L"helppack_*.txt", "Miranda Help Pack Version 1", (WPARAM)hwndList, (LPARAM)himl); /* nothing installed */ if (!ListView_GetItemCount(hwndList)) DisplayPackInfo(hwndDlg, NULL); /* make it use current langpack locale for sort */ ListView_SortItems(hwndList, CompareListItem, Langpack_GetDefaultLocale()); /* show selection */ int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); if (iItem != -1) ListView_EnsureVisible(hwndList, iItem, FALSE); } return TRUE; } case M_SHOWFILECOL: if ((BOOL)lParam && ListView_GetItemCount(hwndList)>1) { /* add column */ LVCOLUMN lvc; ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE_USEHEADER); lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; lvc.pszText = TranslateT("File"); lvc.cx = 160; ListView_InsertColumn(hwndList, lvc.iSubItem = 1, &lvc); ListView_SetColumnWidth(hwndList, 0, ListView_GetColumnWidth(hwndList, 0) - lvc.cx); /* add text */ lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (lvi.iItem = 0; ListView_GetItem(hwndList, &lvi); ++lvi.iItem) { HELPPACK_INFO *pack = (HELPPACK_INFO*)lvi.lParam; ListView_SetItemText(hwndList, lvi.iItem, 1, pack->szFileName); } } else { ListView_DeleteColumn(hwndList, 1); ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE_USEHEADER); } return TRUE; case WM_THEMECHANGED: case WM_SETTINGCHANGE: { HIMAGELIST himl = ListView_SetImageList(hwndList, CreateRadioImages(ListView_GetBkColor(hwndList), ListView_GetTextColor(hwndList)), LVSIL_STATE); /* auto-destroyed */ if (himl != NULL) ImageList_Destroy(himl); } break; case WM_CTLCOLORLISTBOX: /* mimic readonly edit */ return (BOOL)SendMessage(hwndDlg, WM_CTLCOLORSTATIC, wParam, lParam); case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_LANGEMAIL: { char buf[512]; mir_strcpy(buf, "mailto:"); if (GetDlgItemTextA(hwndDlg, LOWORD(wParam), &buf[7], _countof(buf) - 7)) Utils_OpenUrl(buf); return TRUE; } case IDC_MORELANG: Utils_OpenUrl("https://wiki.miranda-ng.org/index.php?title=Download"); return TRUE; } break; case WM_CONTEXTMENU: if (GetDlgCtrlID((HWND)wParam) == IDC_LANGLIST) { /* get item */ LVHITTESTINFO hti; POINTSTOPOINT(hti.pt, MAKEPOINTS(lParam)); if (hti.pt.x == -1 && hti.pt.y == -1) { /* keyboard invoked */ hti.iItem = ListView_GetNextItem((HWND)wParam, -1, LVNI_SELECTED); if (hti.iItem != -1) break; RECT rc; if (!ListView_GetItemRect((HWND)wParam, hti.iItem, &rc, LVIR_SELECTBOUNDS)) break; hti.pt.x = rc.left + (rc.right - rc.left) / 2; hti.pt.y = rc.top + (rc.bottom - rc.top) / 2; ClientToScreen((HWND)wParam, &hti.pt); } else { ScreenToClient((HWND)wParam, &hti.pt); if (ListView_HitTest((HWND)wParam, &hti) == -1 || !(hti.flags&LVHT_ONITEM)) break; POINTSTOPOINT(hti.pt, MAKEPOINTS(lParam)); } /* param */ lvi.iItem = hti.iItem; lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; if (!ListView_GetItem((HWND)wParam, &lvi)) break; /* context menu */ HELPPACK_INFO *pack = (HELPPACK_INFO*)lvi.lParam; HMENU hContextMenu = CreatePopupMenu(); if (hContextMenu != NULL) { AppendMenu(hContextMenu, MF_STRING, 2, TranslateT("&Remove...")); if (TrackPopupMenuEx(hContextMenu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_HORPOSANIMATION | TPM_VERPOSANIMATION, hti.pt.x, hti.pt.y, (HWND)wParam, NULL)) DeletePackFile(hwndDlg, (HWND)wParam, hti.iItem, pack); DestroyMenu(hContextMenu); } return TRUE; } break; case WM_NOTIFYFORMAT: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, NFR_UNICODE); return TRUE; case WM_NOTIFY: NMHDR *nmhdr = (NMHDR*)lParam; switch (nmhdr->idFrom) { case IDC_LANGLIST: switch (nmhdr->code) { case LVN_DELETEITEM: LVITEM lvi; lvi.iItem = ((NMLISTVIEW*)lParam)->iItem; /* nmlv->lParam is invalid */ lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; if (ListView_GetItem(nmhdr->hwndFrom, &lvi)) mir_free((HELPPACK_INFO*)lvi.lParam); break; case LVN_ITEMCHANGED: { NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam; if (!(nmlv->uChanged&LVIF_STATE)) break; /* display info and check radio item */ if (nmlv->uNewState&LVIS_SELECTED && !(nmlv->uOldState&LVIS_SELECTED)) { ListView_SetItemState(nmhdr->hwndFrom, nmlv->iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK); DisplayPackInfo(hwndDlg, (HELPPACK_INFO*)nmlv->lParam); } /* disable all other radio items */ else if (nmlv->uNewState&INDEXTOSTATEIMAGEMASK(2)) { for (int iItem = ListView_GetItemCount(nmhdr->hwndFrom) - 1; iItem != -1; --iItem) if (iItem != nmlv->iItem) ListView_SetItemState(nmhdr->hwndFrom, iItem, INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK); /* enable apply */ if (nmlv->uOldState) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); } } break; case LVN_KEYDOWN: { int iItem = ListView_GetNextItem(nmhdr->hwndFrom, -1, LVNI_SELECTED); switch (((NMLVKEYDOWN*)lParam)->wVKey) { case VK_SPACE: ListView_SetItemState(nmhdr->hwndFrom, iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK); break; case VK_DELETE: lvi.iItem = iItem; lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; if (ListView_GetItem(nmhdr->hwndFrom, &lvi)) DeletePackFile(hwndDlg, nmhdr->hwndFrom, iItem, (HELPPACK_INFO*)lvi.lParam); break; } } break; case NM_CLICK: LVHITTESTINFO hti; lParam = GetMessagePos(); POINTSTOPOINT(hti.pt, MAKEPOINTS(lParam)); ScreenToClient(nmhdr->hwndFrom, &hti.pt); if (ListView_HitTest(nmhdr->hwndFrom, &hti) != -1) if (hti.flags&(LVHT_ONITEMSTATEICON | LVHT_ONITEMICON)) /* one of them */ ListView_SetItemState(nmhdr->hwndFrom, hti.iItem, LVIS_SELECTED, LVIS_SELECTED); } /* switch nmhdr->code */ break; case 0: switch (nmhdr->code) { case PSN_APPLY: lvi.mask = LVIF_STATE | LVIF_PARAM; lvi.stateMask = LVIS_STATEIMAGEMASK; lvi.iSubItem = 0; for (lvi.iItem = 0; ListView_GetItem(hwndList, &lvi); ++lvi.iItem) { HELPPACK_INFO *pack = (HELPPACK_INFO*)lvi.lParam; if (lvi.state&INDEXTOSTATEIMAGEMASK(2)) { EnablePack(pack, L"helppack_*.txt"); pack->flags |= HPF_ENABLED; } else pack->flags &= ~HPF_ENABLED; } return TRUE; } } /* switch nmhdr->idFrom */ break; } return FALSE; } void ReloadLangOptList(void) { if (hwndLangOpt != NULL) { SendMessage(hwndLangOpt, M_RELOADLIST, 0, 0); SendMessage(hwndLangOpt, M_SHOWFILECOL, 0, 1); } } /**************************** ADV OPTS ****************************/ static INT_PTR CALLBACK AdvOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); { WORD val = settingAutoTipDelay; if (!val) val = db_get_w(NULL, "HelpPlugin", "AutoTipDelay", SETTING_AUTOTIPDELAY_DEFAULT); CheckDlgButton(hwndDlg, IDC_AUTOTIPSENABLED, settingAutoTipDelay != 0); SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_SETRANGE, 0, MAKELPARAM(10000, 500)); SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAY, EM_SETLIMITTEXT, (WPARAM)5, 0); { UDACCEL uda = { 0, 500 }; SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_SETACCEL, 1, (LPARAM)&uda); } SetDlgItemInt(hwndDlg, IDC_AUTOTIPDELAY, val, FALSE); SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_SETPOS, 0, MAKELPARAM(val, 0)); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYLABEL), settingAutoTipDelay != 0); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAY), settingAutoTipDelay != 0); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYSPIN), settingAutoTipDelay != 0); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYMS), settingAutoTipDelay != 0); } return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_AUTOTIPSENABLED: { BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_AUTOTIPSENABLED); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYLABEL), checked); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAY), checked); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYSPIN), checked); EnableWindow(GetDlgItem(hwndDlg, IDC_AUTOTIPDELAYMS), checked); break; } case IDC_AUTOTIPDELAY: if (HIWORD(wParam) == EN_KILLFOCUS) { WORD minVal = HIWORD(SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_GETRANGE, 0, 0)); if (GetDlgItemInt(hwndDlg, IDC_AUTOTIPDELAY, NULL, FALSE)idFrom) { case 0: switch (((LPNMHDR)lParam)->code) { case PSN_APPLY: { WORD minVal; minVal = HIWORD(SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_GETRANGE, 0, 0)); if (GetDlgItemInt(hwndDlg, IDC_AUTOTIPDELAY, NULL, FALSE) < minVal) { SetDlgItemInt(hwndDlg, IDC_AUTOTIPDELAY, minVal, FALSE); SendDlgItemMessage(hwndDlg, IDC_AUTOTIPDELAYSPIN, UDM_SETPOS, 0, MAKELPARAM(minVal, 0)); } settingAutoTipDelay = (WORD)GetDlgItemInt(hwndDlg, IDC_AUTOTIPDELAY, NULL, FALSE); db_set_w(NULL, "HelpPlugin", "AutoTipDelay", settingAutoTipDelay); if (!IsDlgButtonChecked(hwndDlg, IDC_AUTOTIPSENABLED)) settingAutoTipDelay = 0; db_set_b(NULL, "HelpPlugin", "AutoTipsEnabled", (BYTE)(settingAutoTipDelay != 0)); return TRUE; } } break; } break; } return FALSE; } /**************************** INIT ********************************/ static int HelpOptInit(WPARAM wParam, LPARAM) { OPTIONSDIALOGPAGE odp = { 0 }; odp.position = 1200000080; odp.hInstance = hInst; odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LANG); odp.ptszGroup = LPGENT("Customize"); // autotranslated odp.ptszTitle = LPGENT("Help"); // autotranslated odp.ptszTab = LPGENT("Language"); // autotranslated odp.flags = ODPF_TCHAR | ODPF_BOLDGROUPS; odp.pfnDlgProc = LangOptDlgProc; Options_AddPage(wParam, &odp); #ifdef EDITOR odp.ptszTab = L"Help editor"; /* autotranslated */ #else odp.ptszTab = LPGENT("Advanced"); /* autotranslated */ #endif odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ADV); odp.pfnDlgProc = AdvOptDlgProc; Options_AddPage(wParam, &odp); return 0; } void InitOptions(void) { settingAutoTipDelay = 0; if (db_get_b(NULL, "HelpPlugin", "AutoTipsEnabled", SETTING_AUTOTIPSENABLED_DEFAULT)) settingAutoTipDelay = db_get_w(NULL, "HelpPlugin", "AutoTipDelay", SETTING_AUTOTIPDELAY_DEFAULT); hwndLangOpt = NULL; hHookOptInit = HookEvent(ME_OPT_INITIALISE, HelpOptInit); CorrectPacks(L"helppack_*.txt", L"helppack_english.txt", FALSE); } void UninitOptions(void) { UnhookEvent(hHookOptInit); }