duilib支持了窗体阴影,有算法阴影和图片阴影两种,但是算法阴影的效果不尽人意,参数设置也不能理解
之前写过一篇关于阴影的
duilib窗体阴影偏移情况
纠正了图片的一些偏移情况,今天偶然看到css里设置box-shadow的阴影启示,何不把duilib也弄成了css里的?
所以开始了这篇文章,原理很简单,算法模式更换成先画小矩形的阴影,在模糊化,图片添加到CPaintManagerUI中,后面的事儿就和图片一样了。
效果如图:
参数的设置和css一样了,radius、spread、ofset、color
颜色支持透明度。
属性列表:
<Attribute name="showshadow" default="false" type="BOOL" comment="是否启用窗体阴影"/>
<Attribute name="shadowimage" default="" type="STRING" comment="阴影图片,使用此属性后自动屏蔽算法阴影(不支持source等属性设置)"/>
<Attribute name="shadowcorner" default="0,0,0,0" type="RECT" comment="图片阴影的九宫格描述"/>
<Attribute name="shadowradius" default="10" type="BYTE" comment="算法阴影的模糊半径(0到20)"/>
<Attribute name="shadowspread" default="0" type="BYTE" comment="算法阴影的扩展"/>
<Attribute name="shadowoffset" default="0,0" type="SIZE" comment="算法阴影的偏移量"/>
<Attribute name="shadowcolor" default="0x2f000000" type="DWORD" comment="算法阴影的颜色,ARGB支持透明度"/>
参数修改了当然要修改UIDlgBuilder,参数关键词修改如下,把带shadow的标签词替换成下面的。
else if( _tcsicmp(pstrName, _T("shadowradius")) == 0 ) {
pManager->GetShadow()->SetRadius(_ttoi(pstrValue));
}
else if( _tcsicmp(pstrName, _T("shadowspread")) == 0 ) {
pManager->GetShadow()->SetSpread(_ttoi(pstrValue));
}
else if( _tcsicmp(pstrName, _T("shadowoffset")) == 0 ) {
LPTSTR pstr = NULL;
int cx = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
int cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->GetShadow()->SetOffset(cx, cy);
}
else if( _tcsicmp(pstrName, _T("shadowcolor")) == 0 ) {
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
pManager->GetShadow()->SetColor(clrColor);
}
else if( _tcsicmp(pstrName, _T("shadowcorner")) == 0 ) {
RECT rcCorner = { 0 };
LPTSTR pstr = NULL;
rcCorner.left = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
rcCorner.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcCorner.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcCorner.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->GetShadow()->SetShadowCorner(rcCorner);
}
else if( _tcsicmp(pstrName, _T("shadowimage")) == 0 ) {
pManager->GetShadow()->SetImage(pstrValue);
}
else if( _tcsicmp(pstrName, _T("showshadow")) == 0 ) {
pManager->GetShadow()->ShowShadow(_tcsicmp(pstrValue, _T("true")) == 0);
}
UIShadow.h和UIShadow.cpp文件
//UIShadow.h
// WndShadow.h : header file
//
// Version 0.1
//
// Copyright (c) 2006 Perry Zhu, All Rights Reserved.
//
// mailto:perry@live.com
//
//
// This source file may be redistributed unmodified by any means PROVIDING
// it is NOT sold for profit without the authors expressed written
// consent, and providing that this notice and the author's name and all
// copyright notices remain intact. This software is by no means to be
// included as part of any third party components library, or as part any
// development solution that offers MFC extensions that are sold for profit.
//
// If the source code is used in any commercial applications then a statement
// along the lines of:
//
// "Portions Copyright (c) 2006 Perry Zhu" must be included in the "Startup
// Banner", "About Box" or "Printed Documentation". This software is provided
// "as is" without express or implied warranty. Use it at your own risk! The
// author accepts no liability for any damage/loss of business that this
// product may cause.
//
/////////////////////////////////////////////////////////////////////////////
//****************************************************************************
#ifndef __UISHADOW_H__
#define __UISHADOW_H__
#pragma once
#include "map"
namespace DuiLib
{
class UILIB_API CShadowUI
{
public:
friend class CPaintManagerUI;
CShadowUI(void);
virtual ~CShadowUI(void);
public:
// bShow为真时才会创建阴影
void ShowShadow(bool bShow);
bool IsShowShadow() const;
void DisableShadow(bool bDisable);
bool IsDisableShadow() const;
// 算法阴影的函数
bool SetRadius(int NewSize = 0);
DWORD GetRadius() const;
bool SetSpread(int NewSharpness);
DWORD GetSpread() const;
bool SetOffset(int NewXOffset, int NewYOffset);
SIZE GetOffset() const;
bool SetColor(COLORREF NewColor);
DWORD GetCorlor() const;
// 图片阴影的函数
bool SetImage(LPCTSTR szImage);
LPCTSTR GetImage() const;
bool SetShadowCorner(RECT rcCorner); // 九宫格方式描述阴影
RECT GetShadowCorner() const;
// 把自己的阴影样式复制到传入参数
bool CopyShadow(CShadowUI* pShadow);
// 创建阴影窗体,由CPaintManagerUI自动调用,除非自己要单独创建阴影
void Create(CPaintManagerUI* pPaintManager);
protected:
// 初始化并注册阴影类
static bool Initialize(HINSTANCE hInstance);
// 保存已经附加的窗体句柄和与其关联的阴影类,方便在ParentProc()函数中通过句柄得到阴影类
static std::map<HWND, CShadowUI *>& GetShadowMap();
// 子类化父窗体
static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 父窗体改变大小,移动,或者主动重绘阴影时调用
void Update(HWND hParent);
//快速模糊化
static void superFastBlur(unsigned char *pix, int w, int h, int radius);
// 通过算法计算阴影
void MakeShadowImage(HDC hDc);
protected:
enum ShadowStatus
{
SS_ENABLED = 1, // Shadow is enabled, if not, the following one is always false
SS_VISABLE = 1 << 1, // Shadow window is visible
SS_PARENTVISIBLE = 1 << 2 // Parent window is visible, if not, the above one is always false
};
static bool s_bHasInit;
CPaintManagerUI *m_pManager; // 父窗体的CPaintManagerUI,用来获取素材资源和父窗体句柄
HWND m_hWnd; // 阴影窗体的句柄
LONG_PTR m_OriParentProc; // 子类化父窗体
BYTE m_Status;
bool m_bIsImageMode; // 是否为图片阴影模式
bool m_bIsShowShadow; // 是否要显示阴影
bool m_bIsDisableShadow;
// 算法阴影成员变量
//算法生成的阴影图片 内部索引名
CDuiString m_sMadeShadowImage;
//shaodow blur radius px
int m_Radius;
//shaodow spread
int m_Spread;
// relative to the parent window, at center of both windows (not top-left corner), signed
// The X and Y offsets of shadow window,
SIZE m_szOffset;
COLORREF m_ShadowColor; // Color of shadow
// Restore last parent window size, used to determine the update strategy when parent window is resized
LPARAM m_WndSize;
// Set this to true if the shadow should not be update until next WM_PAINT is received
bool m_bUpdate;
// 图片阴影成员变量
CDuiString m_sShadowImage;
RECT m_rcShadowCorner;
};
}
#endif //__UISHADOW_H__
//UIShadow.cpp
#include "StdAfx.h"
#include "UIShadow.h"
#include "math.h"
#include "crtdbg.h"
namespace DuiLib
{
const TCHAR *strWndClassName = _T("PerryShadowWnd");
bool CShadowUI::s_bHasInit = FALSE;
CShadowUI::CShadowUI(void)
: m_hWnd((HWND)NULL)
, m_OriParentProc(NULL)
, m_Status(0)
, m_WndSize(0)
, m_bUpdate(false)
, m_bIsImageMode(false)
, m_bIsShowShadow(false)
, m_bIsDisableShadow(false)
, m_ShadowColor(0x2f000000)
,m_Radius(10)
,m_Spread(0)
{
m_szOffset = { 0, 0 };
::ZeroMemory(&m_rcShadowCorner, sizeof(RECT));
}
CShadowUI::~CShadowUI(void)
{
}
bool CShadowUI::Initialize(HINSTANCE hInstance)
{
if (s_bHasInit)
return false;
// Register window class for shadow window
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DefWindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = strWndClassName;
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
s_bHasInit = true;
return true;
}
void CShadowUI::Create(CPaintManagerUI* pPaintManager)
{
if(!m_bIsShowShadow)
return;
// Already initialized
_ASSERT(CPaintManagerUI::GetInstance() != INVALID_HANDLE_VALUE);
_ASSERT(pPaintManager != NULL);
m_pManager = pPaintManager;
HWND hParentWnd = m_pManager->GetPaintWindow();
// Add parent window - shadow pair to the map
_ASSERT(GetShadowMap().find(hParentWnd) == GetShadowMap().end()); // Only one shadow for each window
GetShadowMap()[hParentWnd] = this;
// Determine the initial show state of shadow according to parent window's state
LONG lParentStyle = GetWindowLongPtr(hParentWnd, GWL_STYLE);
// Create the shadow window
LONG styleValue = lParentStyle & WS_CAPTION;
m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,
/*WS_VISIBLE | */styleValue | WS_POPUPWINDOW,
CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, CPaintManagerUI::GetInstance(), NULL);
if(!(WS_VISIBLE & lParentStyle)) // Parent invisible
m_Status = SS_ENABLED;
else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
m_Status = SS_ENABLED | SS_PARENTVISIBLE;
else // Show the shadow
{
m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
Update(hParentWnd);
}
// Replace the original WndProc of parent window to steal messages
m_OriParentProc = GetWindowLongPtr(hParentWnd, GWLP_WNDPROC);
#pragma warning(disable: 4311) // temporrarily disable the type_cast warning in Win32
SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)ParentProc);
#pragma warning(default: 4311)
}
std::map<HWND, CShadowUI *>& CShadowUI::GetShadowMap()
{
static std::map<HWND, CShadowUI *> s_Shadowmap;
return s_Shadowmap;
}
LRESULT CALLBACK CShadowUI::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_ASSERT(GetShadowMap().find(hwnd) != GetShadowMap().end()); // Shadow must have been attached
CShadowUI *pThis = GetShadowMap()[hwnd];
if (pThis->m_bIsDisableShadow) {
#pragma warning(disable: 4312) // temporrarily disable the type_cast warning in Win32
// Call the default(original) window procedure for other messages or messages processed but not returned
return ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);
#pragma warning(default: 4312)
}
switch(uMsg)
{
case WM_WINDOWPOSCHANGED:
RECT WndRect;
GetWindowRect(hwnd, &WndRect);
if (pThis->m_bIsImageMode) {
SetWindowPos(pThis->m_hWnd, 0, WndRect.left - pThis->m_rcShadowCorner.left, WndRect.top - pThis->m_rcShadowCorner.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
else {
SetWindowPos(pThis->m_hWnd, 0, WndRect.left + pThis->m_szOffset.cx - pThis->m_Radius - pThis->m_Spread, WndRect.top + pThis->m_szOffset.cy - pThis->m_Radius - pThis->m_Spread, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
break;
case WM_MOVE:
if(pThis->m_Status & SS_VISABLE)
{
RECT WndRect;
GetWindowRect(hwnd, &WndRect);
if (pThis->m_bIsImageMode) {
SetWindowPos(pThis->m_hWnd, 0, WndRect.left - pThis->m_rcShadowCorner.left, WndRect.top - pThis->m_rcShadowCorner.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
else {
SetWindowPos(pThis->m_hWnd, 0, WndRect.left + pThis->m_szOffset.cx - pThis->m_Radius - pThis->m_Spread, WndRect.top + pThis->m_szOffset.cy - pThis->m_Radius - pThis->m_Spread, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
}
break;
case WM_SIZE:
if(pThis->m_Status & SS_ENABLED)
{
if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam)
{
::ShowWindow(pThis->m_hWnd, SW_HIDE);
pThis->m_Status &= ~SS_VISABLE;
}
else if(pThis->m_Status & SS_PARENTVISIBLE) // Parent maybe resized even if invisible
{
// Awful! It seems that if the window size was not decreased
// the window region would never be updated until WM_PAINT was sent.
// So do not Update() until next WM_PAINT is received in this case
if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))
pThis->m_bUpdate = true;
else
pThis->Update(hwnd);
if(!(pThis->m_Status & SS_VISABLE))
{
::ShowWindow(pThis->m_hWnd, SW_SHOWNOACTIVATE);
pThis->m_Status |= SS_VISABLE;
}
}
pThis->m_WndSize = lParam;
}
break;
case WM_PAINT:
{
if(pThis->m_bUpdate)
{
pThis->Update(hwnd);
pThis->m_bUpdate = false;
}
//return hr;
break;
}
// In some cases of sizing, the up-right corner of the parent window region would not be properly updated
// Update() again when sizing is finished
case WM_EXITSIZEMOVE:
if(pThis->m_Status & SS_VISABLE)
{
pThis->Update(hwnd);
}
break;
case WM_SHOWWINDOW:
if(pThis->m_Status & SS_ENABLED)
{
if(!wParam) // the window is being hidden
{
::ShowWindow(pThis->m_hWnd, SW_HIDE);
pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);
}
else if(!(pThis->m_Status & SS_PARENTVISIBLE))
{
//pThis->Update(hwnd);
pThis->m_bUpdate = true;
::ShowWindow(pThis->m_hWnd, SW_SHOWNOACTIVATE);
pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;
}
}
break;
case WM_DESTROY:
DestroyWindow(pThis->m_hWnd); // Destroy the shadow
break;
case WM_NCDESTROY:
GetShadowMap().erase(hwnd); // Remove this window and shadow from the map
break;
}
#pragma warning(disable: 4312) // temporrarily disable the type_cast warning in Win32
// Call the default(original) window procedure for other messages or messages processed but not returned
return ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);
#pragma warning(default: 4312)
}
void GetLastErrorMessage() { //Formats GetLastError() value.
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf, 0, NULL
);
// Display the string.
//MessageBox(NULL, (const wchar_t*)lpMsgBuf, L"GetLastError", MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
void CShadowUI::Update(HWND hParent)
{
if(!m_bIsShowShadow || !(m_Status & SS_VISABLE)) return;
RECT WndRect;
GetWindowRect(hParent, &WndRect);
int nShadWndWid;
int nShadWndHei;
if (m_bIsImageMode) {
if(m_sShadowImage.IsEmpty()) return;
nShadWndWid = WndRect.right - WndRect.left + m_rcShadowCorner.left + m_rcShadowCorner.right;
nShadWndHei = WndRect.bottom - WndRect.top + m_rcShadowCorner.top + m_rcShadowCorner.bottom;
}
else {
if (m_Radius == 0) return;
nShadWndWid = WndRect.right - WndRect.left + (m_Radius + m_Spread) * 2;
nShadWndHei = WndRect.bottom - WndRect.top + (m_Radius + m_Spread) * 2;
}
// Create the alpha blending bitmap
BITMAPINFO bmi; // bitmap header
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = nShadWndWid;
bmi.bmiHeader.biHeight = nShadWndHei;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // four 8-bit components
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;
BYTE *pvBits; // pointer to DIB section
HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);
if (hbitmap == NULL) {
GetLastErrorMessage();
}
HDC hMemDC = CreateCompatibleDC(NULL);
if (hMemDC == NULL) {
GetLastErrorMessage();
}
HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
if (GetLastError()!=0) {
GetLastErrorMessage();
}
if (m_bIsImageMode)
{
RECT rcPaint = {0, 0, nShadWndWid, nShadWndHei};
const TImageInfo* data = m_pManager->GetImageEx((LPCTSTR)m_sShadowImage, NULL, 0);
if( !data ) return;
RECT rcBmpPart = {0};
rcBmpPart.right = data->nX;
rcBmpPart.bottom = data->nY;
RECT corner = m_rcShadowCorner;
CRenderEngine::DrawImage(hMemDC, data->hBitmap, rcPaint, rcPaint, rcBmpPart, corner, data->bAlpha, 0xFF, true, false, false);
}
else
{
MakeShadowImage(hMemDC);
RECT rcPaint = { 0, 0, nShadWndWid, nShadWndHei };
const TImageInfo* data = m_pManager->GetImage(m_sMadeShadowImage);
if (!data) return;
RECT rcBmpPart = { 0 };
rcBmpPart.right = data->nX;
rcBmpPart.bottom = data->nY;
RECT corner = { m_Radius + m_Spread - m_szOffset.cx, m_Radius + m_Spread - m_szOffset.cy, m_Radius + m_Spread + m_szOffset.cx, m_Radius + m_Spread + m_szOffset.cy };
CRenderEngine::DrawImage(hMemDC, data->hBitmap, rcPaint, rcPaint, rcBmpPart, corner, data->bAlpha, 0xFF, true, false, false);
}
POINT ptDst;
if (m_bIsImageMode)
{
ptDst.x = WndRect.left - m_rcShadowCorner.left;
ptDst.y = WndRect.top - m_rcShadowCorner.top;
}
else
{
ptDst.x = WndRect.left + m_szOffset.cx - m_Radius - m_Spread;
ptDst.y = WndRect.top + m_szOffset.cy - m_Radius - m_Spread;
}
POINT ptSrc = {0, 0};
SIZE WndSize = {nShadWndWid, nShadWndHei};
BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);
BOOL bRet= ::UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC, &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);
_ASSERT(bRet); // something was wrong....
// Delete used resources
SelectObject(hMemDC, hOriBmp);
DeleteObject(hbitmap);
DeleteDC(hMemDC);
}
/*
* Super Fast Blur v1.1
* Original author: Mario Klingemann (C++ version)
* Original address: http://incubator.quasimondo.com/processing/superfastblur.pde
* C version updated by Lellansin (http://www.lellansin.com)
*/
//32位图
void CShadowUI::superFastBlur(unsigned char *pix, int w, int h, int radius)
{
int div;
int wm, hm, wh;
int *vMIN, *vMAX;
unsigned char *r, *g, *b,*a, *dv;
int rsum, gsum, bsum,asum, x, y, i, p, p1, p2, yp, yi, yw;
if (radius < 1) return;
wm = w - 1;
hm = h - 1;
wh = w * h;
div = radius + radius + 1;
vMIN = (int *)malloc(sizeof(int)* max(w, h));
vMAX = (int *)malloc(sizeof(int)* max(w, h));
r = (unsigned char *)malloc(sizeof(unsigned char)* wh);
g = (unsigned char *)malloc(sizeof(unsigned char)* wh);
b = (unsigned char *)malloc(sizeof(unsigned char)* wh);
a = (unsigned char *)malloc(sizeof(unsigned char)* wh);
dv = (unsigned char *)malloc(sizeof(unsigned char)* 256 * div);
for (i = 0; i < 256 * div; i++)
dv[i] = (i / div);
yw = yi = 0;
for (y = 0; y < h; y++)
{
rsum = gsum = bsum = asum=0;
for (i = -radius; i <= radius; i++)
{
p = (yi + min(wm, max(i, 0))) * 4;
bsum += pix[p];
gsum += pix[p + 1];
rsum += pix[p + 2];
asum += pix[p + 3];
}
for (x = 0; x < w; x++)
{
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
a[yi] = dv[asum];
if (y == 0)
{
vMIN[x] = min(x + radius + 1, wm);
vMAX[x] = max(x - radius, 0);
}
p1 = (yw + vMIN[x]) * 4;
p2 = (yw + vMAX[x]) * 4;
bsum += pix[p1] - pix[p2];
gsum += pix[p1 + 1] - pix[p2 + 1];
rsum += pix[p1 + 2] - pix[p2 + 2];
asum += pix[p1 + 3] - pix[p2 + 3];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++)
{
rsum = gsum = bsum = asum=0;
yp = -radius * w;
for (i = -radius; i <= radius; i++)
{
yi = max(0, yp) + x;
rsum += r[yi];
gsum += g[yi];
bsum += b[yi];
asum += a[yi];
yp += w;
}
yi = x;
for (y = 0; y < h; y++)
{
pix[yi * 4] = dv[bsum];
pix[yi * 4 + 1] = dv[gsum];
pix[yi * 4 + 2] = dv[rsum];
pix[yi * 4 + 3] = dv[asum];
if (x == 0)
{
vMIN[y] = min(y + radius + 1, hm) * w;
vMAX[y] = max(y - radius, 0) * w;
}
p1 = x + vMIN[y];
p2 = x + vMAX[y];
rsum += r[p1] - r[p2];
gsum += g[p1] - g[p2];
bsum += b[p1] - b[p2];
asum += a[p1] - a[p2];
yi += w;
}
}
free(r);
free(g);
free(b);
free(a);
free(vMIN);
free(vMAX);
free(dv);
}
void CShadowUI::MakeShadowImage(HDC hDc)
{
//当前生成颜色索引,如果已经存在,则返回直接调用 格式:offset.cx-offset.cy-radius-spread--color, like box-shadow 参数
m_sMadeShadowImage.Format(L"%d-%d-%d-%d-%x", m_szOffset.cx, m_szOffset.cy,m_Radius, m_Spread, m_ShadowColor);
const TImageInfo *data = m_pManager->GetImage(m_sMadeShadowImage);
if (data)
return;
int srcWidth = (m_Radius + m_Spread)*2 + 40;
int srcHeigh = (m_Radius + m_Spread)*2 + 40;
// Create the alpha blending bitmap
BITMAPINFO bmi; // bitmap header
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = srcWidth;
bmi.bmiHeader.biHeight = srcHeigh;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // four 8-bit components
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = srcWidth * srcHeigh * 4;
BYTE *pvBits; // pointer to DIB section
HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);
if (hbitmap == NULL) {
GetLastErrorMessage();
}
HDC hMemDC = CreateCompatibleDC(hDc);
if (hMemDC == NULL) {
GetLastErrorMessage();
}
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
if (GetLastError()!=0) {
GetLastErrorMessage();
}
ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);
RECT rc = { m_Radius, m_Radius, srcWidth - m_Radius, srcHeigh - m_Radius };
CRenderEngine::DrawColor(hMemDC,rc,m_ShadowColor);
superFastBlur(pvBits, srcWidth, srcHeigh, m_Radius);
SelectObject(hMemDC, hOldBmp);
DeleteDC(hMemDC);
//hbitmap m_pManager负责释放
m_pManager->AddImage(m_sMadeShadowImage, hbitmap, srcWidth, srcHeigh, true, false);
}
void CShadowUI::ShowShadow(bool bShow)
{
m_bIsShowShadow = bShow;
}
bool CShadowUI::IsShowShadow() const
{
return m_bIsShowShadow;
}
void CShadowUI::DisableShadow(bool bDisable) {
m_bIsDisableShadow = bDisable;
if (m_hWnd != NULL) {
if (m_bIsDisableShadow) {
::ShowWindow(m_hWnd, SW_HIDE);
}
else {
// Determine the initial show state of shadow according to parent window's state
LONG lParentStyle = GetWindowLongPtr(GetParent(m_hWnd), GWL_STYLE);
if (!(WS_VISIBLE & lParentStyle)) // Parent invisible
m_Status = SS_ENABLED;
else if ((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
m_Status = SS_ENABLED | SS_PARENTVISIBLE;
else // Show the shadow
{
m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
}
if ((WS_VISIBLE & lParentStyle) && !((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle))// Parent visible && no maxsize or min size
{
::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
Update(GetParent(m_hWnd));
}
}
}
}
////TODO shadow disnable fix////
bool CShadowUI::IsDisableShadow() const {
return m_bIsDisableShadow;
}
bool CShadowUI::SetRadius(int NewRadius)
{
if(NewRadius > 20 || NewRadius < -20)
return false;
m_Radius = (signed char)NewRadius;
if(m_hWnd != NULL && (SS_VISABLE & m_Status))
Update(GetParent(m_hWnd));
return true;
}
DWORD CShadowUI::GetRadius() const
{
return m_Radius;
}
bool CShadowUI::SetSpread(int NewSpread)
{
if(NewSpread > 20)
return false;
m_Spread = (unsigned char)NewSpread;
if(m_hWnd != NULL && (SS_VISABLE & m_Status))
Update(GetParent(m_hWnd));
return true;
}
DWORD CShadowUI::GetSpread() const
{
return m_Spread;
}
bool CShadowUI::SetOffset(int NewXOffset, int NewYOffset)
{
if(NewXOffset > 20 || NewXOffset < -20 ||
NewYOffset > 20 || NewYOffset < -20)
return false;
m_szOffset.cx = NewXOffset;
m_szOffset.cy = NewYOffset;
if(m_hWnd != NULL && (SS_VISABLE & m_Status))
Update(GetParent(m_hWnd));
return true;
}
SIZE CShadowUI::GetOffset() const
{
return m_szOffset;
}
bool CShadowUI::SetColor(COLORREF NewColor)
{
m_ShadowColor = NewColor;
if(m_hWnd != NULL && (SS_VISABLE & m_Status))
Update(GetParent(m_hWnd));
return true;
}
DWORD CShadowUI::GetCorlor() const
{
return (DWORD)m_ShadowColor;
}
bool CShadowUI::SetImage(LPCTSTR szImage)
{
if (szImage == NULL)
return false;
m_bIsImageMode = true;
m_sShadowImage = szImage;
if(m_hWnd != NULL && (SS_VISABLE & m_Status))
Update(GetParent(m_hWnd));
return true;
}
LPCTSTR CShadowUI::GetImage() const
{
return m_sShadowImage.GetData();
}
bool CShadowUI::SetShadowCorner(RECT rcCorner)
{
if (rcCorner.left < 0 || rcCorner.top < 0 || rcCorner.right < 0 || rcCorner.bottom < 0) return false;
m_rcShadowCorner = rcCorner;
if(m_hWnd != NULL && (SS_VISABLE & m_Status)) {
Update(GetParent(m_hWnd));
}
return true;
}
RECT CShadowUI::GetShadowCorner() const
{
return m_rcShadowCorner;
}
bool CShadowUI::CopyShadow(CShadowUI* pShadow)
{
if (m_bIsImageMode) {
pShadow->SetImage(m_sShadowImage);
pShadow->SetShadowCorner(m_rcShadowCorner);
}
else {
pShadow->SetRadius(m_Radius);
pShadow->SetSpread(m_Spread);
pShadow->SetColor(m_ShadowColor);
pShadow->SetOffset(m_szOffset.cx, m_szOffset.cy);
}
pShadow->ShowShadow(m_bIsShowShadow);
return true;
}
} //namespace DuiLib