UIShadow.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. #include "StdAfx.h"
  2. #include "UIShadow.h"
  3. #include "math.h"
  4. #include "crtdbg.h"
  5. namespace DuiLib
  6. {
  7. const TCHAR *strWndClassName = _T("PerryShadowWnd");
  8. bool CShadowUI::s_bHasInit = FALSE;
  9. CShadowUI::CShadowUI(void)
  10. : m_hWnd((HWND)NULL)
  11. , m_OriParentProc(NULL)
  12. , m_Status(0)
  13. , m_nDarkness(150)
  14. , m_nSharpness(5)
  15. , m_nSize(0)
  16. , m_nxOffset(0)
  17. , m_nyOffset(0)
  18. , m_Color(RGB(0, 0, 0))
  19. , m_WndSize(0)
  20. , m_bUpdate(false)
  21. , m_bIsImageMode(false)
  22. , m_bIsShowShadow(false)
  23. , m_bIsDisableShadow(false)
  24. {
  25. ::ZeroMemory(&m_rcShadowCorner, sizeof(RECT));
  26. }
  27. CShadowUI::~CShadowUI(void)
  28. {
  29. }
  30. bool CShadowUI::Initialize(HINSTANCE hInstance)
  31. {
  32. if (s_bHasInit)
  33. return false;
  34. // Register window class for shadow window
  35. WNDCLASSEX wcex;
  36. memset(&wcex, 0, sizeof(wcex));
  37. wcex.cbSize = sizeof(WNDCLASSEX);
  38. wcex.style = CS_HREDRAW | CS_VREDRAW;
  39. wcex.lpfnWndProc = DefWindowProc;
  40. wcex.cbClsExtra = 0;
  41. wcex.cbWndExtra = 0;
  42. wcex.hInstance = hInstance;
  43. wcex.hIcon = NULL;
  44. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  45. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  46. wcex.lpszMenuName = NULL;
  47. wcex.lpszClassName = strWndClassName;
  48. wcex.hIconSm = NULL;
  49. RegisterClassEx(&wcex);
  50. s_bHasInit = true;
  51. return true;
  52. }
  53. void CShadowUI::Create(CPaintManagerUI* pPaintManager)
  54. {
  55. if(!m_bIsShowShadow)
  56. return;
  57. // Already initialized
  58. _ASSERT(CPaintManagerUI::GetInstance() != INVALID_HANDLE_VALUE);
  59. _ASSERT(pPaintManager != NULL);
  60. m_pManager = pPaintManager;
  61. HWND hParentWnd = m_pManager->GetPaintWindow();
  62. // Add parent window - shadow pair to the map
  63. _ASSERT(GetShadowMap().find(hParentWnd) == GetShadowMap().end()); // Only one shadow for each window
  64. GetShadowMap()[hParentWnd] = this;
  65. // Determine the initial show state of shadow according to parent window's state
  66. LONG lParentStyle = GetWindowLongPtr(hParentWnd, GWL_STYLE);
  67. // Create the shadow window
  68. LONG styleValue = lParentStyle & WS_CAPTION;
  69. m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,
  70. /*WS_VISIBLE | */styleValue | WS_POPUPWINDOW,
  71. CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, CPaintManagerUI::GetInstance(), NULL);
  72. if(!(WS_VISIBLE & lParentStyle)) // Parent invisible
  73. m_Status = SS_ENABLED;
  74. else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
  75. m_Status = SS_ENABLED | SS_PARENTVISIBLE;
  76. else // Show the shadow
  77. {
  78. m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
  79. ::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
  80. Update(hParentWnd);
  81. }
  82. // Replace the original WndProc of parent window to steal messages
  83. m_OriParentProc = GetWindowLongPtr(hParentWnd, GWLP_WNDPROC);
  84. #pragma warning(disable: 4311) // temporrarily disable the type_cast warning in Win32
  85. SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)ParentProc);
  86. #pragma warning(default: 4311)
  87. }
  88. std::map<HWND, CShadowUI *>& CShadowUI::GetShadowMap()
  89. {
  90. static std::map<HWND, CShadowUI *> s_Shadowmap;
  91. return s_Shadowmap;
  92. }
  93. LRESULT CALLBACK CShadowUI::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  94. {
  95. _ASSERT(GetShadowMap().find(hwnd) != GetShadowMap().end()); // Shadow must have been attached
  96. CShadowUI *pThis = GetShadowMap()[hwnd];
  97. if (pThis->IsDisableShadow()) {
  98. return CallWindowProc((WNDPROC)pThis->m_OriParentProc, hwnd, uMsg, wParam, lParam);
  99. }
  100. switch(uMsg)
  101. {
  102. case WM_ACTIVATEAPP:
  103. {
  104. if(!IsWindowEnabled(hwnd)) break;
  105. ::SetWindowPos(pThis->m_hWnd, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
  106. break;
  107. }
  108. case WM_NCACTIVATE:
  109. {
  110. if(!IsWindowEnabled(hwnd)) break;
  111. ::SetWindowPos(pThis->m_hWnd, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
  112. break;
  113. }
  114. case WM_WINDOWPOSCHANGED:
  115. {
  116. RECT WndRect;
  117. LPWINDOWPOS pWndPos;
  118. pWndPos = (LPWINDOWPOS)lParam;
  119. GetWindowRect(hwnd, &WndRect);
  120. if (pThis->m_bIsImageMode) {
  121. SetWindowPos(pThis->m_hWnd, hwnd, WndRect.left - pThis->m_nSize, WndRect.top - pThis->m_nSize, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  122. }
  123. else {
  124. SetWindowPos(pThis->m_hWnd, hwnd, WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  125. }
  126. if (pWndPos->flags & SWP_SHOWWINDOW) {
  127. if (pThis->m_Status & SS_ENABLED && !(pThis->m_Status & SS_PARENTVISIBLE))
  128. {
  129. pThis->m_bUpdate = true;
  130. ::ShowWindow(pThis->m_hWnd, SW_SHOWNOACTIVATE);
  131. pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;
  132. }
  133. }
  134. else if (pWndPos->flags & SWP_HIDEWINDOW) {
  135. if (pThis->m_Status & SS_ENABLED)
  136. {
  137. ::ShowWindow(pThis->m_hWnd, SW_HIDE);
  138. pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);
  139. }
  140. }
  141. break;
  142. }
  143. case WM_MOVE:
  144. if(pThis->m_Status & SS_VISABLE) {
  145. RECT WndRect;
  146. GetWindowRect(hwnd, &WndRect);
  147. if (pThis->m_bIsImageMode) {
  148. SetWindowPos(pThis->m_hWnd, hwnd, WndRect.left - pThis->m_nSize, WndRect.top - pThis->m_nSize, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  149. }
  150. else {
  151. SetWindowPos(pThis->m_hWnd, hwnd, WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  152. }
  153. }
  154. break;
  155. case WM_SIZE:
  156. if(pThis->m_Status & SS_ENABLED) {
  157. if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam) {
  158. ::ShowWindow(pThis->m_hWnd, SW_HIDE);
  159. pThis->m_Status &= ~SS_VISABLE;
  160. }
  161. // Parent maybe resized even if invisible
  162. else if(pThis->m_Status & SS_PARENTVISIBLE) {
  163. // Awful! It seems that if the window size was not decreased
  164. // the window region would never be updated until WM_PAINT was sent.
  165. // So do not Update() until next WM_PAINT is received in this case
  166. if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))
  167. pThis->m_bUpdate = true;
  168. else
  169. pThis->Update(hwnd);
  170. if(!(pThis->m_Status & SS_VISABLE)) {
  171. ::ShowWindow(pThis->m_hWnd, SW_SHOWNOACTIVATE);
  172. pThis->m_Status |= SS_VISABLE;
  173. }
  174. }
  175. pThis->m_WndSize = lParam;
  176. }
  177. break;
  178. case WM_PAINT:
  179. {
  180. if(pThis->m_bUpdate) {
  181. pThis->Update(hwnd);
  182. pThis->m_bUpdate = false;
  183. }
  184. break;
  185. }
  186. // In some cases of sizing, the up-right corner of the parent window region would not be properly updated
  187. // Update() again when sizing is finished
  188. case WM_EXITSIZEMOVE:
  189. if(pThis->m_Status & SS_VISABLE) {
  190. pThis->Update(hwnd);
  191. }
  192. break;
  193. case WM_SHOWWINDOW:
  194. if(pThis->m_Status & SS_ENABLED) {
  195. // the window is being hidden
  196. if(!wParam) {
  197. ::ShowWindow(pThis->m_hWnd, SW_HIDE);
  198. pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);
  199. }
  200. else if(!(pThis->m_Status & SS_PARENTVISIBLE)) {
  201. //pThis->Update(hwnd);
  202. pThis->m_bUpdate = true;
  203. ::ShowWindow(pThis->m_hWnd, SW_SHOWNOACTIVATE);
  204. pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;
  205. }
  206. }
  207. break;
  208. case WM_DESTROY:
  209. DestroyWindow(pThis->m_hWnd); // Destroy the shadow
  210. break;
  211. case WM_NCDESTROY:
  212. GetShadowMap().erase(hwnd); // Remove this window and shadow from the map
  213. break;
  214. }
  215. return CallWindowProc((WNDPROC)pThis->m_OriParentProc, hwnd, uMsg, wParam, lParam);
  216. }
  217. //Formats GetLastError() value.
  218. void GetLastErrorMessage()
  219. {
  220. LPVOID lpMsgBuf;
  221. FormatMessage(
  222. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  223. NULL, GetLastError(),
  224. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  225. (LPTSTR)&lpMsgBuf, 0, NULL
  226. );
  227. // Display the string.
  228. //MessageBox(NULL, (const wchar_t*)lpMsgBuf, L"GetLastError", MB_OK | MB_ICONINFORMATION);
  229. // Free the buffer.
  230. LocalFree(lpMsgBuf);
  231. }
  232. void CShadowUI::Update(HWND hParent)
  233. {
  234. if(!m_bIsShowShadow || !(m_Status & SS_VISABLE)) return;
  235. RECT WndRect;
  236. GetWindowRect(hParent, &WndRect);
  237. int nShadWndWid;
  238. int nShadWndHei;
  239. if (m_bIsImageMode) {
  240. if(m_sShadowImage.IsEmpty()) return;
  241. nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;
  242. nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;
  243. }
  244. else {
  245. if (m_nSize == 0) return;
  246. nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;
  247. nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;
  248. }
  249. // Create the alpha blending bitmap
  250. BITMAPINFO bmi; // bitmap header
  251. ZeroMemory(&bmi, sizeof(BITMAPINFO));
  252. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  253. bmi.bmiHeader.biWidth = nShadWndWid;
  254. bmi.bmiHeader.biHeight = nShadWndHei;
  255. bmi.bmiHeader.biPlanes = 1;
  256. bmi.bmiHeader.biBitCount = 32; // four 8-bit components
  257. bmi.bmiHeader.biCompression = BI_RGB;
  258. bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;
  259. BYTE *pvBits; // pointer to DIB section
  260. HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);
  261. if (hbitmap == NULL) {
  262. GetLastErrorMessage();
  263. }
  264. HDC hMemDC = CreateCompatibleDC(NULL);
  265. if (hMemDC == NULL) {
  266. GetLastErrorMessage();
  267. }
  268. HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
  269. if (GetLastError()!=0) {
  270. GetLastErrorMessage();
  271. }
  272. if (m_bIsImageMode) {
  273. RECT rcPaint = {0, 0, nShadWndWid, nShadWndHei};
  274. const TDrawInfo* pDrawInfo = m_pManager->GetDrawInfo(m_sShadowImage, _T(""));
  275. if(pDrawInfo != NULL) {
  276. const TImageInfo* data = m_pManager->GetImageEx(pDrawInfo->sImageName, pDrawInfo->sResType, pDrawInfo->dwMask, pDrawInfo->bHSL, pDrawInfo->bGdiplus);
  277. if( !data ) return;
  278. RECT rcBmpPart = {0};
  279. rcBmpPart.right = data->nX;
  280. rcBmpPart.bottom = data->nY;
  281. RECT corner = m_rcShadowCorner;
  282. CRenderEngine::DrawImage(hMemDC, data->hBitmap, rcPaint, rcPaint, rcBmpPart, corner, data->bAlpha, 0xFF, true, false, false);
  283. }
  284. }
  285. else {
  286. ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);
  287. MakeShadow((UINT32 *)pvBits, hParent, &WndRect);
  288. }
  289. POINT ptDst;
  290. if (m_bIsImageMode) {
  291. ptDst.x = WndRect.left - m_nSize;
  292. ptDst.y = WndRect.top - m_nSize;
  293. }
  294. else {
  295. ptDst.x = WndRect.left + m_nxOffset - m_nSize;
  296. ptDst.y = WndRect.top + m_nyOffset - m_nSize;
  297. }
  298. POINT ptSrc = {0, 0};
  299. SIZE WndSize = {nShadWndWid, nShadWndHei};
  300. BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  301. MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);
  302. BOOL bRet= ::UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC, &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);
  303. _ASSERT(bRet); // something was wrong....
  304. // Delete used resources
  305. SelectObject(hMemDC, hOriBmp);
  306. DeleteObject(hbitmap);
  307. DeleteDC(hMemDC);
  308. }
  309. void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
  310. {
  311. // The shadow algorithm:
  312. // Get the region of parent window,
  313. // Apply morphologic erosion to shrink it into the size (ShadowWndSize - Sharpness)
  314. // Apply modified (with blur effect) morphologic dilation to make the blurred border
  315. // The algorithm is optimized by assuming parent window is just "one piece" and without "wholes" on it
  316. // Get the region of parent window,
  317. HRGN hParentRgn = CreateRectRgn(0, 0, abs(rcParent->right - rcParent->left), abs(rcParent->bottom - rcParent->top));
  318. GetWindowRgn(hParent, hParentRgn);
  319. // Determine the Start and end point of each horizontal scan line
  320. SIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};
  321. SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};
  322. // Extra 2 lines (set to be empty) in ptAnchors are used in dilation
  323. int nAnchors = max(szParent.cy, szShadow.cy); // # of anchor points pares
  324. int (*ptAnchors)[2] = new int[nAnchors + 2][2];
  325. int (*ptAnchorsOri)[2] = new int[szParent.cy][2]; // anchor points, will not modify during erosion
  326. ptAnchors[0][0] = szParent.cx;
  327. ptAnchors[0][1] = 0;
  328. ptAnchors[nAnchors + 1][0] = szParent.cx;
  329. ptAnchors[nAnchors + 1][1] = 0;
  330. if(m_nSize > 0) {
  331. // Put the parent window anchors at the center
  332. for(int i = 0; i < m_nSize; i++) {
  333. ptAnchors[i + 1][0] = szParent.cx;
  334. ptAnchors[i + 1][1] = 0;
  335. ptAnchors[szShadow.cy - i][0] = szParent.cx;
  336. ptAnchors[szShadow.cy - i][1] = 0;
  337. }
  338. ptAnchors += m_nSize;
  339. }
  340. for(int i = 0; i < szParent.cy; i++) {
  341. // find start point
  342. int j;
  343. for(j = 0; j < szParent.cx; j++) {
  344. if(PtInRegion(hParentRgn, j, i)) {
  345. ptAnchors[i + 1][0] = j + m_nSize;
  346. ptAnchorsOri[i][0] = j;
  347. break;
  348. }
  349. }
  350. // Start point not found
  351. if(j >= szParent.cx) {
  352. ptAnchors[i + 1][0] = szParent.cx;
  353. ptAnchorsOri[i][1] = 0;
  354. ptAnchors[i + 1][0] = szParent.cx;
  355. ptAnchorsOri[i][1] = 0;
  356. }
  357. else {
  358. // find end point
  359. for(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--) {
  360. if(PtInRegion(hParentRgn, j, i)) {
  361. ptAnchors[i + 1][1] = j + 1 + m_nSize;
  362. ptAnchorsOri[i][1] = j + 1;
  363. break;
  364. }
  365. }
  366. }
  367. }
  368. if(m_nSize > 0)
  369. ptAnchors -= m_nSize; // Restore pos of ptAnchors for erosion
  370. int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2]; // Store the result of erosion
  371. // First and last line should be empty
  372. ptAnchorsTmp[0][0] = szParent.cx;
  373. ptAnchorsTmp[0][1] = 0;
  374. ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;
  375. ptAnchorsTmp[nAnchors + 1][1] = 0;
  376. int nEroTimes = 0;
  377. // morphologic erosion
  378. for(int i = 0; i < m_nSharpness - m_nSize; i++) {
  379. nEroTimes++;
  380. //ptAnchorsTmp[1][0] = szParent.cx;
  381. //ptAnchorsTmp[1][1] = 0;
  382. //ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;
  383. //ptAnchorsTmp[szParent.cy + 1][1] = 0;
  384. for(int j = 1; j < nAnchors + 1; j++) {
  385. ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;
  386. ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;
  387. }
  388. // Exchange ptAnchors and ptAnchorsTmp;
  389. int (*ptAnchorsXange)[2] = ptAnchorsTmp;
  390. ptAnchorsTmp = ptAnchors;
  391. ptAnchors = ptAnchorsXange;
  392. }
  393. // morphologic dilation
  394. ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1; // now coordinates in ptAnchors are same as in shadow window
  395. // Generate the kernel
  396. int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;
  397. int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;
  398. UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];
  399. UINT32 *pKernelIter = pKernel;
  400. for(int i = 0; i <= 2 * nKernelSize; i++) {
  401. for(int j = 0; j <= 2 * nKernelSize; j++) {
  402. double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));
  403. if(dLength < nCenterSize)
  404. *pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  405. else if(dLength <= nKernelSize) {
  406. UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));
  407. *pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);
  408. }
  409. else
  410. *pKernelIter = 0;
  411. //TRACE("%d ", *pKernelIter >> 24);
  412. pKernelIter ++;
  413. }
  414. //TRACE("\n");
  415. }
  416. // Generate blurred border
  417. for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)
  418. {
  419. int j;
  420. if(ptAnchors[i][0] < ptAnchors[i][1])
  421. {
  422. // Start of line
  423. for(j = ptAnchors[i][0]; j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]); j++)
  424. {
  425. for(int k = 0; k <= 2 * nKernelSize; k++)
  426. {
  427. UINT32 *pPixel = pShadBits +
  428. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  429. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  430. for(int l = 0; l <= 2 * nKernelSize; l++)
  431. {
  432. if(*pPixel < *pKernelPixel)
  433. *pPixel = *pKernelPixel;
  434. pPixel++;
  435. pKernelPixel++;
  436. }
  437. }
  438. } // for() start of line
  439. // End of line
  440. for(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1); j < ptAnchors[i][1]; j++)
  441. {
  442. for(int k = 0; k <= 2 * nKernelSize; k++)
  443. {
  444. UINT32 *pPixel = pShadBits +
  445. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  446. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  447. for(int l = 0; l <= 2 * nKernelSize; l++)
  448. {
  449. if(*pPixel < *pKernelPixel)
  450. *pPixel = *pKernelPixel;
  451. pPixel++;
  452. pKernelPixel++;
  453. }
  454. }
  455. } // for() end of line
  456. }
  457. } // for() Generate blurred border
  458. // Erase unwanted parts and complement missing
  459. UINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  460. for(int i = min(nKernelSize, max(m_nSize - m_nyOffset, 0)); i < max(szShadow.cy - nKernelSize, min(szParent.cy + m_nSize - m_nyOffset, szParent.cy + 2 * m_nSize)); i++) {
  461. UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;
  462. // Line is not covered by parent window
  463. if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy) {
  464. for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++) {
  465. *(pLine + j) = clCenter;
  466. }
  467. }
  468. else {
  469. for(int j = ptAnchors[i][0]; j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]); j++)
  470. *(pLine + j) = clCenter;
  471. for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, 0); j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, szShadow.cx); j++)
  472. *(pLine + j) = 0;
  473. for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]); j < ptAnchors[i][1]; j++)
  474. *(pLine + j) = clCenter;
  475. }
  476. }
  477. // Delete used resources
  478. delete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);
  479. delete[] ptAnchorsTmp;
  480. delete[] ptAnchorsOri;
  481. delete[] pKernel;
  482. DeleteObject(hParentRgn);
  483. }
  484. void CShadowUI::ShowShadow(bool bShow)
  485. {
  486. m_bIsShowShadow = bShow;
  487. }
  488. bool CShadowUI::IsShowShadow() const
  489. {
  490. return m_bIsShowShadow;
  491. }
  492. void CShadowUI::DisableShadow(bool bDisable)
  493. {
  494. m_bIsDisableShadow = bDisable;
  495. if (m_hWnd != NULL) {
  496. if (m_bIsDisableShadow) {
  497. ::ShowWindow(m_hWnd, SW_HIDE);
  498. }
  499. else {
  500. // Determine the initial show state of shadow according to parent window's state
  501. LONG lParentStyle = GetWindowLongPtr(GetParent(m_hWnd), GWL_STYLE);
  502. if (!(WS_VISIBLE & lParentStyle)) // Parent invisible
  503. m_Status = SS_ENABLED;
  504. else if ((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
  505. m_Status = SS_ENABLED | SS_PARENTVISIBLE;
  506. else {
  507. m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
  508. }
  509. if ((WS_VISIBLE & lParentStyle) && !((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle)) {
  510. ::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
  511. Update(GetParent(m_hWnd));
  512. }
  513. }
  514. }
  515. }
  516. ////TODO shadow disnable fix////
  517. bool CShadowUI::IsDisableShadow() const
  518. {
  519. return m_bIsDisableShadow;
  520. }
  521. bool CShadowUI::SetSize(int NewSize)
  522. {
  523. if(NewSize > 35 || NewSize < -35)
  524. return false;
  525. m_nSize = (signed char)NewSize;
  526. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  527. Update(GetParent(m_hWnd));
  528. return true;
  529. }
  530. bool CShadowUI::SetSharpness(unsigned int NewSharpness)
  531. {
  532. if(NewSharpness > 35)
  533. return false;
  534. m_nSharpness = (unsigned char)NewSharpness;
  535. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  536. Update(GetParent(m_hWnd));
  537. return true;
  538. }
  539. bool CShadowUI::SetDarkness(unsigned int NewDarkness)
  540. {
  541. if(NewDarkness > 255)
  542. return false;
  543. m_nDarkness = (unsigned char)NewDarkness;
  544. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  545. Update(GetParent(m_hWnd));
  546. return true;
  547. }
  548. bool CShadowUI::SetPosition(int NewXOffset, int NewYOffset)
  549. {
  550. if(NewXOffset > 35 || NewXOffset < -35 ||
  551. NewYOffset > 35 || NewYOffset < -35)
  552. return false;
  553. m_nxOffset = (signed char)NewXOffset;
  554. m_nyOffset = (signed char)NewYOffset;
  555. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  556. Update(GetParent(m_hWnd));
  557. return true;
  558. }
  559. bool CShadowUI::SetColor(COLORREF NewColor)
  560. {
  561. m_Color = NewColor;
  562. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  563. Update(GetParent(m_hWnd));
  564. return true;
  565. }
  566. bool CShadowUI::SetImage(LPCTSTR szImage)
  567. {
  568. if (szImage == NULL)
  569. return false;
  570. m_bIsImageMode = true;
  571. m_sShadowImage = szImage;
  572. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  573. Update(GetParent(m_hWnd));
  574. return true;
  575. }
  576. bool CShadowUI::SetShadowCorner(RECT rcCorner)
  577. {
  578. if (rcCorner.left < 0 || rcCorner.top < 0 || rcCorner.right < 0 || rcCorner.bottom < 0) return false;
  579. m_rcShadowCorner = rcCorner;
  580. if(m_hWnd != NULL && (SS_VISABLE & m_Status)) {
  581. Update(GetParent(m_hWnd));
  582. }
  583. return true;
  584. }
  585. bool CShadowUI::CopyShadow(CShadowUI* pShadow)
  586. {
  587. if (m_bIsImageMode) {
  588. pShadow->SetImage(m_sShadowImage);
  589. pShadow->SetShadowCorner(m_rcShadowCorner);
  590. pShadow->SetSize((int)m_nSize);
  591. }
  592. else {
  593. pShadow->SetSize((int)m_nSize);
  594. pShadow->SetSharpness((unsigned int)m_nSharpness);
  595. pShadow->SetDarkness((unsigned int)m_nDarkness);
  596. pShadow->SetColor(m_Color);
  597. pShadow->SetPosition((int)m_nxOffset, (int)m_nyOffset);
  598. }
  599. pShadow->ShowShadow(m_bIsShowShadow);
  600. return true;
  601. }
  602. } //namespace DuiLib