WndShadow.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. // WndShadow.h : header file
  2. //
  3. // Version 0.1
  4. //
  5. // Copyright (c) 2006 Perry Zhu, All Rights Reserved.
  6. //
  7. // mailto:perry@live.com
  8. //
  9. //
  10. // This source file may be redistributed unmodified by any means PROVIDING
  11. // it is NOT sold for profit without the authors expressed written
  12. // consent, and providing that this notice and the author's name and all
  13. // copyright notices remain intact. This software is by no means to be
  14. // included as part of any third party components library, or as part any
  15. // development solution that offers MFC extensions that are sold for profit.
  16. //
  17. // If the source code is used in any commercial applications then a statement
  18. // along the lines of:
  19. //
  20. // "Portions Copyright (c) 2006 Perry Zhu" must be included in the "Startup
  21. // Banner", "About Box" or "Printed Documentation". This software is provided
  22. // "as is" without express or implied warranty. Use it at your own risk! The
  23. // author accepts no liability for any damage/loss of business that this
  24. // product may cause.
  25. //
  26. /////////////////////////////////////////////////////////////////////////////
  27. //****************************************************************************
  28. #include "StdAfx.h"
  29. #include "WndShadow.h"
  30. #include <crtdbg.h>
  31. #include <math.h>
  32. // Some extra work to make this work in VC++ 6.0
  33. // walk around the for iterator scope bug of VC++6.0
  34. #ifdef _MSC_VER
  35. #if _MSC_VER == 1200
  36. #define for if(false);else for
  37. #endif
  38. #endif
  39. // Some definitions for VC++ 6.0 without newest SDK
  40. #ifndef WS_EX_LAYERED
  41. #define WS_EX_LAYERED 0x00080000
  42. #endif
  43. #ifndef AC_SRC_ALPHA
  44. #define AC_SRC_ALPHA 0x01
  45. #endif
  46. #ifndef ULW_ALPHA
  47. #define ULW_ALPHA 0x00000002
  48. #endif
  49. using namespace DuiLib;
  50. CWndShadow::pfnUpdateLayeredWindow CWndShadow::s_UpdateLayeredWindow = NULL;
  51. const TCHAR *strWndClassName = _T("DuiShadowWnd");
  52. HINSTANCE CWndShadow::s_hInstance = (HINSTANCE)INVALID_HANDLE_VALUE;
  53. typedef struct HWNDSHADOW
  54. {
  55. HWND hWnd;
  56. CWndShadow *pWndShadow;
  57. } HwndShadow;
  58. DuiLib::CDuiValArray CWndShadow::s_ShadowArray(sizeof(HwndShadow), 10);
  59. CWndShadow::CWndShadow(void)
  60. : m_hWnd((HWND)INVALID_HANDLE_VALUE)
  61. , m_OriParentProc(NULL)
  62. , m_nDarkness(150)
  63. , m_nSharpness(5)
  64. , m_nSize(0)
  65. , m_nxOffset(5)
  66. , m_nyOffset(5)
  67. , m_Color(RGB(0, 0, 0))
  68. , m_pImageInfo(NULL)
  69. , m_WndSize(0)
  70. , m_bUpdate(false)
  71. {
  72. ::ZeroMemory(&m_rcCorner, sizeof(m_rcCorner));
  73. }
  74. CWndShadow::~CWndShadow(void)
  75. {
  76. if( ::IsWindow(m_hWnd) ) PostMessage(m_hWnd, WM_CLOSE, (WPARAM)0, 0L);
  77. if (m_pImageInfo)
  78. {
  79. CRenderEngine::FreeImage(m_pImageInfo);
  80. m_pImageInfo = NULL;
  81. }
  82. }
  83. bool CWndShadow::Initialize(HINSTANCE hInstance)
  84. {
  85. // Should not initiate more than once
  86. if (NULL != s_UpdateLayeredWindow)
  87. return false;
  88. HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));
  89. s_UpdateLayeredWindow =
  90. (pfnUpdateLayeredWindow)GetProcAddress(hUser32,
  91. "UpdateLayeredWindow");
  92. // If the import did not succeed, make sure your app can handle it!
  93. if (NULL == s_UpdateLayeredWindow)
  94. return false;
  95. // Store the instance handle
  96. s_hInstance = hInstance;
  97. // Register window class for shadow window
  98. WNDCLASSEX wcex;
  99. memset(&wcex, 0, sizeof(wcex));
  100. wcex.cbSize = sizeof(WNDCLASSEX);
  101. wcex.style = CS_HREDRAW | CS_VREDRAW;
  102. wcex.lpfnWndProc = CWndShadow::WndProc;
  103. wcex.cbClsExtra = 0;
  104. wcex.cbWndExtra = 0;
  105. wcex.hInstance = hInstance;
  106. wcex.hIcon = NULL;
  107. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  108. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  109. wcex.lpszMenuName = NULL;
  110. wcex.lpszClassName = strWndClassName;
  111. wcex.hIconSm = NULL;
  112. RegisterClassEx(&wcex);
  113. return true;
  114. }
  115. HWND CWndShadow::GetHWND() const
  116. {
  117. return m_hWnd;
  118. }
  119. CWndShadow::operator HWND() const
  120. {
  121. return m_hWnd;
  122. }
  123. void CWndShadow::Create(HWND hParentWnd)
  124. {
  125. // Do nothing if the system does not support layered windows
  126. if(NULL == s_UpdateLayeredWindow)
  127. return;
  128. // Already initialized
  129. _ASSERT(s_hInstance != INVALID_HANDLE_VALUE);
  130. // Add parent window - shadow pair to the map
  131. _ASSERT(FindShadowWindow(hParentWnd) == NULL); // Only one shadow for each window
  132. HwndShadow hs = {hParentWnd, this};
  133. s_ShadowArray.Add(&hs);
  134. // Create the shadow window
  135. m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,
  136. /*WS_VISIBLE | *//*WS_CAPTION | */WS_POPUPWINDOW,
  137. CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, s_hInstance, NULL);
  138. // Determine the initial show state of shadow according to parent window's state
  139. LONG lParentStyle = GetWindowLong(hParentWnd, GWL_STYLE);
  140. if(!(WS_VISIBLE & lParentStyle)) // Parent invisible
  141. m_Status = SS_ENABLED;
  142. else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
  143. m_Status = SS_ENABLED | SS_PARENTVISIBLE;
  144. else // Show the shadow
  145. {
  146. m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
  147. ::ShowWindow(m_hWnd, SW_SHOWNA);
  148. Update(hParentWnd);
  149. }
  150. // Replace the original WndProc of parent window to steal messages
  151. m_OriParentProc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWLP_WNDPROC);
  152. #pragma warning(disable: 4311) // temporrarily disable the type_cast warning in Win32
  153. SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)ParentProc);
  154. #pragma warning(default: 4311)
  155. }
  156. LRESULT CALLBACK CWndShadow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  157. {
  158. CWindowWnd* pThis = NULL;
  159. if( uMsg == WM_MOUSEACTIVATE ) return MA_NOACTIVATE;
  160. return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
  161. }
  162. LRESULT CALLBACK CWndShadow::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  163. {
  164. CWndShadow *pThis = FindShadowWindow(hwnd);
  165. _ASSERT (pThis);
  166. switch(uMsg)
  167. {
  168. case WM_MOVE:
  169. if(pThis->m_Status & SS_VISABLE)
  170. {
  171. RECT WndRect;
  172. GetWindowRect(hwnd, &WndRect);
  173. if (pThis->m_pImageInfo) {
  174. SetWindowPos(pThis->m_hWnd, NULL,
  175. WndRect.left - pThis->m_rcCorner.left, WndRect.top - pThis->m_rcCorner.top,
  176. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  177. }
  178. else {
  179. SetWindowPos(pThis->m_hWnd, NULL,
  180. WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize,
  181. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  182. }
  183. }
  184. break;
  185. case WM_SIZE:
  186. if(pThis->m_Status & SS_ENABLED)
  187. {
  188. if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam)
  189. {
  190. ::ShowWindow(pThis->m_hWnd, SW_HIDE);
  191. pThis->m_Status &= ~SS_VISABLE;
  192. }
  193. else if(pThis->m_Status & SS_PARENTVISIBLE) // Parent maybe resized even if invisible
  194. {
  195. // Awful! It seems that if the window size was not decreased
  196. // the window region would never be updated until WM_PAINT was sent.
  197. // So do not Update() until next WM_PAINT is received in this case
  198. if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))
  199. pThis->m_bUpdate = true;
  200. else
  201. pThis->Update(hwnd);
  202. if(!(pThis->m_Status & SS_VISABLE))
  203. {
  204. ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);
  205. pThis->m_Status |= SS_VISABLE;
  206. }
  207. }
  208. pThis->m_WndSize = lParam;
  209. }
  210. break;
  211. case WM_PAINT:
  212. {
  213. if(pThis->m_bUpdate)
  214. {
  215. pThis->Update(hwnd);
  216. pThis->m_bUpdate = false;
  217. }
  218. //return hr;
  219. break;
  220. }
  221. // In some cases of sizing, the up-right corner of the parent window region would not be properly updated
  222. // Update() again when sizing is finished
  223. case WM_EXITSIZEMOVE:
  224. if(pThis->m_Status & SS_VISABLE)
  225. {
  226. pThis->Update(hwnd);
  227. }
  228. break;
  229. case WM_SHOWWINDOW:
  230. if(pThis->m_Status & SS_ENABLED)
  231. {
  232. if(!wParam) // the window is being hidden
  233. {
  234. ::ShowWindow(pThis->m_hWnd, SW_HIDE);
  235. pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);
  236. }
  237. else if(!(pThis->m_Status & SS_PARENTVISIBLE))
  238. {
  239. //pThis->Update(hwnd);
  240. pThis->m_bUpdate = true;
  241. ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);
  242. pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;
  243. }
  244. }
  245. break;
  246. case WM_DESTROY:
  247. DestroyWindow(pThis->m_hWnd); // Destroy the shadow
  248. break;
  249. case WM_NCDESTROY:
  250. {
  251. int iIndex = GetShadowWindowIndex(hwnd);
  252. if (iIndex >= 0) s_ShadowArray.Remove(iIndex);
  253. }
  254. break;
  255. }
  256. #pragma warning(disable: 4312) // temporrarily disable the type_cast warning in Win32
  257. // Call the default(original) window procedure for other messages or messages processed but not returned
  258. return ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);
  259. #pragma warning(default: 4312)
  260. }
  261. CWndShadow* CWndShadow::FindShadowWindow(HWND hWnd)
  262. {
  263. for (int i = 0; i < s_ShadowArray.GetSize(); ++i)
  264. {
  265. HwndShadow* hwndShadow = (HwndShadow*)s_ShadowArray[i];
  266. if (hwndShadow->hWnd == hWnd) return hwndShadow->pWndShadow;
  267. }
  268. return NULL;
  269. }
  270. int CWndShadow::GetShadowWindowIndex(HWND hWnd)
  271. {
  272. for (int i = 0; i < s_ShadowArray.GetSize(); ++i)
  273. {
  274. HwndShadow* hwndShadow = (HwndShadow*)s_ShadowArray[i];
  275. if (hwndShadow->hWnd == hWnd) return i;
  276. }
  277. return -1;
  278. }
  279. void CWndShadow::Update(HWND hParent)
  280. {
  281. //int ShadSize = 5;
  282. //int Multi = 100 / ShadSize;
  283. RECT WndRect;
  284. GetWindowRect(hParent, &WndRect);
  285. int nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;
  286. int nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;
  287. if (m_pImageInfo) {
  288. nShadWndWid = WndRect.right - WndRect.left + m_rcCorner.left + m_rcCorner.right;
  289. nShadWndHei = WndRect.bottom - WndRect.top + m_rcCorner.top + m_rcCorner.bottom;
  290. }
  291. // Create the alpha blending bitmap
  292. BITMAPINFO bmi; // bitmap header
  293. ZeroMemory(&bmi, sizeof(BITMAPINFO));
  294. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  295. bmi.bmiHeader.biWidth = nShadWndWid;
  296. bmi.bmiHeader.biHeight = nShadWndHei;
  297. bmi.bmiHeader.biPlanes = 1;
  298. bmi.bmiHeader.biBitCount = 32; // four 8-bit components
  299. bmi.bmiHeader.biCompression = BI_RGB;
  300. bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;
  301. BYTE *pvBits; // pointer to DIB section
  302. HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);
  303. ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);
  304. HDC hMemDC = CreateCompatibleDC(NULL);
  305. HBITMAP hOriBmp = NULL;
  306. if (m_pImageInfo)
  307. {
  308. hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
  309. RECT rc = {0, 0, nShadWndWid, nShadWndHei};
  310. RECT rcBmpPart = {0, 0, m_pImageInfo->nX, m_pImageInfo->nY};
  311. RECT rcCorner = {m_rcCorner.left + m_rcHoleOffset.left, m_rcCorner.top + m_rcHoleOffset.top,
  312. m_rcCorner.right + m_rcHoleOffset.right, m_rcCorner.bottom + m_rcHoleOffset.bottom};
  313. CRenderEngine::DrawImage(hMemDC, m_pImageInfo->hBitmap, rc, rc, rcBmpPart, rcCorner, true, 255, true);
  314. }
  315. else
  316. {
  317. MakeShadow((UINT32 *)pvBits, hParent, &WndRect);
  318. hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
  319. }
  320. POINT ptDst = {WndRect.left + m_nxOffset - m_nSize, WndRect.top + m_nyOffset - m_nSize};
  321. if (m_pImageInfo) {
  322. ptDst.x = WndRect.left - m_rcCorner.left;
  323. ptDst.y = WndRect.top - m_rcCorner.top;
  324. }
  325. POINT ptSrc = {0, 0};
  326. SIZE WndSize = {nShadWndWid, nShadWndHei};
  327. BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  328. MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);
  329. BOOL bRet= s_UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC,
  330. &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);
  331. _ASSERT(bRet); // something was wrong....
  332. // Delete used resources
  333. if (hOriBmp) SelectObject(hMemDC, hOriBmp);
  334. if (hbitmap) DeleteObject(hbitmap);
  335. DeleteDC(hMemDC);
  336. }
  337. void CWndShadow::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
  338. {
  339. // The shadow algorithm:
  340. // Get the region of parent window,
  341. // Apply morphologic erosion to shrink it into the size (ShadowWndSize - Sharpness)
  342. // Apply modified (with blur effect) morphologic dilation to make the blurred border
  343. // The algorithm is optimized by assuming parent window is just "one piece" and without "wholes" on it
  344. // Get the region of parent window,
  345. HRGN hParentRgn = CreateRectRgn(0, 0, rcParent->right - rcParent->left, rcParent->bottom - rcParent->top);
  346. GetWindowRgn(hParent, hParentRgn);
  347. // Determine the Start and end point of each horizontal scan line
  348. SIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};
  349. SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};
  350. // Extra 2 lines (set to be empty) in ptAnchors are used in dilation
  351. int nAnchors = max(szParent.cy, szShadow.cy); // # of anchor points pares
  352. int (*ptAnchors)[2] = new int[nAnchors + 2][2];
  353. int (*ptAnchorsOri)[2] = new int[szParent.cy][2]; // anchor points, will not modify during erosion
  354. ptAnchors[0][0] = szParent.cx;
  355. ptAnchors[0][1] = 0;
  356. ptAnchors[nAnchors + 1][0] = szParent.cx;
  357. ptAnchors[nAnchors + 1][1] = 0;
  358. if(m_nSize > 0)
  359. {
  360. // Put the parent window anchors at the center
  361. for(int i = 0; i < m_nSize; i++)
  362. {
  363. ptAnchors[i + 1][0] = szParent.cx;
  364. ptAnchors[i + 1][1] = 0;
  365. ptAnchors[szShadow.cy - i][0] = szParent.cx;
  366. ptAnchors[szShadow.cy - i][1] = 0;
  367. }
  368. ptAnchors += m_nSize;
  369. }
  370. for(int i = 0; i < szParent.cy; i++)
  371. {
  372. // find start point
  373. int j;
  374. for(j = 0; j < szParent.cx; j++)
  375. {
  376. if(PtInRegion(hParentRgn, j, i))
  377. {
  378. ptAnchors[i + 1][0] = j + m_nSize;
  379. ptAnchorsOri[i][0] = j;
  380. break;
  381. }
  382. }
  383. if(j >= szParent.cx) // Start point not found
  384. {
  385. ptAnchors[i + 1][0] = szParent.cx;
  386. ptAnchorsOri[i][1] = 0;
  387. ptAnchors[i + 1][0] = szParent.cx;
  388. ptAnchorsOri[i][1] = 0;
  389. }
  390. else
  391. {
  392. // find end point
  393. for(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--)
  394. {
  395. if(PtInRegion(hParentRgn, j, i))
  396. {
  397. ptAnchors[i + 1][1] = j + 1 + m_nSize;
  398. ptAnchorsOri[i][1] = j + 1;
  399. break;
  400. }
  401. }
  402. }
  403. }
  404. if(m_nSize > 0)
  405. ptAnchors -= m_nSize; // Restore pos of ptAnchors for erosion
  406. int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2]; // Store the result of erosion
  407. // First and last line should be empty
  408. ptAnchorsTmp[0][0] = szParent.cx;
  409. ptAnchorsTmp[0][1] = 0;
  410. ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;
  411. ptAnchorsTmp[nAnchors + 1][1] = 0;
  412. int nEroTimes = 0;
  413. // morphologic erosion
  414. for(int i = 0; i < m_nSharpness - m_nSize; i++)
  415. {
  416. nEroTimes++;
  417. //ptAnchorsTmp[1][0] = szParent.cx;
  418. //ptAnchorsTmp[1][1] = 0;
  419. //ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;
  420. //ptAnchorsTmp[szParent.cy + 1][1] = 0;
  421. for(int j = 1; j < nAnchors + 1; j++)
  422. {
  423. ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;
  424. ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;
  425. }
  426. // Exchange ptAnchors and ptAnchorsTmp;
  427. int (*ptAnchorsXange)[2] = ptAnchorsTmp;
  428. ptAnchorsTmp = ptAnchors;
  429. ptAnchors = ptAnchorsXange;
  430. }
  431. // morphologic dilation
  432. ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1; // now coordinates in ptAnchors are same as in shadow window
  433. // Generate the kernel
  434. int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;
  435. int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;
  436. UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];
  437. UINT32 *pKernelIter = pKernel;
  438. for(int i = 0; i <= 2 * nKernelSize; i++)
  439. {
  440. for(int j = 0; j <= 2 * nKernelSize; j++)
  441. {
  442. double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));
  443. if(dLength < nCenterSize)
  444. *pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  445. else if(dLength <= nKernelSize)
  446. {
  447. UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));
  448. *pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);
  449. }
  450. else
  451. *pKernelIter = 0;
  452. //TRACE("%d ", *pKernelIter >> 24);
  453. pKernelIter ++;
  454. }
  455. //TRACE("\n");
  456. }
  457. // Generate blurred border
  458. for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)
  459. {
  460. int j;
  461. if(ptAnchors[i][0] < ptAnchors[i][1])
  462. {
  463. // Start of line
  464. for(j = ptAnchors[i][0];
  465. j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]);
  466. j++)
  467. {
  468. for(int k = 0; k <= 2 * nKernelSize; k++)
  469. {
  470. UINT32 *pPixel = pShadBits +
  471. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  472. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  473. for(int l = 0; l <= 2 * nKernelSize; l++)
  474. {
  475. if(*pPixel < *pKernelPixel)
  476. *pPixel = *pKernelPixel;
  477. pPixel++;
  478. pKernelPixel++;
  479. }
  480. }
  481. } // for() start of line
  482. // End of line
  483. for(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1);
  484. j < ptAnchors[i][1];
  485. j++)
  486. {
  487. for(int k = 0; k <= 2 * nKernelSize; k++)
  488. {
  489. UINT32 *pPixel = pShadBits +
  490. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  491. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  492. for(int l = 0; l <= 2 * nKernelSize; l++)
  493. {
  494. if(*pPixel < *pKernelPixel)
  495. *pPixel = *pKernelPixel;
  496. pPixel++;
  497. pKernelPixel++;
  498. }
  499. }
  500. } // for() end of line
  501. }
  502. } // for() Generate blurred border
  503. // Erase unwanted parts and complement missing
  504. UINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  505. for(int i = min(nKernelSize, max(m_nSize - m_nyOffset, 0));
  506. i < max(szShadow.cy - nKernelSize, min(szParent.cy + m_nSize - m_nyOffset, szParent.cy + 2 * m_nSize));
  507. i++)
  508. {
  509. UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;
  510. if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy) // Line is not covered by parent window
  511. {
  512. for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++)
  513. {
  514. *(pLine + j) = clCenter;
  515. }
  516. }
  517. else
  518. {
  519. for(int j = ptAnchors[i][0];
  520. j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]);
  521. j++)
  522. *(pLine + j) = clCenter;
  523. for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, 0);
  524. j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, szShadow.cx);
  525. j++)
  526. *(pLine + j) = 0;
  527. for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]);
  528. j < ptAnchors[i][1];
  529. j++)
  530. *(pLine + j) = clCenter;
  531. }
  532. }
  533. // Delete used resources
  534. delete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);
  535. delete[] ptAnchorsTmp;
  536. delete[] ptAnchorsOri;
  537. delete[] pKernel;
  538. DeleteObject(hParentRgn);
  539. }
  540. bool CWndShadow::SetImage(LPCTSTR image, RECT rcCorner, RECT rcHoleOffset)
  541. {
  542. TImageInfo* pImageInfo = CRenderEngine::LoadImage(image);
  543. if (pImageInfo == NULL) return false;
  544. if (m_pImageInfo) CRenderEngine::FreeImage(m_pImageInfo);
  545. m_pImageInfo = pImageInfo;
  546. m_rcCorner = rcCorner;
  547. m_rcHoleOffset = rcHoleOffset;
  548. if(SS_VISABLE & m_Status)
  549. Update(GetParent(m_hWnd));
  550. return true;
  551. }
  552. bool CWndShadow::SetSize(int NewSize)
  553. {
  554. //if(NewSize > 20 || NewSize < -20)
  555. // return false;
  556. m_nSize = (signed char)NewSize;
  557. if(SS_VISABLE & m_Status)
  558. Update(GetParent(m_hWnd));
  559. return true;
  560. }
  561. bool CWndShadow::SetSharpness(unsigned int NewSharpness)
  562. {
  563. if(NewSharpness > 20)
  564. return false;
  565. m_nSharpness = (unsigned char)NewSharpness;
  566. if(SS_VISABLE & m_Status)
  567. Update(GetParent(m_hWnd));
  568. return true;
  569. }
  570. bool CWndShadow::SetDarkness(unsigned int NewDarkness)
  571. {
  572. if(NewDarkness > 255)
  573. return false;
  574. m_nDarkness = (unsigned char)NewDarkness;
  575. if(SS_VISABLE & m_Status)
  576. Update(GetParent(m_hWnd));
  577. return true;
  578. }
  579. bool CWndShadow::SetPosition(int NewXOffset, int NewYOffset)
  580. {
  581. if(NewXOffset > 20 || NewXOffset < -20 ||
  582. NewYOffset > 20 || NewYOffset < -20)
  583. return false;
  584. m_nxOffset = (signed char)NewXOffset;
  585. m_nyOffset = (signed char)NewYOffset;
  586. if(SS_VISABLE & m_Status)
  587. Update(GetParent(m_hWnd));
  588. return true;
  589. }
  590. bool CWndShadow::SetColor(COLORREF NewColor)
  591. {
  592. m_Color = NewColor;
  593. if(SS_VISABLE & m_Status)
  594. Update(GetParent(m_hWnd));
  595. return true;
  596. }