/* 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 #include #define _WIN32_WINNT 0x0500 #define __RPCASYNC_H__ /* header shows warnings in VS6 */ #include #include #define MIRANDA_VER 0x0600 #include #include #include #include #include "help.h" #include #pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */ #include #pragma warning(default:4201) /* nonstandard extension used : nameless struct/union */ #include "resource.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 BOOL 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); SetWindowLong(hwndDlg,GWL_EXSTYLE,GetWindowLong(hwndDlg,GWL_EXSTYLE)|WS_EX_LAYERED); pfnSetLayeredWindowAttributes(hwndDlg,RGB(0,0,0),96,LWA_ALPHA); return FALSE; } case WM_CTLCOLORDLG: return (BOOL)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)GetWindowLong(hwnd,GWL_USERDATA),hwnd,msg,wParam,lParam); } #endif // !defined EDITOR BOOL CALLBACK HelpDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam) { HWND hwndCtl=(HWND)GetWindowLong(hwndDlg,GWL_USERDATA); static LCID locale; #ifndef EDITOR static HWND hwndShadowDlg; static HWND hwndToolTip; #endif switch(msg) { case WM_INITDIALOG: hwndHelpDlg=hwndDlg; #ifdef EDITOR TranslateDialogDefault(hwndDlg); SetWindowLong(GetDlgItem(hwndDlg,IDC_DLGID),GWL_STYLE,GetWindowLong(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); } SetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_WNDPROC,(LONG)HelpSubclassProc)); SetWindowLong(GetDlgItem(hwndDlg,IDC_CARETSUCKER),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_CARETSUCKER),GWL_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); SetWindowLong(GetDlgItem(hwndDlg,IDC_TEXT),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_TEXT),GWL_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); 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=GlobalLock(hglb); 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=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 defined(_UNICODE) if(!SetClipboardData(CF_UNICODETEXT,hglb)) GlobalFree(hglb); // shell takes ownership #else if(!SetClipboardData(CF_TEXT,hglb)) GlobalFree(hglb); // shell takes ownership #endif } 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; SetWindowLong(hwndDlg,GWL_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=GetWindowLong(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=SelectObject(hdc,(HFONT)SendMessage(hwndCtlText,WM_GETFONT,0,0)); // 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); } SetWindowLong(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: SetWindowLong(hwndDlg,DWL_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(); SetWindowLong(hwndDlg,DWL_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); SetWindowLong(hwndDlg,DWL_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)) { CallService(MS_UTILS_OPENURL,1,(LPARAM)pszLink); // pszLink is MBCS string in CP_ACP SetWindowLong(hwndDlg,DWL_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; ZeroMemory(&ti,sizeof(ti)); 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)+(GetWindowLong(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; }