XML Configuratino Attributes
<Attribute name="showshadow" default="false" type="BOOL" comment="Enable window shadow"/>
<Attribute name="shadowimage" default="" type="STRING" comment="Shadow image path (disables algorithmic shadow)"/>
<Attribute name="shadowcorner" default="0,0,0,0" type="RECT" comment="Nine-grid shadow corner definition"/>
<Attribute name="shadowradius" default="10" type="BYTE" comment="Blur radius (0-20)"/>
<Attribute name="shadowspread" default="0" type="BYTE" comment="Shadow expansion"/>
<Attribute name="shadowoffset" default="0,0" type="SIZE" comment="Shadow displacement"/>
<Attribute name="shadowcolor" default="0x2f000000" type="DWORD" comment="ARGB shadow color"/>
Dialog Builder Attribute Handling
if (::_tcsicmp(attrName, _T("shadowradius")) == 0) {
pManager->GetShadow()->SetBlurRadius(::_ttoi(attrValue));
}
else if (::_tcsicmp(attrName, _T("shadowspread")) == 0) {
pManager->GetShadow()->SetSpreadAmount(::_ttoi(attrValue));
}
else if (::_tcsicmp(attrName, _T("shadowoffset")) == 0) {
TCHAR* parsePtr = nullptr;
int offsetX = ::_tcstol(attrValue, &parsePtr, 10);
int offsetY = ::_tcstol(parsePtr + 1, &parsePtr, 10);
pManager->GetShadow()->SetDisplacement(offsetX, offsetY);
}
else if (::_tcsicmp(attrName, _T("shadowcolor")) == 0) {
DWORD colorValue = ::_tcstoul(attrValue[0] == _T('#') ? attrValue + 1 : attrValue, nullptr, 16);
pManager->GetShadow()->SetShadowColor(colorValue);
}
else if (::_tcsicmp(attrName, _T("shadowimage")) == 0) {
pManager->GetShadow()->SetImageResource(attrValue);
}
Shadow Class Interface
class UILIB_API CShadowUI {
public:
void EnableShadow(bool enable);
void SetBlurRadius(int radius);
void SetSpreadAmount(int spread);
void SetDisplacement(int x, int y);
void SetShadowColor(COLORREF color);
void SetImageResource(LPCTSTR imagePath);
void Create(CPaintManagerUI* manager);
private:
void UpdateShadowAppearance();
void GenerateBlurEffect(HDC targetDC);
static void ApplyBlur(unsigned char* pixels, int width, int height, int radius);
HWND shadowWindow_;
LONG_PTR originalWndProc_;
int blurRadius_;
int spreadAmount_;
SIZE displacement_;
COLORREF shadowColor_;
CDuiString imagePath_;
RECT cornerDefinition_;
bool useImageMode_;
};
Core Implementation Logic
void CShadowUI::Create(CPaintManagerUI* manager) {
manager_ = manager;
HWND parentHwnd = manager->GetPaintWindow();
shadowWindow_ = ::CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT,
className_, nullptr, WS_POPUP,
0, 0, 0, 0, parentHwnd, nullptr, nullptr, nullptr);
originalWndProc_ = ::SetWindowLongPtr(parentHwnd, GWLP_WNDPROC,
reinterpret_cast<long_ptr>(ParentMessageHandler));
}
void CShadowUI::UpdateShadowAppearance() {
RECT parentRect;
::GetWindowRect(manager_->GetPaintWindow(), &parentRect);
int width = parentRect.right - parentRect.left + (blurRadius_ + spreadAmount_) * 2;
int height = parentRect.bottom - parentRect.top + (blurRadius_ + spreadAmount_) * 2;
HDC memDC = ::CreateCompatibleDC(nullptr);
BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), width, height, 1, 32 };
unsigned char* pixelData = nullptr;
HBITMAP bitmap = ::CreateDIBSection(memDC, &bmi, DIB_RGB_COLORS, (void**)&pixelData, nullptr, 0);
if (useImageMode_) {
// Render image-based shadow
} else {
GenerateBlurEffect(memDC);
}
POINT windowPos = {
parentRect.left + displacement_.cx - blurRadius_ - spreadAmount_,
parentRect.top + displacement_.cy - blurRadius_ - spreadAmount_
};
SIZE windowSize = { width, height };
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
::UpdateLayeredWindow(shadowWindow_, nullptr, &windowPos, &windowSize, memDC, nullptr, 0, &blend, ULW_ALPHA);
::DeleteObject(bitmap);
::DeleteDC(memDC);
}
void CShadowUI::ApplyBlur(unsigned char* pixels, int width, int height, int radius) {
if (radius < 1) return;
int divisor = radius * 2 + 1;
std::vector<unsigned char> blurMap(256 * divisor);
for (int i = 0; i < 256 * divisor; ++i)
blurMap[i] = static_cast<unsigned char>(i / divisor);
// Horizontal and vertical blur passes
// Implementation of separable box blur algorithm
}</long_ptr>