/* To use this code, you should define LnkCtrl_MemAlloc and LnkCtrl_MemFree before you include this header if your plugin uses a memory function other than GlobalXXX ////////////////////////////////////////////////////////////////////////// nsDialogs: ---------- #define LnkCtrl_MemAlloc(cb) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb)) #define LnkCtrl_MemFree(mem) (HeapFree(GetProcessHeap(), 0, mem)) #define NSISLNKCTRL_UNDERLINED #define NSISLNKCTRL_CURSORHAND #include "../?Shared?/NSISDlg_LinkCtrl.h" ..... case WM_DRAWITEM: if ( !lParam || !GetControl( ((DRAWITEMSTRUCT*)lParam)->hwndItem ) )break; return LnkCtrl_HandleDraw( (DRAWITEMSTRUCT*)lParam , g_dialog.rtl ); ////////////////////////////////////////////////////////////////////////// InstallOptions: --------------- #define LnkCtrl_MemAlloc MALLOC #define LnkCtrl_MemFree FREE #define NSISLNKCTRL_DEFBTN #define NSISLNKCTRL_UNDERLINED #define NSISLNKCTRL_CURSORHAND #include "../?Shared?/NSISDlg_LinkCtrl.h" .... case WM_DRAWITEM: if (FindControlIdx( !lParam || ((DRAWITEMSTRUCT*)lParam)->CtlID) < 0 )break; return LnkCtrl_HandleDraw( (DRAWITEMSTRUCT*)lParam , bRTL ); .... //pField->nParentIdx = SetWindowLong(hwCtrl, GWL_WNDPROC, (long)StaticLINKWindowProc); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// And remember kids, if you change any code in this file, always test with XPStyle on AND off */ #pragma once #include #if 0 # define LnkCtrl_DBGTRACE TRACE # else # define LnkCtrl_DBGTRACE(x) # endif #ifndef ODS_NOACCEL #define ODS_NOACCEL 0x0100 #define ODS_NOFOCUSRECT 0x0200 #endif #ifndef DT_HIDEPREFIX #define DT_HIDEPREFIX 0x00100000 #endif #ifndef NSISLNKCTRL_FINLINE #ifdef _MSC_VER #define NSISLNKCTRL_FINLINE __forceinline #else #define NSISLNKCTRL_FINLINE inline #endif #endif #if defined(NSISLNKCTRL_UNDERLINED) || defined(NSISLNKCTRL_CURSORHAND) || defined(NSISLNKCTRL_DEFBTN) #define NSISLNKCTRL_SUBCLASS typedef struct { // BOOL HasFocusRect; WNDPROC OrgWndProc; #ifdef NSISLNKCTRL_CURSORHAND RECT rcHitTest; #endif #ifdef NSISLNKCTRL_DEFBTN BOOL IsDefBtn; #endif } LNKCTRLDATA; #define LnkCtrl_GetData(hLnk) ((LNKCTRLDATA*)GetProp(hLnk,"NSIS:LnkCtrl")) #define LnkCtrl_SetData(hLnk,pLNKCTRLDATA) (SetProp(hLnk,"NSIS:LnkCtrl",(HANDLE)(LNKCTRLDATA*)pLNKCTRLDATA)) #define LnkCtrl_FreeDataPtr(hLnk) (RemoveProp(hLnk,"NSIS:LnkCtrl")) //"owner" can choose mem functions #ifndef LnkCtrl_MemAlloc //must return 0 on fail! #define LnkCtrl_MemAlloc(cb) (GlobalAlloc(GPTR,cb)) #define LnkCtrl_MemFree(mem) (GlobalFree((HGLOBAL)mem)) #endif #endif /* defined(NSISLNKCTRL_UNDERLINED) || defined(NSISLNKCTRL_CURSORHAND) */ #define LnkCtrl_EraseBkgnd(hwnd,hdc,pRect) (SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)hdc,0)) /*#ifndef NSISLNKCTRL_SUBCLASS #define LnkCtrl_GetFocusState(hwnd) ((BOOL)GetProp(hwnd,"NSIS:LnkCtrl")) #define LnkCtrl_SetFocusState(hwnd,s) (SetProp(hwnd,"NSIS:LnkCtrl",(HANDLE)s)) //other nsD code does not seem to care about RemoveProp, so I'm "leaking" aswell #endif */ #ifdef NSISLNKCTRL_SUBCLASS /*void NSISLNKCTRL_FINLINE LnkCtrl_SetFocusState(HWND hLnk,BOOL HasFocusRect) { LNKCTRLDATA* pLCD=LnkCtrl_GetData(hLnk); if (pLCD)pLCD->HasFocusRect=HasFocusRect; } BOOL NSISLNKCTRL_FINLINE LnkCtrl_GetFocusState(HWND hLnk) { LNKCTRLDATA* pLCD=LnkCtrl_GetData(hLnk); return (pLCD) ? pLCD->HasFocusRect : FALSE; }*/ LRESULT CALLBACK LnkCtrl_SubProc(HWND hwnd,UINT uMsg,WPARAM wp,LPARAM lp) { LNKCTRLDATA* pLCD=LnkCtrl_GetData(hwnd); if (!pLCD) return DefWindowProc(hwnd,uMsg,wp,lp); switch(uMsg) { #ifdef NSISLNKCTRL_CURSORHAND case WM_NCHITTEST: if (pLCD) { POINT pt = {GET_X_LPARAM(lp), GET_Y_LPARAM(lp)}; MapWindowPoints(0, hwnd, &pt, 1); return (PtInRect(&pLCD->rcHitTest, pt)) ? HTCLIENT : HTNOWHERE ; } break; case WM_SETCURSOR: if ((HWND)wp == hwnd && LOWORD(lp) == HTCLIENT) { HCURSOR hCur = LoadCursor(NULL, IDC_HAND); if (hCur) { SetCursor(hCur); return 1; // halt further processing } } break; #endif /* NSISLNKCTRL_CURSORHAND */ #ifdef NSISLNKCTRL_DEFBTN case WM_GETDLGCODE: return DLGC_BUTTON | ((pLCD->IsDefBtn) ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON); case BM_SETSTYLE: pLCD->IsDefBtn= ((wp & BS_TYPEMASK) == BS_DEFPUSHBUTTON); //remember DEFBTN state wp = (wp & ~BS_TYPEMASK) | BS_OWNERDRAW; //turn owner-draw back on lp &= ~(TRUE); //No redraw! break; #endif /* NSISLNKCTRL_DEFBTN */ case WM_NCDESTROY: { const WNDPROC OrgWndProc=pLCD->OrgWndProc; LnkCtrl_MemFree(pLCD); LnkCtrl_FreeDataPtr(hwnd); return CallWindowProc(OrgWndProc,hwnd,uMsg,wp,lp); } } return CallWindowProc(pLCD->OrgWndProc,hwnd,uMsg,wp,lp); } DWORD NSISLNKCTRL_FINLINE LnkCtrl_SubclassInit(HWND hLnk) { LNKCTRLDATA* pLCD=(LNKCTRLDATA*)LnkCtrl_MemAlloc(sizeof(LNKCTRLDATA)); if (!pLCD) return ERROR_OUTOFMEMORY; pLCD->OrgWndProc=(WNDPROC)SetWindowLongPtr(hLnk,GWLP_WNDPROC,(LONG_PTR)LnkCtrl_SubProc); if (pLCD->OrgWndProc) { LnkCtrl_SetData(hLnk,pLCD); return NO_ERROR; } return GetLastError(); } #endif /* NSISLNKCTRL_SUBCLASS */ LRESULT NSISLNKCTRL_FINLINE LnkCtrl_HandleDraw(DRAWITEMSTRUCT*pDIS,const BOOL RTL) { const baseDrawFlags= DT_VCENTER | DT_WORDBREAK; const BOOL hideFocus = !!(pDIS->itemState & ODS_NOFOCUSRECT); const BOOL hideAccel = !!(pDIS->itemState & ODS_NOACCEL); // BOOL hasFocusRect = LnkCtrl_GetFocusState(pDIS->hwndItem); RECT rc; char text[1024]; #ifdef NSISLNKCTRL_UNDERLINED HFONT OldFont; LOGFONT lf; #endif #ifdef NSISLNKCTRL_SUBCLASS LNKCTRLDATA* pLCD=LnkCtrl_GetData(pDIS->hwndItem); if ( !pLCD ) { if ( NO_ERROR==LnkCtrl_SubclassInit(pDIS->hwndItem) ) { //First time HandleDraw was called, force redraw InvalidateRect(pDIS->hwndItem,0,TRUE); } } #endif /* NSISLNKCTRL_SUBCLASS */ #if 0 {BOOL ActionFocus=(pDIS->itemAction & ODA_FOCUS); BOOL StateFocus=(pDIS->itemState & ODS_FOCUS) ; BOOL DrawEntire=(pDIS->itemAction & ODA_DRAWENTIRE); LnkCtrl_DBGTRACE("ActionFcs=%d StateFcs=%d DrawEntire=%d hadFocus=%d HWND=%X:\n",ActionFocus,StateFocus,DrawEntire,hasFocusRect,pDIS->hwndItem);} #endif #ifdef NSISLNKCTRL_UNDERLINED GetObject(GetCurrentObject(pDIS->hDC, OBJ_FONT), sizeof(lf), &lf); lf.lfUnderline = TRUE; OldFont = (HFONT)SelectObject(pDIS->hDC, CreateFontIndirect(&lf)); #endif rc = pDIS->rcItem; // Get button's text text[0] = '\0'; GetWindowText(pDIS->hwndItem, text, 1024); // Calculate needed size of the control DrawText(pDIS->hDC, text, -1, &rc, baseDrawFlags | DT_CALCRECT); // Make some more room so the focus rect won't cut letters off rc.right = min(rc.right + 2, pDIS->rcItem.right); #ifdef NSISLNKCTRL_UNDERLINED //Make more room rc.bottom= min(rc.bottom + 1, pDIS->rcItem.bottom); #endif // Move rect to right if in RTL mode if (RTL) { rc.left += pDIS->rcItem.right - rc.right; rc.right += pDIS->rcItem.right - rc.right; } //Remove old focus rect? /* if ( ( (pDIS->itemAction & ODA_DRAWENTIRE) || !(pDIS->itemState & ODS_FOCUS) ) && hasFocusRect ) { DrawFocusRect(pDIS->hDC, &rc); hasFocusRect=FALSE; LnkCtrl_SetFocusState(pDIS->hwndItem,(FALSE)); LnkCtrl_DBGTRACE("killing focus rect\n"); } */ if ( (pDIS->itemAction & ODA_DRAWENTIRE) ) { COLORREF oldTxtClr=(COLORREF)-1; DWORD xtraDrawStyle = (RTL ? DT_RTLREADING : 0); if (hideAccel) xtraDrawStyle |= DT_HIDEPREFIX; LnkCtrl_EraseBkgnd(pDIS->hwndItem,pDIS->hDC,&rc); if (!GetWindowLong(pDIS->hwndItem, GWL_USERDATA)) oldTxtClr=SetTextColor(pDIS->hDC, RGB(0,0,255)); // Draw the text /*Should we call? */SetBkMode(pDIS->hDC,TRANSPARENT); DrawText(pDIS->hDC, text, -1, &rc, baseDrawFlags | xtraDrawStyle | DT_CENTER ); LnkCtrl_DBGTRACE("ODA_DRAWENTIRE\n"); //BUGFIX: Must restore so we don't corrupt the focus rect if (oldTxtClr!=-1) SetTextColor(pDIS->hDC,oldTxtClr); } if ( ((pDIS->itemState & ODS_FOCUS)&&(pDIS->itemAction & ODA_DRAWENTIRE)) || (pDIS->itemAction & ODA_FOCUS) ) // if ((pDIS->itemState & ODS_FOCUS) && !hasFocusRect) { if (!hideFocus) { DrawFocusRect(pDIS->hDC, &rc); // LnkCtrl_SetFocusState(pDIS->hwndItem,TRUE); LnkCtrl_DBGTRACE("DrawFocusRect\n"); } } #ifdef NSISLNKCTRL_UNDERLINED DeleteObject(SelectObject(pDIS->hDC, OldFont)); #endif #ifdef NSISLNKCTRL_CURSORHAND //update hit-test rect if(pLCD)pLCD->rcHitTest=rc; #endif return TRUE; }