UIShadow.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  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. //
  318. // [2026-09-24] In layered anti-aliased rounded-corner mode the window deliberately has
  319. // NO window region: CPaintManagerUI::GetRoundCorner() returns {0,0} so that every
  320. // window's OnSize skips CreateRoundRectRgn/SetWindowRgn (a 1-bit HRGN would re-cut the
  321. // smooth anti-aliased corner produced by the alpha mask). Consequence: GetWindowRgn
  322. // below cannot read the real shape, hParentRgn keeps the plain full rectangle, so the
  323. // shadow's inner silhouette degrades into a right angle. In the four corners of a
  324. // rounded window the background then shows through inside a SQUARE shadow frame
  325. // (looks like a "white corner").
  326. // Fix: when no valid region is available, synthesise a rounded region from the window's
  327. // configured corner radius. radius == 0 keeps the old rectangle behaviour, and windows
  328. // that DO have a region (GetWindowRgn returns SIMPLEREGION/COMPLEXREGION) are untouched.
  329. const int nParentW = abs(rcParent->right - rcParent->left);
  330. const int nParentH = abs(rcParent->bottom - rcParent->top);
  331. HRGN hParentRgn = CreateRectRgn(0, 0, nParentW, nParentH);
  332. const int nRgnType = ::GetWindowRgn(hParent, hParentRgn);
  333. if (nRgnType == ERROR || nRgnType == NULLREGION)
  334. {
  335. SIZE szRgnCorner = { 0, 0 };
  336. if (m_pManager != NULL) szRgnCorner = m_pManager->GetRoundCornerForShadow();
  337. if (szRgnCorner.cx > 0 && szRgnCorner.cy > 0
  338. && szRgnCorner.cx * 2 < nParentW && szRgnCorner.cy * 2 < nParentH)
  339. {
  340. ::DeleteObject(hParentRgn);
  341. // [2026-09-24] R17: CreateRoundRectRgn takes 2x radius.
  342. // CreateRoundRectRgn's nWidthEllipse/nHeightEllipse is the FULL width/height of
  343. // the corner ellipse (radius = value / 2), while GetRoundCornerForShadow() returns
  344. // the RADIUS (same unit as CPaintManagerUI::FillRoundRectAlphaMask, which uses the
  345. // value directly as a radius). Feeding the radius here produced a shadow silhouette
  346. // with only HALF the window's corner radius: the dark band cut across at a smaller
  347. // arc and left a sliver of unshadowed background glued to the real arc (a "white
  348. // edge" on light backgrounds, a stray shadow blob on dark ones).
  349. hParentRgn = ::CreateRoundRectRgn(0, 0, nParentW + 1, nParentH + 1,
  350. szRgnCorner.cx * 2, szRgnCorner.cy * 2);
  351. }
  352. }
  353. // Determine the Start and end point of each horizontal scan line
  354. SIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};
  355. SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};
  356. // Extra 2 lines (set to be empty) in ptAnchors are used in dilation
  357. int nAnchors = max(szParent.cy, szShadow.cy); // # of anchor points pares
  358. int (*ptAnchors)[2] = new int[nAnchors + 2][2];
  359. int (*ptAnchorsOri)[2] = new int[szParent.cy][2]; // anchor points, will not modify during erosion
  360. ptAnchors[0][0] = szParent.cx;
  361. ptAnchors[0][1] = 0;
  362. ptAnchors[nAnchors + 1][0] = szParent.cx;
  363. ptAnchors[nAnchors + 1][1] = 0;
  364. if(m_nSize > 0) {
  365. // Put the parent window anchors at the center
  366. for(int i = 0; i < m_nSize; i++) {
  367. ptAnchors[i + 1][0] = szParent.cx;
  368. ptAnchors[i + 1][1] = 0;
  369. ptAnchors[szShadow.cy - i][0] = szParent.cx;
  370. ptAnchors[szShadow.cy - i][1] = 0;
  371. }
  372. ptAnchors += m_nSize;
  373. }
  374. for(int i = 0; i < szParent.cy; i++) {
  375. // find start point
  376. int j;
  377. for(j = 0; j < szParent.cx; j++) {
  378. if(PtInRegion(hParentRgn, j, i)) {
  379. ptAnchors[i + 1][0] = j + m_nSize;
  380. ptAnchorsOri[i][0] = j;
  381. break;
  382. }
  383. }
  384. // Start point not found
  385. if(j >= szParent.cx) {
  386. ptAnchors[i + 1][0] = szParent.cx;
  387. ptAnchorsOri[i][1] = 0;
  388. ptAnchors[i + 1][0] = szParent.cx;
  389. ptAnchorsOri[i][1] = 0;
  390. }
  391. else {
  392. // find end point
  393. for(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--) {
  394. if(PtInRegion(hParentRgn, j, i)) {
  395. ptAnchors[i + 1][1] = j + 1 + m_nSize;
  396. ptAnchorsOri[i][1] = j + 1;
  397. break;
  398. }
  399. }
  400. }
  401. }
  402. if(m_nSize > 0)
  403. ptAnchors -= m_nSize; // Restore pos of ptAnchors for erosion
  404. int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2]; // Store the result of erosion
  405. // First and last line should be empty
  406. ptAnchorsTmp[0][0] = szParent.cx;
  407. ptAnchorsTmp[0][1] = 0;
  408. ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;
  409. ptAnchorsTmp[nAnchors + 1][1] = 0;
  410. int nEroTimes = 0;
  411. // morphologic erosion
  412. for(int i = 0; i < m_nSharpness - m_nSize; i++) {
  413. nEroTimes++;
  414. //ptAnchorsTmp[1][0] = szParent.cx;
  415. //ptAnchorsTmp[1][1] = 0;
  416. //ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;
  417. //ptAnchorsTmp[szParent.cy + 1][1] = 0;
  418. for(int j = 1; j < nAnchors + 1; j++) {
  419. ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;
  420. ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;
  421. }
  422. // Exchange ptAnchors and ptAnchorsTmp;
  423. int (*ptAnchorsXange)[2] = ptAnchorsTmp;
  424. ptAnchorsTmp = ptAnchors;
  425. ptAnchors = ptAnchorsXange;
  426. }
  427. // morphologic dilation
  428. ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1; // now coordinates in ptAnchors are same as in shadow window
  429. // Generate the kernel
  430. int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;
  431. int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;
  432. UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];
  433. UINT32 *pKernelIter = pKernel;
  434. for(int i = 0; i <= 2 * nKernelSize; i++) {
  435. for(int j = 0; j <= 2 * nKernelSize; j++) {
  436. double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));
  437. if(dLength < nCenterSize)
  438. *pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  439. else if(dLength <= nKernelSize) {
  440. UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));
  441. *pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);
  442. }
  443. else
  444. *pKernelIter = 0;
  445. //TRACE("%d ", *pKernelIter >> 24);
  446. pKernelIter ++;
  447. }
  448. //TRACE("\n");
  449. }
  450. // Generate blurred border
  451. for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)
  452. {
  453. int j;
  454. if(ptAnchors[i][0] < ptAnchors[i][1])
  455. {
  456. // Start of line
  457. for(j = ptAnchors[i][0]; j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]); j++)
  458. {
  459. for(int k = 0; k <= 2 * nKernelSize; k++)
  460. {
  461. UINT32 *pPixel = pShadBits +
  462. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  463. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  464. for(int l = 0; l <= 2 * nKernelSize; l++)
  465. {
  466. if(*pPixel < *pKernelPixel)
  467. *pPixel = *pKernelPixel;
  468. pPixel++;
  469. pKernelPixel++;
  470. }
  471. }
  472. } // for() start of line
  473. // End of line
  474. for(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1); j < ptAnchors[i][1]; j++)
  475. {
  476. for(int k = 0; k <= 2 * nKernelSize; k++)
  477. {
  478. UINT32 *pPixel = pShadBits +
  479. (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
  480. UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
  481. for(int l = 0; l <= 2 * nKernelSize; l++)
  482. {
  483. if(*pPixel < *pKernelPixel)
  484. *pPixel = *pKernelPixel;
  485. pPixel++;
  486. pKernelPixel++;
  487. }
  488. }
  489. } // for() end of line
  490. }
  491. } // for() Generate blurred border
  492. // Erase unwanted parts and complement missing
  493. UINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
  494. 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++) {
  495. UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;
  496. // Line is not covered by parent window
  497. if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy) {
  498. for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++) {
  499. *(pLine + j) = clCenter;
  500. }
  501. }
  502. else {
  503. for(int j = ptAnchors[i][0]; j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]); j++)
  504. *(pLine + j) = clCenter;
  505. 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++)
  506. *(pLine + j) = 0;
  507. for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]); j < ptAnchors[i][1]; j++)
  508. *(pLine + j) = clCenter;
  509. }
  510. }
  511. // Delete used resources
  512. delete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);
  513. delete[] ptAnchorsTmp;
  514. delete[] ptAnchorsOri;
  515. delete[] pKernel;
  516. DeleteObject(hParentRgn);
  517. }
  518. void CShadowUI::ShowShadow(bool bShow)
  519. {
  520. m_bIsShowShadow = bShow;
  521. }
  522. bool CShadowUI::IsShowShadow() const
  523. {
  524. return m_bIsShowShadow;
  525. }
  526. void CShadowUI::DisableShadow(bool bDisable)
  527. {
  528. m_bIsDisableShadow = bDisable;
  529. if (m_hWnd != NULL) {
  530. if (m_bIsDisableShadow) {
  531. ::ShowWindow(m_hWnd, SW_HIDE);
  532. }
  533. else {
  534. // Determine the initial show state of shadow according to parent window's state
  535. LONG lParentStyle = GetWindowLongPtr(GetParent(m_hWnd), GWL_STYLE);
  536. if (!(WS_VISIBLE & lParentStyle)) // Parent invisible
  537. m_Status = SS_ENABLED;
  538. else if ((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
  539. m_Status = SS_ENABLED | SS_PARENTVISIBLE;
  540. else {
  541. m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
  542. }
  543. if ((WS_VISIBLE & lParentStyle) && !((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle)) {
  544. ::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
  545. Update(GetParent(m_hWnd));
  546. }
  547. }
  548. }
  549. }
  550. ////TODO shadow disnable fix////
  551. bool CShadowUI::IsDisableShadow() const
  552. {
  553. return m_bIsDisableShadow;
  554. }
  555. bool CShadowUI::SetSize(int NewSize)
  556. {
  557. if(NewSize > 35 || NewSize < -35)
  558. return false;
  559. m_nSize = (signed char)NewSize;
  560. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  561. Update(GetParent(m_hWnd));
  562. return true;
  563. }
  564. bool CShadowUI::SetSharpness(unsigned int NewSharpness)
  565. {
  566. if(NewSharpness > 35)
  567. return false;
  568. m_nSharpness = (unsigned char)NewSharpness;
  569. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  570. Update(GetParent(m_hWnd));
  571. return true;
  572. }
  573. bool CShadowUI::SetDarkness(unsigned int NewDarkness)
  574. {
  575. if(NewDarkness > 255)
  576. return false;
  577. m_nDarkness = (unsigned char)NewDarkness;
  578. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  579. Update(GetParent(m_hWnd));
  580. return true;
  581. }
  582. bool CShadowUI::SetPosition(int NewXOffset, int NewYOffset)
  583. {
  584. if(NewXOffset > 35 || NewXOffset < -35 ||
  585. NewYOffset > 35 || NewYOffset < -35)
  586. return false;
  587. m_nxOffset = (signed char)NewXOffset;
  588. m_nyOffset = (signed char)NewYOffset;
  589. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  590. Update(GetParent(m_hWnd));
  591. return true;
  592. }
  593. bool CShadowUI::SetColor(COLORREF NewColor)
  594. {
  595. m_Color = NewColor;
  596. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  597. Update(GetParent(m_hWnd));
  598. return true;
  599. }
  600. bool CShadowUI::SetImage(LPCTSTR szImage)
  601. {
  602. if (szImage == NULL)
  603. return false;
  604. m_bIsImageMode = true;
  605. m_sShadowImage = szImage;
  606. if(m_hWnd != NULL && (SS_VISABLE & m_Status))
  607. Update(GetParent(m_hWnd));
  608. return true;
  609. }
  610. bool CShadowUI::SetShadowCorner(RECT rcCorner)
  611. {
  612. if (rcCorner.left < 0 || rcCorner.top < 0 || rcCorner.right < 0 || rcCorner.bottom < 0) return false;
  613. m_rcShadowCorner = rcCorner;
  614. if(m_hWnd != NULL && (SS_VISABLE & m_Status)) {
  615. Update(GetParent(m_hWnd));
  616. }
  617. return true;
  618. }
  619. bool CShadowUI::CopyShadow(CShadowUI* pShadow)
  620. {
  621. if (m_bIsImageMode) {
  622. pShadow->SetImage(m_sShadowImage);
  623. pShadow->SetShadowCorner(m_rcShadowCorner);
  624. pShadow->SetSize((int)m_nSize);
  625. }
  626. else {
  627. pShadow->SetSize((int)m_nSize);
  628. pShadow->SetSharpness((unsigned int)m_nSharpness);
  629. pShadow->SetDarkness((unsigned int)m_nDarkness);
  630. pShadow->SetColor(m_Color);
  631. pShadow->SetPosition((int)m_nxOffset, (int)m_nyOffset);
  632. }
  633. pShadow->ShowShadow(m_bIsShowShadow);
  634. return true;
  635. }
  636. } //namespace DuiLib