summaryrefslogtreecommitdiff
path: root/plugins/ContextHelp/src/helpdlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ContextHelp/src/helpdlg.cpp')
-rw-r--r--plugins/ContextHelp/src/helpdlg.cpp735
1 files changed, 735 insertions, 0 deletions
diff --git a/plugins/ContextHelp/src/helpdlg.cpp b/plugins/ContextHelp/src/helpdlg.cpp
new file mode 100644
index 0000000000..b035777a0f
--- /dev/null
+++ b/plugins/ContextHelp/src/helpdlg.cpp
@@ -0,0 +1,735 @@
+/*
+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"
+
+
+#include <richedit.h>
+
+extern HINSTANCE hInst;
+HWND hwndHelpDlg;
+
+static int HelpDialogResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+ UNREFERENCED_PARAMETER(hwndDlg);
+ UNREFERENCED_PARAMETER(lParam);
+ switch (urc->wId) {
+ case IDC_CTLTEXT:
+#ifdef EDITOR
+ case IDC_DLGID:
+ case IDC_MODULE:
+#endif
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP;
+ case IDC_TEXT:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+#ifndef EDITOR
+INT_PTR CALLBACK ShadowDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ BOOL(WINAPI *pfnSetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
+ *(FARPROC*)&pfnSetLayeredWindowAttributes = GetProcAddress(GetModuleHandleA("USER32"), "SetLayeredWindowAttributes");
+ if (!pfnSetLayeredWindowAttributes) {
+ *(HANDLE*)lParam = NULL; // hwndShadowDlg reset
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+ EnableWindow(hwndDlg, FALSE);
+ SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) | WS_EX_LAYERED);
+ pfnSetLayeredWindowAttributes(hwndDlg, RGB(0, 0, 0), 96, LWA_ALPHA);
+ return FALSE;
+ }
+ case WM_CTLCOLORDLG:
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOWFRAME);
+ }
+ return FALSE;
+}
+
+// in client coordinates
+int GetCharRangeRect(HWND hwndEdit, LONG *cpMin, LONG cpMax, RECT *rcRange)
+{
+ LONG cpLineBreak;
+
+ LONG nLine, nLinePrev;
+ if (*cpMin>cpMax)
+ return 1;
+ nLine = SendMessage(hwndEdit, EM_EXLINEFROMCHAR, 0, *cpMin);
+ for (cpLineBreak = *cpMin + 1; cpLineBreak <= cpMax; cpLineBreak++) {
+ nLinePrev = nLine;
+ nLine = SendMessage(hwndEdit, EM_EXLINEFROMCHAR, 0, cpLineBreak);
+ if (nLine != nLinePrev)
+ break;
+ }
+ cpMax = cpLineBreak - 1;
+
+ POINTL pt;
+ if (SendMessage(hwndEdit, EM_SETTYPOGRAPHYOPTIONS, 0, 0)) { // test for richedit v3.0
+ SendMessage(hwndEdit, EM_POSFROMCHAR, (WPARAM)&pt, *cpMin);
+ rcRange->left = pt.x;
+ rcRange->top = pt.y;
+ SendMessage(hwndEdit, EM_POSFROMCHAR, (WPARAM)&pt, cpMax);
+ rcRange->right = pt.x;
+ rcRange->bottom = pt.y;
+ }
+ else {
+ DWORD pos;
+ pos = SendMessage(hwndEdit, EM_POSFROMCHAR, (WPARAM)*cpMin, 0);
+ POINTSTOPOINT(pt, MAKEPOINTS(pos));
+ rcRange->left = pt.x;
+ rcRange->top = pt.y;
+ pos = SendMessage(hwndEdit, EM_POSFROMCHAR, (WPARAM)cpMax, 0);
+ POINTSTOPOINT(pt, MAKEPOINTS(pos));
+ rcRange->right = pt.x;
+ rcRange->bottom = pt.y;
+ }
+
+ FORMATRANGE fr;
+ ZeroMemory(&fr, sizeof(fr));
+ fr.chrg.cpMin = *cpMin;
+ fr.chrg.cpMax = cpMax;
+ fr.hdc = fr.hdcTarget = GetDC(hwndEdit);
+ if (fr.hdc == NULL)
+ return 1;
+ SendMessage(hwndEdit, EM_FORMATRANGE, 0, (LPARAM)&fr);
+ PostMessage(hwndEdit, EM_FORMATRANGE, 0, 0); // clear memory
+ rcRange->bottom += MulDiv(fr.rc.bottom, GetDeviceCaps(fr.hdc, LOGPIXELSY), 1440); // twips to pixels
+ ReleaseDC(hwndEdit, fr.hdc);
+
+ *cpMin = cpLineBreak;
+ return 0;
+}
+
+static HCURSOR hHandCursor;
+static LRESULT CALLBACK HelpSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_KEYDOWN:
+ if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'C') {
+ SendMessage(GetParent(hwnd), M_CLIPBOARDCOPY, 0, 0);
+ return 0;
+ }
+ break;
+ case WM_LBUTTONDBLCLK:
+ DestroyWindow(GetParent(hwnd));
+ return 0;
+ case WM_CONTEXTMENU:
+ return DefWindowProc(hwnd, msg, wParam, lParam); // redirect to parent
+ case WM_SETCURSOR: // not available via EN_MSGFILTER
+ if (GetDlgCtrlID((HWND)wParam) == IDC_TEXT) {
+ POINT pt;
+ DWORD pos;
+ CHARRANGE rng;
+ pos = GetMessagePos();
+ POINTSTOPOINT(pt, MAKEPOINTS(pos));
+ ScreenToClient((HWND)wParam, &pt);
+ pos = SendMessage((HWND)wParam, EM_CHARFROMPOS, 0, (WPARAM)&pt);
+ if (IsHyperlink(pos, &rng.cpMin, &rng.cpMax, NULL)) {
+ RECT rc;
+ while (!GetCharRangeRect((HWND)wParam, &rng.cpMin, rng.cpMax, &rc))
+ if (PtInRect(&rc, pt)) {
+ SetCursor(hHandCursor);
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return CallWindowProc((WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA), hwnd, msg, wParam, lParam);
+}
+#endif // !defined EDITOR
+
+INT_PTR CALLBACK HelpDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndCtl = (HWND)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ static LCID locale;
+#ifndef EDITOR
+ static HWND hwndShadowDlg;
+ static HWND hwndToolTip;
+#endif
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ hwndHelpDlg = hwndDlg;
+#ifdef EDITOR
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DLGID), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DLGID), GWL_STYLE) | SS_ENDELLIPSIS);
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETEVENTMASK, 0, ENM_KEYEVENTS);
+ { RECT rcDlg, rcWork;
+ if (SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, FALSE) && GetWindowRect(hwndDlg, &rcDlg))
+ SetWindowPos(hwndDlg, 0, rcDlg.left, rcWork.bottom - rcDlg.bottom + rcDlg.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+#else
+ {
+ RECT rc, rcBuf;
+ SendDlgItemMessage(hwndDlg, IDC_CTLTEXT, EM_GETRECT, 0, (LPARAM)&rcBuf);
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_GETRECT, 0, (LPARAM)&rc);
+ rc.left = rcBuf.left; // sync richedit offset with edit
+ rc.right = rcBuf.right;
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETRECTNP, 0, (LPARAM)&rc);
+ }
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CTLTEXT), GWLP_USERDATA, SetWindowLong(GetDlgItem(hwndDlg, IDC_CTLTEXT), GWLP_WNDPROC, (LONG)HelpSubclassProc));
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CARETSUCKER), GWLP_USERDATA, SetWindowLong(GetDlgItem(hwndDlg, IDC_CARETSUCKER), GWLP_WNDPROC, (LONG)HelpSubclassProc));
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETEVENTMASK, 0, ENM_KEYEVENTS | ENM_MOUSEEVENTS | ENM_REQUESTRESIZE);
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_INFOBK));
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TEXT), GWLP_USERDATA, SetWindowLong(GetDlgItem(hwndDlg, IDC_TEXT), GWLP_WNDPROC, (LONG)HelpSubclassProc));
+ hwndShadowDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SHADOW), hwndDlg, ShadowDlgProc, (LPARAM)&hwndShadowDlg);
+ hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL, hInst, NULL);
+ if (hwndToolTip != NULL) {
+ SetWindowPos(hwndToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ SendMessage(hwndToolTip, TTM_SETTIPBKCOLOR, GetSysColor(COLOR_WINDOW), 0); // yelleow on yellow looks silly
+ SendMessage(hwndToolTip, TTM_SETDELAYTIME, TTDT_AUTOMATIC, GetDoubleClickTime() * 3);
+ }
+ hHandCursor = (HCURSOR)LoadImage(NULL, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ if (hHandCursor == NULL) // use fallback out of miranda32.exe
+ hHandCursor = (HCURSOR)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(214), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+#endif
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETLANGOPTIONS, 0, SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_GETLANGOPTIONS, 0, 0) | IMF_UIFONTS);
+ SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ return TRUE;
+ case WM_SIZE:
+ {
+ /* UTILRESIZEDIALOG urd;
+ ZeroMemory(&urd,sizeof(urd));
+ urd.cbSize=sizeof(urd);
+ urd.hInstance=hInst;
+ urd.hwndDlg=hwndDlg;
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_HELP);
+ urd.pfnResizer=HelpDialogResize;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd); */
+ Utils_ResizeDialog(hwndDlg, hInst, MAKEINTRESOURCEA(IDD_HELP), HelpDialogResize);
+ InvalidateRect(hwndDlg, NULL, TRUE);
+#ifdef EDITOR
+ break;
+#endif
+ }
+#ifndef EDITOR
+ case WM_MOVE:
+ if (IsWindow(hwndShadowDlg)) {
+ RECT rc;
+ HRGN hRgnShadow, hRgnDlg;
+ if (!GetWindowRect(hwndDlg, &rc))
+ break;
+ hRgnShadow = CreateRectRgnIndirect(&rc);
+ if (hRgnShadow == NULL)
+ break;
+ OffsetRgn(hRgnShadow, 5, 5);
+ hRgnDlg = CreateRectRgnIndirect(&rc);
+ if (hRgnDlg == NULL)
+ break;
+ if (CombineRgn(hRgnShadow, hRgnShadow, hRgnDlg, RGN_DIFF) == ERROR) {
+ DeleteObject(hRgnShadow);
+ DeleteObject(hRgnDlg);
+ break;
+ }
+ DeleteObject(hRgnDlg);
+ OffsetRgn(hRgnShadow, -rc.left - 5, -rc.top - 5);
+ SetWindowRgn(hwndShadowDlg, hRgnShadow, FALSE); // system gets ownership of hRgnShadow
+ SetWindowPos(hwndShadowDlg, HWND_TOPMOST, rc.left + 5, rc.top + 5, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW);
+ SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ break;
+ case WM_KEYDOWN:
+ if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'C') {
+ SendMessage(hwndDlg, M_CLIPBOARDCOPY, 0, 0);
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ {
+ HMENU hMenu;
+ POINT pt;
+ POINTSTOPOINT(pt, MAKEPOINTS(lParam));
+ hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, WM_COPY, TranslateT("&Copy"));
+ if (TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_HORPOSANIMATION | TPM_VERPOSANIMATION | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, hwndDlg, NULL))
+ SendMessage(hwndDlg, M_CLIPBOARDCOPY, 0, 0);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ case WM_LBUTTONDBLCLK:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case M_CLIPBOARDCOPY:
+ {
+ HWND hwnd = GetFocus();
+ if (hwnd == GetDlgItem(hwndDlg, IDC_CTLTEXT) || hwnd == GetDlgItem(hwndDlg, IDC_TEXT)) {
+ CHARRANGE sel;
+ ZeroMemory(&sel, sizeof(sel));
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel.cpMin, (LPARAM)&sel.cpMax);
+ if (sel.cpMin != sel.cpMax) {
+ SendMessage(hwnd, WM_COPY, 0, 0);
+ return TRUE;
+ }
+ }
+ }
+ if (OpenClipboard(hwndDlg)) {
+ HGLOBAL hglb;
+ int cch, len;
+ EmptyClipboard();
+ hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(LCID));
+ if (hglb != NULL) {
+ LCID *plocale = (LCID*)GlobalLock(hglb); // look at !!
+ if (plocale != NULL) {
+ *plocale = locale;
+ GlobalUnlock(hglb);
+ if (!SetClipboardData(CF_LOCALE, hglb))
+ GlobalFree(hglb); // shell takes ownership
+ }
+ else
+ GlobalFree(hglb);
+ }
+ cch = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CTLTEXT)) + GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TEXT)) + 3;
+ hglb = GlobalAlloc(GMEM_MOVEABLE, (cch + 1)*sizeof(TCHAR));
+ if (hglb != NULL) {
+ TCHAR *pszText = (TCHAR*)GlobalLock(hglb);
+ if (pszText != NULL) {
+ if (!GetWindowText(GetDlgItem(hwndDlg, IDC_CTLTEXT), pszText, cch - 2)) pszText[0] = _T('\0');
+ len = lstrlen(pszText);
+ if (GetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), pszText + len + 2, cch - 2 - len) && len) {
+ pszText[len] = _T('\r');
+ pszText[len + 1] = _T('\n');
+ }
+ GlobalUnlock(hglb);
+ if (!SetClipboardData(CF_UNICODETEXT, hglb))
+ GlobalFree(hglb); // shell takes ownership
+ }
+ else GlobalFree(hglb);
+ }
+ CloseClipboard();
+ }
+ return TRUE;
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSTATIC:
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_INFOTEXT));
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_INFOBK));
+ return (BOOL)GetSysColorBrush(COLOR_INFOBK);
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_INACTIVE)
+ break;
+ if (GetParent((HWND)lParam) == hwndDlg)
+ break;
+ // fall through
+ case WM_SYSCOLORCHANGE:
+ case WM_ACTIVATEAPP:
+ PostMessage(hwndDlg, WM_CLOSE, 0, 0); // no DestroyWindow() here! would cause recursion
+ break;
+#endif // !defined EDITOR
+ case M_CHANGEHELPCONTROL:
+ if (hwndCtl == (HWND)lParam)
+ break;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ hwndCtl = (HWND)lParam;
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, NULL);
+#ifdef EDITOR
+ {
+ TCHAR text[1024];
+ char *szModule, *szDlgId;
+
+ GetControlTitle(hwndCtl, text, sizeof(text));
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, text);
+ mir_sntprintf(text, sizeof(text), TranslateT("Control ID: %d"), GetControlID(hwndCtl));
+ SetDlgItemText(hwndDlg, IDC_CTLID, text);
+
+ szDlgId = CreateDialogIdString(GetControlDialog(hwndCtl));
+ mir_sntprintf(text, sizeof(text), TranslateT("Dialog ID: %hs"), (szDlgId != NULL) ? szDlgId : Translate("Unknown"));
+ mir_free(szDlgId); // does NULL check
+ SetDlgItemText(hwndDlg, IDC_DLGID, text);
+
+ mir_sntprintf(text, sizeof(text), TranslateT("Type: %s"), TranslateTS(szControlTypeNames[GetControlType(hwndCtl)]));
+ SetDlgItemText(hwndDlg, IDC_CTLTYPE, text);
+
+ szModule = GetControlModuleName(hwndCtl);
+ mir_sntprintf(text, sizeof(text), TranslateT("Module: %hs"), szModule ? szModule : Translate("Unknown"));
+ mir_free(szModule); // does NULL check
+ SetDlgItemText(hwndDlg, IDC_MODULE, text);
+ }
+#endif // defined EDITOR
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+ SendMessage(hwndDlg, M_LOADHELP, 0, 0);
+#ifdef EDITOR
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+#else
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_REQUESTRESIZE, 0, 0);
+ return FALSE;
+#endif
+ return TRUE;
+ case M_HELPLOADFAILED:
+ if (hwndCtl != (HWND)lParam)
+ break;
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT), TRUE);
+ {
+ TCHAR text[2024];
+ GetControlTitle(hwndCtl, text, sizeof(text));
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, text);
+ }
+#else
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, TranslateT("No Help Pack installed!"));
+#endif
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+ MessageBeep(MB_ICONERROR);
+ break;
+#ifdef EDITOR
+ case M_SAVECOMPLETE:
+#endif
+ case M_HELPLOADED:
+ if (hwndCtl != (HWND)lParam)
+ break;
+ case M_LOADHELP:
+ {
+ TCHAR *szTitle;
+ char *szText;
+ char *szDlgId, *szModule;
+ UINT codepage;
+ BOOL isRTL;
+ int id, loading;
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT), TRUE);
+#endif
+ szDlgId = CreateDialogIdString(GetControlDialog(hwndCtl));
+ szModule = GetControlModuleName(hwndCtl);
+ id = GetControlID(hwndCtl);
+#ifndef EDITOR
+ // show id string instead of help text when 'ctrl' key pressed
+ if (msg == M_LOADHELP && GetAsyncKeyState(VK_CONTROL) & 0x8000) {
+ char *buf;
+ HWND hwnd;
+ buf = CreateControlIdentifier(szDlgId ? szDlgId : "unknown", szModule ? szModule : "unknown", id, hwndCtl);
+ hwnd = GetDlgItem(hwndDlg, IDC_CTLTEXT);
+ SetWindowTextA(hwnd, buf); // accepts NULL
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+ mir_free(buf); // does NULL check
+ mir_free(szDlgId); // does NULL check
+ mir_free(szModule); // does NULL check
+ break;
+ }
+#endif
+ if (szDlgId == NULL || szModule == NULL) {
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+#ifndef EDITOR
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, TranslateT("No help available for this item."));
+#endif
+ mir_free(szDlgId); // does NULL check
+ mir_free(szModule); // does NULL check
+ break;
+ }
+
+ loading = GetControlHelp(hwndCtl, szDlgId, szModule, id, &szTitle, &szText, NULL, &locale, &codepage, &isRTL, (msg == M_HELPLOADED) ? GCHF_DONTLOAD : 0);
+ if (!loading) {
+ if (szText)
+ StreamInHtml(GetDlgItem(hwndDlg, IDC_TEXT), szText, codepage, RGB(255, 0, 0));
+ else
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+ if (szTitle) {
+ TCHAR buf[128];
+ RECT rc;
+ HFONT hFontPrev;
+ DWORD exStyle;
+ HWND hwndCtlText;
+ HDC hdc;
+ hwndCtlText = GetDlgItem(hwndDlg, IDC_CTLTEXT);
+ exStyle = GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CTLTEXT), GWL_EXSTYLE);
+ hdc = GetDC(hwndCtlText);
+ {
+ DWORD(WINAPI *pfnGetLayout)(HDC); // obey right-to-left languages
+ *(FARPROC*)&pfnGetLayout = GetProcAddress(GetModuleHandleA("GDI32"), "GetLayout");
+ if (pfnGetLayout) isRTL = (isRTL && !pfnGetLayout(hdc));
+ if (isRTL)
+ exStyle |= WS_EX_RTLREADING | WS_EX_RIGHT;
+ else
+ exStyle &= ~(WS_EX_RTLREADING | WS_EX_RIGHT);
+ }
+ mir_sntprintf(buf, sizeof(buf) - 4, _T("%s"), szTitle);
+ if (hdc != NULL && hwndCtlText != NULL) {
+ SendMessage(hwndCtlText, EM_GETRECT, 0, (LPARAM)&rc);
+ hFontPrev = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hwndCtlText, WM_GETFONT, 0, 0)); // look at !!
+ // doesn't actually draw the string due to DT_CALCRECT
+ DrawTextEx(hdc, buf, -1, &rc, DT_MODIFYSTRING | DT_CALCRECT | DT_EDITCONTROL | DT_END_ELLIPSIS | DT_INTERNAL | (isRTL ? (DT_RTLREADING | DT_RIGHT) : DT_LEFT) | DT_NOPREFIX | DT_SINGLELINE, NULL);
+ SelectObject(hdc, hFontPrev);
+ ReleaseDC(hwndCtlText, hdc);
+ }
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CTLTEXT), GWL_EXSTYLE, exStyle);
+ SetWindowText(hwndCtlText, buf);
+ }
+ else
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, NULL);
+ }
+ else {
+ if (msg == M_HELPLOADED) {
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+#ifndef EDITOR
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, TranslateT("No help available for this item."));
+#endif
+ }
+ else {
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT), FALSE);
+ SetDlgItemText(hwndDlg, IDC_TEXT, TranslateT("Loading..."));
+#else
+ SetDlgItemText(hwndDlg, IDC_CTLTEXT, TranslateT("Loading..."));
+ SetDlgItemText(hwndDlg, IDC_TEXT, NULL);
+#endif
+ }
+ }
+ mir_free(szDlgId);
+ mir_free(szModule);
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->idFrom) {
+ case IDC_TEXT:
+ switch (((NMHDR*)lParam)->code) {
+#ifdef EDITOR
+ case EN_MSGFILTER:
+ switch (((MSGFILTER*)lParam)->msg) {
+ case WM_CHAR:
+ switch (((MSGFILTER*)lParam)->wParam) {
+ case 'B' - 'A' + 1:
+ case 'I' - 'A' + 1:
+ case 'U' - 'A' + 1:
+ case 'H' - 'A' + 1:
+ case 'L' - 'A' + 1:
+ case 'S' - 'A' + 1:
+ case 'G' - 'A' + 1:
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ break;
+ case WM_KEYDOWN:
+ {
+ CHARFORMAT cf;
+ int changes = 0;
+
+ ZeroMemory(&cf, sizeof(cf));
+ if (!(GetKeyState(VK_CONTROL) & 0x8000))
+ break;
+ cf.cbSize = sizeof(cf);
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_GETCHARFORMAT, TRUE, (LPARAM)&cf);
+ switch (((MSGFILTER*)lParam)->wParam) {
+ case 'B':
+ cf.dwEffects ^= CFE_BOLD;
+ cf.dwMask = CFM_BOLD;
+ changes = 1;
+ break;
+ case 'I':
+ cf.dwEffects ^= CFE_ITALIC;
+ cf.dwMask = CFM_ITALIC;
+ changes = 1;
+ break;
+ case 'U':
+ cf.dwEffects ^= CFE_UNDERLINE;
+ cf.dwMask = CFM_UNDERLINE;
+ changes = 1;
+ break;
+ case 'L':
+ {
+ CHOOSECOLOR cc;
+ COLORREF custCol[16];
+ ZeroMemory(&custCol, sizeof(custCol));
+ ZeroMemory(&cc, sizeof(cc));
+ cc.lStructSize = sizeof(cc);
+ cc.hwndOwner = hwndDlg;
+ cc.lpCustColors = custCol;
+ cc.rgbResult = cf.crTextColor;
+ cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
+ if (!ChooseColor(&cc))
+ break;
+ cf.crTextColor = 0;
+ cf.dwEffects = 0;
+ if (cc.rgbResult)
+ cf.crTextColor = cc.rgbResult;
+ else cf.dwEffects = CFE_AUTOCOLOR;
+ cf.dwMask = CFM_COLOR;
+ changes = 1;
+ break;
+ }
+ case 'H':
+ cf.dwEffects ^= CFE_STRIKEOUT;
+ cf.dwMask = CFM_STRIKEOUT;
+ changes = 1;
+ break;
+ case VK_OEM_PLUS:
+ cf.yHeight = ((GetKeyState(VK_SHIFT) & 0x8000) ? TEXTSIZE_BIG : TEXTSIZE_NORMAL) * 10;
+ cf.dwMask = CFM_SIZE;
+ changes = 1;
+ break;
+ case VK_OEM_MINUS:
+ cf.yHeight = TEXTSIZE_SMALL * 10;
+ cf.dwMask = CFM_SIZE;
+ changes = 1;
+ break;
+ case 'S':
+ {
+ TCHAR szTitle[1024];
+ char *szText, *szDlgId, *szModule;
+ if (!GetDlgItemText(hwndDlg, IDC_CTLTEXT, szTitle, sizeof(szTitle)))
+ break;
+ szDlgId = CreateDialogIdString(GetControlDialog(hwndCtl));
+ if (szDlgId == NULL)
+ break;
+ szText = StreamOutHtml(GetDlgItem(hwndDlg, IDC_TEXT));
+ szModule = GetControlModuleName(hwndCtl);
+ if (szModule == NULL) {
+ mir_free(szDlgId);
+ break;
+ }
+ SetControlHelp(szDlgId, szModule, GetControlID(hwndCtl), szTitle, szText, GetControlType(hwndCtl));
+ mir_free(szText);
+ mir_free(szDlgId);
+ mir_free(szModule);
+ SaveDialogCache();
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ case 'G':
+ SendMessage(hwndDlg, M_LOADHELP, 0, 0);
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ if (changes) {
+ SendDlgItemMessage(hwndDlg, IDC_TEXT, EM_SETCHARFORMAT, SCF_WORD | SCF_SELECTION, (LPARAM)&cf);
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ }
+ break;
+#else // defined EDITOR
+ case EN_MSGFILTER:
+ {
+ MSGFILTER *msgf = (MSGFILTER*)lParam;
+ switch (msgf->msg) {
+ case WM_LBUTTONUP:
+ {
+ POINT pt;
+ DWORD pos;
+ CHARRANGE sel;
+ char *pszLink;
+ HWND hwndEdit = msgf->nmhdr.hwndFrom;
+
+ ZeroMemory(&sel, sizeof(sel));
+ SendMessage(msgf->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel);
+ if (sel.cpMin != sel.cpMax)
+ break;
+ POINTSTOPOINT(pt, MAKEPOINTS(msgf->lParam));
+ pos = SendMessage(hwndEdit, EM_CHARFROMPOS, 0, (WPARAM)&pt);
+ if (IsHyperlink(pos, NULL, NULL, &pszLink)) {
+ Utils_OpenUrl(pszLink); // pszLink is MBCS string in CP_ACP
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ break;
+ case WM_MOUSEMOVE: // register hyperlink tooltips when current
+ if (hwndToolTip != NULL) {
+ POINTL pt;
+ DWORD pos;
+ CHARRANGE rng;
+ char *pszLink;
+
+ POINTSTOPOINT(pt, MAKEPOINTS(msgf->lParam));
+ pos = SendMessage(msgf->nmhdr.hwndFrom, EM_CHARFROMPOS, 0, (WPARAM)&pt);
+ if (IsHyperlink(pos, &rng.cpMin, &rng.cpMax, &pszLink)) { // pszLink is MBCS in CP_ACP
+ TTTOOLINFOA ti = { 0 };
+ ti.cbSize = sizeof(ti);
+ ti.hwnd = msgf->nmhdr.hwndFrom;
+ ti.uId = (UINT)rng.cpMin;
+ if (!SendMessage(hwndToolTip, TTM_GETTOOLINFOA, 0, (LPARAM)&ti)) {
+ LONG cpRectMin;
+ ti.uFlags = TTF_SUBCLASS;
+ ti.lpszText = pszLink;
+ cpRectMin = rng.cpMin;
+ while (!GetCharRangeRect(ti.hwnd, &rng.cpMin, rng.cpMax, &ti.rect)) {
+ ti.uId = (UINT)cpRectMin;
+ SendMessage(hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+ cpRectMin = rng.cpMin;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case EN_REQUESTRESIZE:
+ {
+ RECT rcDlg, rcEdit, rcCtl, rcNew;
+ REQRESIZE *rr = (REQRESIZE*)lParam;
+ POINT ptScreenBottomRight;
+
+ if (!GetWindowRect(hwndDlg, &rcDlg))
+ break;
+ if (!GetWindowRect(hwndCtl, &rcCtl))
+ break;
+ if (!GetWindowRect(GetDlgItem(hwndDlg, IDC_TEXT), &rcEdit))
+ break;
+ rcNew.left = rcCtl.left + 30;
+ rcNew.top = rcCtl.bottom + 10;
+ rcNew.right = rcNew.left + (rr->rc.right - rr->rc.left) + (rcDlg.right - rcDlg.left) - (rcEdit.right - rcEdit.left) + (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TEXT), GWL_STYLE)&WS_VSCROLL ? GetSystemMetrics(SM_CXVSCROLL) : 0);
+ if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TEXT)))
+ rcNew.bottom = rcNew.top + min(GetSystemMetrics(SM_CYSCREEN) / 5, (rr->rc.bottom - rr->rc.top) + (rcDlg.bottom - rcDlg.top) - (rcEdit.bottom - rcEdit.top));
+ else
+ rcNew.bottom = rcNew.top + min(GetSystemMetrics(SM_CYSCREEN) / 5, (rcDlg.bottom - rcDlg.top) - (rcEdit.bottom - rcEdit.top));
+ if (GetSystemMetrics(SM_CXVIRTUALSCREEN)) {
+ ptScreenBottomRight.x = GetSystemMetrics(SM_CXVIRTUALSCREEN) + GetSystemMetrics(SM_XVIRTUALSCREEN);
+ ptScreenBottomRight.y = GetSystemMetrics(SM_CYVIRTUALSCREEN) + GetSystemMetrics(SM_YVIRTUALSCREEN);
+ }
+ else {
+ ptScreenBottomRight.x = GetSystemMetrics(SM_CXSCREEN);
+ ptScreenBottomRight.y = GetSystemMetrics(SM_CYSCREEN);
+ }
+ if (rcNew.right >= ptScreenBottomRight.x)
+ OffsetRect(&rcNew, ptScreenBottomRight.x - rcNew.right, 0);
+ if (rcNew.bottom >= ptScreenBottomRight.y)
+ OffsetRect(&rcNew, 0, ptScreenBottomRight.y - rcNew.bottom);
+ SetWindowPos(hwndDlg, 0, rcNew.left, rcNew.top, rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, SWP_NOZORDER);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ break;
+ }
+#endif // defined EDITOR
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL: // WM_CLOSE
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+#ifndef EDITOR
+ FreeHyperlinkData();
+ if (IsWindow(hwndShadowDlg))
+ DestroyWindow(hwndShadowDlg);
+ if (hwndToolTip != NULL)
+ DestroyWindow(hwndToolTip);
+#endif
+ hwndHelpDlg = NULL;
+ break;
+ }
+ return FALSE;
+}