2025-11-28 00:35:46 +09:00

371 lines
9.6 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include "Private.h"
#include "Globals.h"
#include "BaseWindow.h"
#include "ShadowWindow.h"
#define SHADOW_ALPHANUMBER (5)
#define ALPHA(x) (255 - (x))
//// Gray scale values for the shadow grades
#define GS01 255
#define GS02 254
#define GS03 253
#define GS04 252
#define GS05 250
#define GS06 246
#define GS07 245
#define GS08 242
#define GS09 241
#define GS10 227
#define GS11 217
#define GS12 213
#define GS13 212
#define GS14 199
#define GS15 180
#define GS16 172
#define GS17 171
#define GS18 155
#define GS19 144
#define GS20 142
// pre-computed alpha values for the shadow
const BYTE AlphaTable[SHADOW_ALPHANUMBER] = {
ALPHA(GS04), ALPHA(GS09), ALPHA(GS13), ALPHA(GS17), ALPHA(GS20)
};
const BYTE CornerShadowAlphaMetric[SHADOW_ALPHANUMBER][SHADOW_ALPHANUMBER] = {
ALPHA(GS08), ALPHA(GS06), ALPHA(GS05), ALPHA(GS03), ALPHA(GS02),
ALPHA(GS11), ALPHA(GS10), ALPHA(GS09), ALPHA(GS05), ALPHA(GS02),
ALPHA(GS15), ALPHA(GS14), ALPHA(GS10), ALPHA(GS07), ALPHA(GS03),
ALPHA(GS18), ALPHA(GS15), ALPHA(GS11), ALPHA(GS08), ALPHA(GS03),
ALPHA(GS19), ALPHA(GS16), ALPHA(GS12), ALPHA(GS09), ALPHA(GS04),
};
//+---------------------------------------------------------------------------
//
// _Create
//
//----------------------------------------------------------------------------
BOOL CShadowWindow::_Create(ATOM atom, DWORD dwExStyle, DWORD dwStyle, _In_opt_ CBaseWindow *pParent, int wndWidth, int wndHeight)
{
if (!CBaseWindow::_Create(atom, dwExStyle, dwStyle, pParent, wndWidth, wndHeight))
{
return FALSE;
}
return _Initialize();
}
//+---------------------------------------------------------------------------
//
// _WindowProcCallback
//
// Shadow window proc.
//----------------------------------------------------------------------------
LRESULT CALLBACK CShadowWindow::_WindowProcCallback(_In_ HWND wndHandle, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
HDC dcHandle;
PAINTSTRUCT ps;
dcHandle = BeginPaint(wndHandle, &ps);
HBRUSH hBrush = CreateSolidBrush(_color);
FillRect(dcHandle, &ps.rcPaint, hBrush);
DeleteObject(hBrush);
EndPaint(wndHandle, &ps);
}
return 0;
case WM_SETTINGCHANGE:
_OnSettingChange();
break;
}
return DefWindowProc(wndHandle, uMsg, wParam, lParam);
}
//+---------------------------------------------------------------------------
//
// _OnSettingChange
//
//----------------------------------------------------------------------------
void CShadowWindow::_OnSettingChange()
{
_InitSettings();
DWORD dwWndStyleEx = GetWindowLong(_GetWnd(), GWL_EXSTYLE);
if (_isGradient)
{
SetWindowLong(_GetWnd(), GWL_EXSTYLE, (dwWndStyleEx | WS_EX_LAYERED));
}
else
{
SetWindowLong(_GetWnd(), GWL_EXSTYLE, (dwWndStyleEx & ~WS_EX_LAYERED));
}
_AdjustWindowPos();
_InitShadow();
}
//+---------------------------------------------------------------------------
//
// _OnOwnerWndMoved
//
//----------------------------------------------------------------------------
void CShadowWindow::_OnOwnerWndMoved(BOOL isResized)
{
if (IsWindow(_GetWnd()) && _IsWindowVisible())
{
_AdjustWindowPos();
if (isResized)
{
_InitShadow();
}
}
}
//+---------------------------------------------------------------------------
//
// _Show
//
//----------------------------------------------------------------------------
void CShadowWindow::_Show(BOOL isShowWnd)
{
_OnOwnerWndMoved(TRUE);
CBaseWindow::_Show(isShowWnd);
}
//+---------------------------------------------------------------------------
//
// _Initialize
//
//----------------------------------------------------------------------------
BOOL CShadowWindow::_Initialize()
{
_InitSettings();
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _InitSettings
//
//----------------------------------------------------------------------------
void CShadowWindow::_InitSettings()
{
HDC dcHandle = GetDC(nullptr);
// device caps
int cBitsPixelScreen = GetDeviceCaps(dcHandle, BITSPIXEL);
_isGradient = cBitsPixelScreen > 8;
ReleaseDC(nullptr, dcHandle);
if (_isGradient)
{
_color = RGB(0, 0, 0);
_sizeShift.cx = SHADOW_ALPHANUMBER;
_sizeShift.cy = SHADOW_ALPHANUMBER;
}
else
{
_color = RGB(128, 128, 128);
_sizeShift.cx = 2;
_sizeShift.cy = 2;
}
}
//+---------------------------------------------------------------------------
//
// _AdjustWindowPos
//
//----------------------------------------------------------------------------
void CShadowWindow::_AdjustWindowPos()
{
if (!IsWindow(_GetWnd()))
{
return;
}
HWND hWndOwner = _pWndOwner->_GetWnd();
RECT rc = {0, 0, 0, 0};
GetWindowRect(hWndOwner, &rc);
SetWindowPos(_GetWnd(), hWndOwner,
rc.left + _sizeShift.cx,
rc.top + _sizeShift.cy,
rc.right - rc.left,
rc.bottom - rc.top,
SWP_NOOWNERZORDER | SWP_NOACTIVATE);
}
//+---------------------------------------------------------------------------
//
// _InitShadow
//
//----------------------------------------------------------------------------
#define GETRGBALPHA(_x_, _y_) ((RGBALPHA *)pDIBits + (_y_) * size.cx + (_x_))
void CShadowWindow::_InitShadow()
{
typedef struct _RGBAPLHA {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbAlpha;
} RGBALPHA;
HDC dcScreenHandle = nullptr;
HDC dcLayeredHandle = nullptr;
RECT rcWindow = {0, 0, 0, 0};
SIZE size = {0, 0};
BITMAPINFO bitmapInfo;
HBITMAP bitmapMemHandle = nullptr;
HBITMAP bitmapOldHandle = nullptr;
void* pDIBits = nullptr;
int i = 0;
int j = 0;
POINT ptSrc = {0, 0};
POINT ptDst = {0, 0};
BLENDFUNCTION Blend;
if (!_isGradient)
{
return;
}
SetWindowLong(_GetWnd(), GWL_EXSTYLE, (GetWindowLong(_GetWnd(), GWL_EXSTYLE) | WS_EX_LAYERED));
_GetWindowRect(&rcWindow);
size.cx = rcWindow.right - rcWindow.left;
size.cy = rcWindow.bottom - rcWindow.top;
dcScreenHandle = GetDC(nullptr);
if (dcScreenHandle == nullptr) {
return;
}
dcLayeredHandle = CreateCompatibleDC(dcScreenHandle);
if (dcLayeredHandle == nullptr) {
ReleaseDC(nullptr, dcScreenHandle);
return;
}
// create bitmap
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = size.cx;
bitmapInfo.bmiHeader.biHeight = size.cy;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = 0;
bitmapInfo.bmiHeader.biXPelsPerMeter = 100;
bitmapInfo.bmiHeader.biYPelsPerMeter = 100;
bitmapInfo.bmiHeader.biClrUsed = 0;
bitmapInfo.bmiHeader.biClrImportant = 0;
bitmapMemHandle = CreateDIBSection(dcScreenHandle, &bitmapInfo, DIB_RGB_COLORS, &pDIBits, nullptr, 0);
if (pDIBits == nullptr || bitmapMemHandle == nullptr) {
ReleaseDC(nullptr, dcScreenHandle);
DeleteDC(dcLayeredHandle);
return;
}
memset(pDIBits, 0, ((((32 * size.cx) + 31) & ~31) / 8) * size.cy);
// edges
for (i = 0; i < SHADOW_ALPHANUMBER; i++) {
RGBALPHA *ppxl;
BYTE bAlpha = AlphaTable[i];
// bottom
if (i <= (size.cy + 1)/2) {
for (j = SHADOW_ALPHANUMBER; j < size.cx - SHADOW_ALPHANUMBER; j++) {
ppxl = GETRGBALPHA(j, i);
ppxl->rgbAlpha = bAlpha;
}
}
// right
if (i <= (size.cx + 1)/2) {
for (j = SHADOW_ALPHANUMBER; j < size.cy - SHADOW_ALPHANUMBER; j++) {
ppxl = GETRGBALPHA(size.cx - 1 - i, j);
ppxl->rgbAlpha = bAlpha;
}
}
}
// corners
for (i = 0; i < SHADOW_ALPHANUMBER; i++) {
for (j = 0; j < SHADOW_ALPHANUMBER; j++) {
RGBALPHA *ppxl;
BYTE bAlpha;
bAlpha = CornerShadowAlphaMetric[i][SHADOW_ALPHANUMBER - j - 1];
// top-right
if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) {
ppxl = GETRGBALPHA(size.cx - 1 - j, size.cy - 1 - i);
ppxl->rgbAlpha = bAlpha;
}
// bottom-left
if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) {
ppxl = GETRGBALPHA(j, i + 1);
ppxl->rgbAlpha = bAlpha;
}
// bottom-right
if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) {
ppxl = GETRGBALPHA(size.cx - 1 - j, i + 1);
ppxl->rgbAlpha = bAlpha;
}
}
}
ptSrc.x = 0;
ptSrc.y = 0;
ptDst.x = rcWindow.left;
ptDst.y = rcWindow.top;
Blend.BlendOp = AC_SRC_OVER;
Blend.BlendFlags = 0;
Blend.SourceConstantAlpha = 255;
Blend.AlphaFormat = AC_SRC_ALPHA;
bitmapOldHandle = (HBITMAP)SelectObject(dcLayeredHandle, bitmapMemHandle);
UpdateLayeredWindow(_GetWnd(), dcScreenHandle, nullptr, &size, dcLayeredHandle, &ptSrc, 0, &Blend, ULW_ALPHA);
SelectObject(dcLayeredHandle, bitmapOldHandle);
// done
ReleaseDC(nullptr, dcScreenHandle);
DeleteDC(dcLayeredHandle);
DeleteObject(bitmapMemHandle);
}