DuiLib, UIShadow, Software Implementation

转载自 : https://blog.csdn.net/qq_21743659/article/details/107683772

和 Css 中 的 Box-Shadow 差不多的额, 加入了 radius, offset, spread, 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支持透明度"/>

 Merges In UIDialogBuilder,


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
// 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;
}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值