Changed local variable and parameter names to snake case style
This commit is contained in:
parent
ba03c544f3
commit
f73233ee55
4 changed files with 247 additions and 247 deletions
|
@ -17,19 +17,19 @@ HBITMAP CopyBitmap(HBITMAP bitmap) {
|
||||||
|
|
||||||
BITMAP bm;
|
BITMAP bm;
|
||||||
if (bitmap && GetObject(bitmap, sizeof(bm), &bm)) {
|
if (bitmap && GetObject(bitmap, sizeof(bm), &bm)) {
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdc_screen = GetDC(NULL);
|
||||||
ret = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight);
|
ret = CreateCompatibleBitmap(hdc_screen, bm.bmWidth, bm.bmHeight);
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdc_screen);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
HDC hdcSrc = CreateCompatibleDC(NULL);
|
HDC hdc_src = CreateCompatibleDC(NULL);
|
||||||
HDC hdcDst = CreateCompatibleDC(NULL);
|
HDC hdc_dst = CreateCompatibleDC(NULL);
|
||||||
SelectBitmap(hdcSrc, bitmap);
|
SelectBitmap(hdc_src, bitmap);
|
||||||
SelectBitmap(hdcDst, ret);
|
SelectBitmap(hdc_dst, ret);
|
||||||
BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight,
|
BitBlt(hdc_dst, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
hdcSrc, 0, 0, SRCCOPY);
|
hdc_src, 0, 0, SRCCOPY);
|
||||||
DeleteDC(hdcDst);
|
DeleteDC(hdc_dst);
|
||||||
DeleteDC(hdcSrc);
|
DeleteDC(hdc_src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ HINSTANCE DesktopNotificationController::RegisterWndClasses() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::DesktopNotificationController(
|
DesktopNotificationController::DesktopNotificationController(
|
||||||
unsigned maximumToasts) {
|
unsigned maximum_toasts) {
|
||||||
instances_.reserve(maximumToasts);
|
instances_.reserve(maximum_toasts);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::~DesktopNotificationController() {
|
DesktopNotificationController::~DesktopNotificationController() {
|
||||||
|
@ -77,37 +77,37 @@ DesktopNotificationController::~DesktopNotificationController() {
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK DesktopNotificationController::WndProc(
|
LRESULT CALLBACK DesktopNotificationController::WndProc(
|
||||||
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
{
|
{
|
||||||
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lParam);
|
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lparam);
|
||||||
SetWindowLongPtr(hWnd, 0, (LONG_PTR)cs->lpCreateParams);
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)cs->lpCreateParams);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (wParam == TimerID_Animate) {
|
if (wparam == TimerID_Animate) {
|
||||||
Get(hWnd)->AnimateAll();
|
Get(hwnd)->AnimateAll();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_DISPLAYCHANGE:
|
case WM_DISPLAYCHANGE:
|
||||||
{
|
{
|
||||||
auto inst = Get(hWnd);
|
auto inst = Get(hwnd);
|
||||||
inst->ClearAssets();
|
inst->ClearAssets();
|
||||||
inst->AnimateAll();
|
inst->AnimateAll();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_SETTINGCHANGE:
|
case WM_SETTINGCHANGE:
|
||||||
if (wParam == SPI_SETWORKAREA) {
|
if (wparam == SPI_SETWORKAREA) {
|
||||||
Get(hWnd)->AnimateAll();
|
Get(hwnd)->AnimateAll();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::StartAnimation() {
|
void DesktopNotificationController::StartAnimation() {
|
||||||
|
@ -140,16 +140,16 @@ void DesktopNotificationController::InitializeFonts() {
|
||||||
auto baseHeight = metrics.lfMessageFont.lfHeight;
|
auto baseHeight = metrics.lfMessageFont.lfHeight;
|
||||||
|
|
||||||
HDC hdc = GetDC(NULL);
|
HDC hdc = GetDC(NULL);
|
||||||
auto dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
auto dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||||
ReleaseDC(NULL, hdc);
|
ReleaseDC(NULL, hdc);
|
||||||
|
|
||||||
metrics.lfMessageFont.lfHeight =
|
metrics.lfMessageFont.lfHeight =
|
||||||
(LONG)ScaleForDpi(baseHeight * 1.1f, dpiY);
|
(LONG)ScaleForDpi(baseHeight * 1.1f, dpi_y);
|
||||||
body_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
body_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
||||||
|
|
||||||
if (caption_font_) DeleteFont(caption_font_);
|
if (caption_font_) DeleteFont(caption_font_);
|
||||||
metrics.lfMessageFont.lfHeight =
|
metrics.lfMessageFont.lfHeight =
|
||||||
(LONG)ScaleForDpi(baseHeight * 1.4f, dpiY);
|
(LONG)ScaleForDpi(baseHeight * 1.4f, dpi_y);
|
||||||
caption_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
caption_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,14 +165,14 @@ void DesktopNotificationController::AnimateAll() {
|
||||||
// to all current conditions. Animation time is only one of the variables
|
// to all current conditions. Animation time is only one of the variables
|
||||||
// influencing them. Screen resolution is another.
|
// influencing them. Screen resolution is another.
|
||||||
|
|
||||||
bool keepAnimating = false;
|
bool keep_animating = false;
|
||||||
|
|
||||||
if (!instances_.empty()) {
|
if (!instances_.empty()) {
|
||||||
RECT workArea;
|
RECT work_area;
|
||||||
if (SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0)) {
|
if (SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0)) {
|
||||||
ScreenMetrics metrics;
|
ScreenMetrics metrics;
|
||||||
POINT origin = { workArea.right,
|
POINT origin = { work_area.right,
|
||||||
workArea.bottom - metrics.Y(toast_margin_<int>) };
|
work_area.bottom - metrics.Y(toast_margin_<int>) };
|
||||||
|
|
||||||
auto hdwp =
|
auto hdwp =
|
||||||
BeginDeferWindowPos(static_cast<int>(instances_.size()));
|
BeginDeferWindowPos(static_cast<int>(instances_.size()));
|
||||||
|
@ -183,14 +183,14 @@ void DesktopNotificationController::AnimateAll() {
|
||||||
auto notification = Toast::Get(inst.hwnd);
|
auto notification = Toast::Get(inst.hwnd);
|
||||||
hdwp = notification->Animate(hdwp, origin);
|
hdwp = notification->Animate(hdwp, origin);
|
||||||
if (!hdwp) break;
|
if (!hdwp) break;
|
||||||
keepAnimating |= notification->IsAnimationActive();
|
keep_animating |= notification->IsAnimationActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdwp) EndDeferWindowPos(hdwp);
|
if (hdwp) EndDeferWindowPos(hdwp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!keepAnimating) {
|
if (!keep_animating) {
|
||||||
_ASSERT(hwnd_controller_);
|
_ASSERT(hwnd_controller_);
|
||||||
if (hwnd_controller_) KillTimer(hwnd_controller_, TimerID_Animate);
|
if (hwnd_controller_) KillTimer(hwnd_controller_, TimerID_Animate);
|
||||||
is_animating_ = false;
|
is_animating_ = false;
|
||||||
|
@ -199,20 +199,20 @@ void DesktopNotificationController::AnimateAll() {
|
||||||
// Purge dismissed notifications and collapse the stack between
|
// Purge dismissed notifications and collapse the stack between
|
||||||
// items which are highlighted
|
// items which are highlighted
|
||||||
if (!instances_.empty()) {
|
if (!instances_.empty()) {
|
||||||
auto isAlive = [](ToastInstance& inst) {
|
auto is_alive = [](ToastInstance& inst) {
|
||||||
return inst.hwnd && IsWindowVisible(inst.hwnd);
|
return inst.hwnd && IsWindowVisible(inst.hwnd);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto isHighlighted = [](ToastInstance& inst) {
|
auto is_highlighted = [](ToastInstance& inst) {
|
||||||
return inst.hwnd && Toast::Get(inst.hwnd)->IsHighlighted();
|
return inst.hwnd && Toast::Get(inst.hwnd)->IsHighlighted();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto it = instances_.begin();; ++it) {
|
for (auto it = instances_.begin();; ++it) {
|
||||||
// find next highlighted item
|
// find next highlighted item
|
||||||
auto it2 = find_if(it, instances_.end(), isHighlighted);
|
auto it2 = find_if(it, instances_.end(), is_highlighted);
|
||||||
|
|
||||||
// collapse the stack in front of the highlighted item
|
// collapse the stack in front of the highlighted item
|
||||||
it = stable_partition(it, it2, isAlive);
|
it = stable_partition(it, it2, is_alive);
|
||||||
|
|
||||||
// purge the dead items
|
// purge the dead items
|
||||||
for_each(it, it2, [this](auto&& inst) { DestroyToast(inst); });
|
for_each(it, it2, [this](auto&& inst) { DestroyToast(inst); });
|
||||||
|
@ -231,17 +231,17 @@ void DesktopNotificationController::AnimateAll() {
|
||||||
ScreenMetrics metrics;
|
ScreenMetrics metrics;
|
||||||
auto margin = metrics.Y(toast_margin_<int>);
|
auto margin = metrics.Y(toast_margin_<int>);
|
||||||
|
|
||||||
int targetPos = 0;
|
int target_pos = 0;
|
||||||
for (auto&& inst : instances_) {
|
for (auto&& inst : instances_) {
|
||||||
if (inst.hwnd) {
|
if (inst.hwnd) {
|
||||||
auto toast = Toast::Get(inst.hwnd);
|
auto toast = Toast::Get(inst.hwnd);
|
||||||
|
|
||||||
if (toast->IsHighlighted())
|
if (toast->IsHighlighted())
|
||||||
targetPos = toast->GetVerticalPosition();
|
target_pos = toast->GetVerticalPosition();
|
||||||
else
|
else
|
||||||
toast->SetVerticalPosition(targetPos);
|
toast->SetVerticalPosition(target_pos);
|
||||||
|
|
||||||
targetPos += toast->GetHeight() + margin;
|
target_pos += toast->GetHeight() + margin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,11 +252,11 @@ void DesktopNotificationController::AnimateAll() {
|
||||||
|
|
||||||
DesktopNotificationController::Notification
|
DesktopNotificationController::Notification
|
||||||
DesktopNotificationController::AddNotification(
|
DesktopNotificationController::AddNotification(
|
||||||
std::wstring caption, std::wstring bodyText, HBITMAP image) {
|
std::wstring caption, std::wstring body_text, HBITMAP image) {
|
||||||
NotificationLink data(this);
|
NotificationLink data(this);
|
||||||
|
|
||||||
data->caption = move(caption);
|
data->caption = move(caption);
|
||||||
data->body_text = move(bodyText);
|
data->body_text = move(body_text);
|
||||||
data->image = CopyBitmap(image);
|
data->image = CopyBitmap(image);
|
||||||
|
|
||||||
// Enqueue new notification
|
// Enqueue new notification
|
||||||
|
@ -291,17 +291,17 @@ void DesktopNotificationController::CheckQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::CreateToast(NotificationLink&& data) {
|
void DesktopNotificationController::CreateToast(NotificationLink&& data) {
|
||||||
auto hInstance = RegisterWndClasses();
|
auto hinstance = RegisterWndClasses();
|
||||||
auto hwnd = Toast::Create(hInstance, data);
|
auto hwnd = Toast::Create(hinstance, data);
|
||||||
if (hwnd) {
|
if (hwnd) {
|
||||||
int toastPos = 0;
|
int toast_pos = 0;
|
||||||
if (!instances_.empty()) {
|
if (!instances_.empty()) {
|
||||||
auto& item = instances_.back();
|
auto& item = instances_.back();
|
||||||
_ASSERT(item.hwnd);
|
_ASSERT(item.hwnd);
|
||||||
|
|
||||||
ScreenMetrics scr;
|
ScreenMetrics scr;
|
||||||
auto toast = Toast::Get(item.hwnd);
|
auto toast = Toast::Get(item.hwnd);
|
||||||
toastPos = toast->GetVerticalPosition() +
|
toast_pos = toast->GetVerticalPosition() +
|
||||||
toast->GetHeight() +
|
toast->GetHeight() +
|
||||||
scr.Y(toast_margin_<int>);
|
scr.Y(toast_margin_<int>);
|
||||||
}
|
}
|
||||||
|
@ -313,11 +313,11 @@ void DesktopNotificationController::CreateToast(NotificationLink&& data) {
|
||||||
// receive system notifications
|
// receive system notifications
|
||||||
hwnd_controller_ = CreateWindow(class_name_, nullptr, 0,
|
hwnd_controller_ = CreateWindow(class_name_, nullptr, 0,
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
NULL, NULL, hInstance, this);
|
NULL, NULL, hinstance, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto toast = Toast::Get(hwnd);
|
auto toast = Toast::Get(hwnd);
|
||||||
toast->PopUp(toastPos);
|
toast->PopUp(toast_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ void DesktopNotificationController::Notification::Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::Notification::Set(
|
void DesktopNotificationController::Notification::Set(
|
||||||
std::wstring caption, std::wstring bodyText, HBITMAP image) {
|
std::wstring caption, std::wstring body_text, HBITMAP image) {
|
||||||
// No business calling this when not pointing to a valid instance
|
// No business calling this when not pointing to a valid instance
|
||||||
_ASSERT(data_);
|
_ASSERT(data_);
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ void DesktopNotificationController::Notification::Set(
|
||||||
if (data_->image) DeleteBitmap(data_->image);
|
if (data_->image) DeleteBitmap(data_->image);
|
||||||
|
|
||||||
data_->caption = move(caption);
|
data_->caption = move(caption);
|
||||||
data_->body_text = move(bodyText);
|
data_->body_text = move(body_text);
|
||||||
data_->image = CopyBitmap(image);
|
data_->image = CopyBitmap(image);
|
||||||
|
|
||||||
auto hwnd = data_->controller->GetToast(data_.get());
|
auto hwnd = data_->controller->GetToast(data_.get());
|
||||||
|
|
|
@ -11,11 +11,11 @@ struct NotificationData;
|
||||||
|
|
||||||
class DesktopNotificationController {
|
class DesktopNotificationController {
|
||||||
public:
|
public:
|
||||||
explicit DesktopNotificationController(unsigned maximumToasts = 3);
|
explicit DesktopNotificationController(unsigned maximum_toasts = 3);
|
||||||
~DesktopNotificationController();
|
~DesktopNotificationController();
|
||||||
|
|
||||||
class Notification;
|
class Notification;
|
||||||
Notification AddNotification(std::wstring caption, std::wstring bodyText,
|
Notification AddNotification(std::wstring caption, std::wstring body_text,
|
||||||
HBITMAP image);
|
HBITMAP image);
|
||||||
void CloseNotification(Notification& notification);
|
void CloseNotification(Notification& notification);
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ class DesktopNotificationController {
|
||||||
|
|
||||||
class Toast;
|
class Toast;
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
WPARAM wParam, LPARAM lParam);
|
WPARAM wparam, LPARAM lparam);
|
||||||
static DesktopNotificationController* Get(HWND hWnd) {
|
static DesktopNotificationController* Get(HWND hwnd) {
|
||||||
return reinterpret_cast<DesktopNotificationController*>(
|
return reinterpret_cast<DesktopNotificationController*>(
|
||||||
GetWindowLongPtr(hWnd, 0));
|
GetWindowLongPtr(hwnd, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController(
|
DesktopNotificationController(
|
||||||
|
@ -95,7 +95,7 @@ class DesktopNotificationController::Notification {
|
||||||
bool operator==(const Notification& other) const;
|
bool operator==(const Notification& other) const;
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
void Set(std::wstring caption, std::wstring bodyText, HBITMAP image);
|
void Set(std::wstring caption, std::wstring body_text, HBITMAP image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<NotificationData> data_;
|
std::shared_ptr<NotificationData> data_;
|
||||||
|
|
|
@ -67,11 +67,11 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
HBITMAP resultBitmap = NULL;
|
HBITMAP result_bitmap = NULL;
|
||||||
|
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdc_screen = GetDC(NULL);
|
||||||
|
|
||||||
HBITMAP alphaSrcBitmap;
|
HBITMAP alpha_src_bitmap;
|
||||||
{
|
{
|
||||||
BITMAPINFOHEADER bmi = { sizeof(BITMAPINFOHEADER) };
|
BITMAPINFOHEADER bmi = { sizeof(BITMAPINFOHEADER) };
|
||||||
bmi.biWidth = bm.bmWidth;
|
bmi.biWidth = bm.bmWidth;
|
||||||
|
@ -80,14 +80,13 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
bmi.biBitCount = bm.bmBitsPixel;
|
bmi.biBitCount = bm.bmBitsPixel;
|
||||||
bmi.biCompression = BI_RGB;
|
bmi.biCompression = BI_RGB;
|
||||||
|
|
||||||
void* alphaSrcBits;
|
void* alpha_src_bits;
|
||||||
alphaSrcBitmap = CreateDIBSection(NULL,
|
alpha_src_bitmap =
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
CreateDIBSection(NULL, reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS, &alphaSrcBits,
|
DIB_RGB_COLORS, &alpha_src_bits, NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
|
|
||||||
if (alphaSrcBitmap) {
|
if (alpha_src_bitmap) {
|
||||||
if (GetDIBits(hdcScreen, bitmap, 0, 0, 0,
|
if (GetDIBits(hdc_screen, bitmap, 0, 0, 0,
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS) &&
|
DIB_RGB_COLORS) &&
|
||||||
bmi.biSizeImage > 0 &&
|
bmi.biSizeImage > 0 &&
|
||||||
|
@ -96,7 +95,7 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
_aligned_malloc(bmi.biSizeImage, sizeof(DWORD)));
|
_aligned_malloc(bmi.biSizeImage, sizeof(DWORD)));
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
GetDIBits(hdcScreen, bitmap, 0, bm.bmHeight, buf,
|
GetDIBits(hdc_screen, bitmap, 0, bm.bmHeight, buf,
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS);
|
DIB_RGB_COLORS);
|
||||||
|
|
||||||
|
@ -104,7 +103,7 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
const DWORD *end =
|
const DWORD *end =
|
||||||
reinterpret_cast<DWORD*>(buf + bmi.biSizeImage);
|
reinterpret_cast<DWORD*>(buf + bmi.biSizeImage);
|
||||||
|
|
||||||
BYTE* dest = reinterpret_cast<BYTE*>(alphaSrcBits);
|
BYTE* dest = reinterpret_cast<BYTE*>(alpha_src_bits);
|
||||||
|
|
||||||
for (; src != end; ++src, ++dest) {
|
for (; src != end; ++src, ++dest) {
|
||||||
BYTE a = *src >> 24;
|
BYTE a = *src >> 24;
|
||||||
|
@ -119,7 +118,7 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alphaSrcBitmap) {
|
if (alpha_src_bitmap) {
|
||||||
BITMAPINFOHEADER bmi = { sizeof(BITMAPINFOHEADER) };
|
BITMAPINFOHEADER bmi = { sizeof(BITMAPINFOHEADER) };
|
||||||
bmi.biWidth = width;
|
bmi.biWidth = width;
|
||||||
bmi.biHeight = height;
|
bmi.biHeight = height;
|
||||||
|
@ -127,44 +126,42 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
bmi.biBitCount = 32;
|
bmi.biBitCount = 32;
|
||||||
bmi.biCompression = BI_RGB;
|
bmi.biCompression = BI_RGB;
|
||||||
|
|
||||||
void* colorBits;
|
void* color_bits;
|
||||||
auto colorBitmap = CreateDIBSection(NULL,
|
auto color_bitmap =
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
CreateDIBSection(NULL, reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS, &colorBits,
|
DIB_RGB_COLORS, &color_bits, NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
|
|
||||||
void* alphaBits;
|
void* alpha_bits;
|
||||||
auto alphaBitmap = CreateDIBSection(NULL,
|
auto alpha_bitmap =
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
CreateDIBSection(NULL, reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS, &alphaBits,
|
DIB_RGB_COLORS, &alpha_bits, NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
|
|
||||||
HDC hdc = CreateCompatibleDC(NULL);
|
HDC hdc = CreateCompatibleDC(NULL);
|
||||||
HDC hdcSrc = CreateCompatibleDC(NULL);
|
HDC hdc_src = CreateCompatibleDC(NULL);
|
||||||
|
|
||||||
if (colorBitmap && alphaBitmap && hdc && hdcSrc) {
|
if (color_bitmap && alpha_bitmap && hdc && hdc_src) {
|
||||||
SetStretchBltMode(hdc, HALFTONE);
|
SetStretchBltMode(hdc, HALFTONE);
|
||||||
|
|
||||||
// resize color channels
|
// resize color channels
|
||||||
SelectObject(hdc, colorBitmap);
|
SelectObject(hdc, color_bitmap);
|
||||||
SelectObject(hdcSrc, bitmap);
|
SelectObject(hdc_src, bitmap);
|
||||||
StretchBlt(hdc, 0, 0, width, height,
|
StretchBlt(hdc, 0, 0, width, height,
|
||||||
hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight,
|
hdc_src, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
SRCCOPY);
|
SRCCOPY);
|
||||||
|
|
||||||
// resize alpha channel
|
// resize alpha channel
|
||||||
SelectObject(hdc, alphaBitmap);
|
SelectObject(hdc, alpha_bitmap);
|
||||||
SelectObject(hdcSrc, alphaSrcBitmap);
|
SelectObject(hdc_src, alpha_src_bitmap);
|
||||||
StretchBlt(hdc, 0, 0, width, height,
|
StretchBlt(hdc, 0, 0, width, height,
|
||||||
hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight,
|
hdc_src, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
SRCCOPY);
|
SRCCOPY);
|
||||||
|
|
||||||
// flush before touching the bits
|
// flush before touching the bits
|
||||||
GdiFlush();
|
GdiFlush();
|
||||||
|
|
||||||
// apply the alpha channel
|
// apply the alpha channel
|
||||||
auto dest = reinterpret_cast<BYTE*>(colorBits);
|
auto dest = reinterpret_cast<BYTE*>(color_bits);
|
||||||
auto src = reinterpret_cast<const BYTE*>(alphaBits);
|
auto src = reinterpret_cast<const BYTE*>(alpha_bits);
|
||||||
auto end = src + (width * height * 4);
|
auto end = src + (width * height * 4);
|
||||||
while (src != end) {
|
while (src != end) {
|
||||||
dest[3] = src[0];
|
dest[3] = src[0];
|
||||||
|
@ -173,32 +170,32 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the resulting bitmap
|
// create the resulting bitmap
|
||||||
resultBitmap = CreateDIBitmap(hdcScreen, &bmi, CBM_INIT,
|
result_bitmap = CreateDIBitmap(hdc_screen, &bmi, CBM_INIT,
|
||||||
colorBits,
|
color_bits,
|
||||||
reinterpret_cast<BITMAPINFO*>(&bmi),
|
reinterpret_cast<BITMAPINFO*>(&bmi),
|
||||||
DIB_RGB_COLORS);
|
DIB_RGB_COLORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdcSrc) DeleteDC(hdcSrc);
|
if (hdc_src) DeleteDC(hdc_src);
|
||||||
if (hdc) DeleteDC(hdc);
|
if (hdc) DeleteDC(hdc);
|
||||||
|
|
||||||
if (alphaBitmap) DeleteObject(alphaBitmap);
|
if (alpha_bitmap) DeleteObject(alpha_bitmap);
|
||||||
if (colorBitmap) DeleteObject(colorBitmap);
|
if (color_bitmap) DeleteObject(color_bitmap);
|
||||||
|
|
||||||
DeleteObject(alphaSrcBitmap);
|
DeleteObject(alpha_src_bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdc_screen);
|
||||||
|
|
||||||
return resultBitmap;
|
return result_bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::Toast::Toast(
|
DesktopNotificationController::Toast::Toast(
|
||||||
HWND hWnd, shared_ptr<NotificationData>* data) :
|
HWND hwnd, shared_ptr<NotificationData>* data) :
|
||||||
hwnd_(hWnd), data_(*data) {
|
hwnd_(hwnd), data_(*data) {
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdc_screen = GetDC(NULL);
|
||||||
hdc_ = CreateCompatibleDC(hdcScreen);
|
hdc_ = CreateCompatibleDC(hdc_screen);
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdc_screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::Toast::~Toast() {
|
DesktopNotificationController::Toast::~Toast() {
|
||||||
|
@ -207,47 +204,47 @@ DesktopNotificationController::Toast::~Toast() {
|
||||||
if (scaled_image_) DeleteBitmap(scaled_image_);
|
if (scaled_image_) DeleteBitmap(scaled_image_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::Toast::Register(HINSTANCE hInstance) {
|
void DesktopNotificationController::Toast::Register(HINSTANCE hinstance) {
|
||||||
WNDCLASSEX wc = { sizeof(wc) };
|
WNDCLASSEX wc = { sizeof(wc) };
|
||||||
wc.lpfnWndProc = &Toast::WndProc;
|
wc.lpfnWndProc = &Toast::WndProc;
|
||||||
wc.lpszClassName = class_name_;
|
wc.lpszClassName = class_name_;
|
||||||
wc.cbWndExtra = sizeof(Toast*);
|
wc.cbWndExtra = sizeof(Toast*);
|
||||||
wc.hInstance = hInstance;
|
wc.hInstance = hinstance;
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
|
||||||
RegisterClassEx(&wc);
|
RegisterClassEx(&wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT DesktopNotificationController::Toast::WndProc(
|
LRESULT DesktopNotificationController::Toast::WndProc(
|
||||||
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
{
|
{
|
||||||
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lParam);
|
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lparam);
|
||||||
auto data =
|
auto data =
|
||||||
static_cast<shared_ptr<NotificationData>*>(cs->lpCreateParams);
|
static_cast<shared_ptr<NotificationData>*>(cs->lpCreateParams);
|
||||||
auto inst = new Toast(hWnd, data);
|
auto inst = new Toast(hwnd, data);
|
||||||
SetWindowLongPtr(hWnd, 0, (LONG_PTR)inst);
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)inst);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
delete Get(hWnd);
|
delete Get(hwnd);
|
||||||
SetWindowLongPtr(hWnd, 0, 0);
|
SetWindowLongPtr(hwnd, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_MOUSEACTIVATE:
|
case WM_MOUSEACTIVATE:
|
||||||
return MA_NOACTIVATE;
|
return MA_NOACTIVATE;
|
||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (wParam == TimerID_AutoDismiss) {
|
if (wparam == TimerID_AutoDismiss) {
|
||||||
Get(hWnd)->AutoDismiss();
|
Get(hwnd)->AutoDismiss();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_LBUTTONDOWN:
|
case WM_LBUTTONDOWN:
|
||||||
{
|
{
|
||||||
auto inst = Get(hWnd);
|
auto inst = Get(hwnd);
|
||||||
|
|
||||||
inst->Dismiss();
|
inst->Dismiss();
|
||||||
|
|
||||||
|
@ -261,15 +258,15 @@ LRESULT DesktopNotificationController::Toast::WndProc(
|
||||||
|
|
||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
{
|
{
|
||||||
auto inst = Get(hWnd);
|
auto inst = Get(hwnd);
|
||||||
if (!inst->is_highlighted_) {
|
if (!inst->is_highlighted_) {
|
||||||
inst->is_highlighted_ = true;
|
inst->is_highlighted_ = true;
|
||||||
|
|
||||||
TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hWnd };
|
TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hwnd };
|
||||||
TrackMouseEvent(&tme);
|
TrackMouseEvent(&tme);
|
||||||
}
|
}
|
||||||
|
|
||||||
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
POINT cursor = { GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
|
||||||
inst->is_close_hot_ =
|
inst->is_close_hot_ =
|
||||||
(PtInRect(&inst->close_button_rect_, cursor) != FALSE);
|
(PtInRect(&inst->close_button_rect_, cursor) != FALSE);
|
||||||
|
|
||||||
|
@ -282,7 +279,7 @@ LRESULT DesktopNotificationController::Toast::WndProc(
|
||||||
|
|
||||||
case WM_MOUSELEAVE:
|
case WM_MOUSELEAVE:
|
||||||
{
|
{
|
||||||
auto inst = Get(hWnd);
|
auto inst = Get(hwnd);
|
||||||
inst->is_highlighted_ = false;
|
inst->is_highlighted_ = false;
|
||||||
inst->is_close_hot_ = false;
|
inst->is_close_hot_ = false;
|
||||||
inst->UpdateContents();
|
inst->UpdateContents();
|
||||||
|
@ -297,80 +294,80 @@ LRESULT DesktopNotificationController::Toast::WndProc(
|
||||||
|
|
||||||
case WM_WINDOWPOSCHANGED:
|
case WM_WINDOWPOSCHANGED:
|
||||||
{
|
{
|
||||||
auto& wp = reinterpret_cast<WINDOWPOS*&>(lParam);
|
auto& wp = reinterpret_cast<WINDOWPOS*&>(lparam);
|
||||||
if (wp->flags & SWP_HIDEWINDOW) {
|
if (wp->flags & SWP_HIDEWINDOW) {
|
||||||
if (!IsWindowVisible(hWnd))
|
if (!IsWindowVisible(hwnd))
|
||||||
Get(hWnd)->is_highlighted_ = false;
|
Get(hwnd)->is_highlighted_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND DesktopNotificationController::Toast::Create(
|
HWND DesktopNotificationController::Toast::Create(
|
||||||
HINSTANCE hInstance, shared_ptr<NotificationData>& data) {
|
HINSTANCE hinstance, shared_ptr<NotificationData>& data) {
|
||||||
return CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST,
|
return CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST,
|
||||||
class_name_, nullptr, WS_POPUP, 0, 0, 0, 0,
|
class_name_, nullptr, WS_POPUP, 0, 0, 0, 0,
|
||||||
NULL, NULL, hInstance, &data);
|
NULL, NULL, hinstance, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::Toast::Draw() {
|
void DesktopNotificationController::Toast::Draw() {
|
||||||
const COLORREF accent = GetAccentColor();
|
const COLORREF accent = GetAccentColor();
|
||||||
|
|
||||||
COLORREF backColor;
|
COLORREF back_color;
|
||||||
{
|
{
|
||||||
// base background color is 2/3 of accent
|
// base background color is 2/3 of accent
|
||||||
// highlighted adds a bit of intensity to every channel
|
// highlighted adds a bit of intensity to every channel
|
||||||
|
|
||||||
int h = is_highlighted_ ? (0xff / 20) : 0;
|
int h = is_highlighted_ ? (0xff / 20) : 0;
|
||||||
|
|
||||||
backColor = RGB(min(0xff, (GetRValue(accent) * 2 / 3) + h),
|
back_color = RGB(min(0xff, (GetRValue(accent) * 2 / 3) + h),
|
||||||
min(0xff, (GetGValue(accent) * 2 / 3) + h),
|
min(0xff, (GetGValue(accent) * 2 / 3) + h),
|
||||||
min(0xff, (GetBValue(accent) * 2 / 3) + h));
|
min(0xff, (GetBValue(accent) * 2 / 3) + h));
|
||||||
}
|
}
|
||||||
|
|
||||||
const float backLuma =
|
const float back_luma =
|
||||||
(GetRValue(backColor) * 0.299f / 255) +
|
(GetRValue(back_color) * 0.299f / 255) +
|
||||||
(GetGValue(backColor) * 0.587f / 255) +
|
(GetGValue(back_color) * 0.587f / 255) +
|
||||||
(GetBValue(backColor) * 0.114f / 255);
|
(GetBValue(back_color) * 0.114f / 255);
|
||||||
|
|
||||||
const struct { float r, g, b; } backF = {
|
const struct { float r, g, b; } back_f = {
|
||||||
GetRValue(backColor) / 255.0f,
|
GetRValue(back_color) / 255.0f,
|
||||||
GetGValue(backColor) / 255.0f,
|
GetGValue(back_color) / 255.0f,
|
||||||
GetBValue(backColor) / 255.0f,
|
GetBValue(back_color) / 255.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
COLORREF foreColor, dimmedColor;
|
COLORREF fore_color, dimmed_color;
|
||||||
{
|
{
|
||||||
// based on the lightness of background, we draw foreground in light
|
// based on the lightness of background, we draw foreground in light
|
||||||
// or dark shades of gray blended onto the background with slight
|
// or dark shades of gray blended onto the background with slight
|
||||||
// transparency to avoid sharp contrast
|
// transparency to avoid sharp contrast
|
||||||
|
|
||||||
constexpr float alpha = 0.9f;
|
constexpr float alpha = 0.9f;
|
||||||
constexpr float intensityLight[] = { (1.0f * alpha), (0.8f * alpha) };
|
constexpr float intensity_light[] = { (1.0f * alpha), (0.8f * alpha) };
|
||||||
constexpr float intensityDark[] = { (0.1f * alpha), (0.3f * alpha) };
|
constexpr float intensity_dark[] = { (0.1f * alpha), (0.3f * alpha) };
|
||||||
|
|
||||||
// select foreground intensity values (light or dark)
|
// select foreground intensity values (light or dark)
|
||||||
auto& i = (backLuma < 0.6f) ? intensityLight : intensityDark;
|
auto& i = (back_luma < 0.6f) ? intensity_light : intensity_dark;
|
||||||
|
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
|
|
||||||
r = i[0] + backF.r * (1 - alpha);
|
r = i[0] + back_f.r * (1 - alpha);
|
||||||
g = i[0] + backF.g * (1 - alpha);
|
g = i[0] + back_f.g * (1 - alpha);
|
||||||
b = i[0] + backF.b * (1 - alpha);
|
b = i[0] + back_f.b * (1 - alpha);
|
||||||
foreColor = RGB(r * 0xff, g * 0xff, b * 0xff);
|
fore_color = RGB(r * 0xff, g * 0xff, b * 0xff);
|
||||||
|
|
||||||
r = i[1] + backF.r * (1 - alpha);
|
r = i[1] + back_f.r * (1 - alpha);
|
||||||
g = i[1] + backF.g * (1 - alpha);
|
g = i[1] + back_f.g * (1 - alpha);
|
||||||
b = i[1] + backF.b * (1 - alpha);
|
b = i[1] + back_f.b * (1 - alpha);
|
||||||
dimmedColor = RGB(r * 0xff, g * 0xff, b * 0xff);
|
dimmed_color = RGB(r * 0xff, g * 0xff, b * 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
{
|
{
|
||||||
auto brush = CreateSolidBrush(backColor);
|
auto brush = CreateSolidBrush(back_color);
|
||||||
|
|
||||||
RECT rc = { 0, 0, toast_size_.cx, toast_size_.cy };
|
RECT rc = { 0, 0, toast_size_.cx, toast_size_.cy };
|
||||||
FillRect(hdc_, &rc, brush);
|
FillRect(hdc_, &rc, brush);
|
||||||
|
@ -381,24 +378,24 @@ void DesktopNotificationController::Toast::Draw() {
|
||||||
SetBkMode(hdc_, TRANSPARENT);
|
SetBkMode(hdc_, TRANSPARENT);
|
||||||
|
|
||||||
const auto close = L'\x2715';
|
const auto close = L'\x2715';
|
||||||
auto captionFont = data_->controller->GetCaptionFont();
|
auto caption_font = data_->controller->GetCaptionFont();
|
||||||
auto bodyFont = data_->controller->GetBodyFont();
|
auto body_font = data_->controller->GetBodyFont();
|
||||||
|
|
||||||
TEXTMETRIC tmCap;
|
TEXTMETRIC tm_cap;
|
||||||
SelectFont(hdc_, captionFont);
|
SelectFont(hdc_, caption_font);
|
||||||
GetTextMetrics(hdc_, &tmCap);
|
GetTextMetrics(hdc_, &tm_cap);
|
||||||
|
|
||||||
auto textOffsetX = margin_.cx;
|
auto text_offset_x = margin_.cx;
|
||||||
|
|
||||||
BITMAP imageInfo = {};
|
BITMAP image_info = {};
|
||||||
if (scaled_image_) {
|
if (scaled_image_) {
|
||||||
GetObject(scaled_image_, sizeof(imageInfo), &imageInfo);
|
GetObject(scaled_image_, sizeof(image_info), &image_info);
|
||||||
|
|
||||||
textOffsetX += margin_.cx + imageInfo.bmWidth;
|
text_offset_x += margin_.cx + image_info.bmWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate close button rect
|
// calculate close button rect
|
||||||
POINT closePos;
|
POINT close_pos;
|
||||||
{
|
{
|
||||||
SIZE extent = {};
|
SIZE extent = {};
|
||||||
GetTextExtentPoint32W(hdc_, &close, 1, &extent);
|
GetTextExtentPoint32W(hdc_, &close, 1, &extent);
|
||||||
|
@ -406,37 +403,37 @@ void DesktopNotificationController::Toast::Draw() {
|
||||||
close_button_rect_.right = toast_size_.cx;
|
close_button_rect_.right = toast_size_.cx;
|
||||||
close_button_rect_.top = 0;
|
close_button_rect_.top = 0;
|
||||||
|
|
||||||
closePos.x = close_button_rect_.right - margin_.cy - extent.cx;
|
close_pos.x = close_button_rect_.right - margin_.cy - extent.cx;
|
||||||
closePos.y = close_button_rect_.top + margin_.cy;
|
close_pos.y = close_button_rect_.top + margin_.cy;
|
||||||
|
|
||||||
close_button_rect_.left = closePos.x - margin_.cy;
|
close_button_rect_.left = close_pos.x - margin_.cy;
|
||||||
close_button_rect_.bottom = closePos.y + extent.cy + margin_.cy;
|
close_button_rect_.bottom = close_pos.y + extent.cy + margin_.cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// image
|
// image
|
||||||
if (scaled_image_) {
|
if (scaled_image_) {
|
||||||
HDC hdcImage = CreateCompatibleDC(NULL);
|
HDC hdc_image = CreateCompatibleDC(NULL);
|
||||||
SelectBitmap(hdcImage, scaled_image_);
|
SelectBitmap(hdc_image, scaled_image_);
|
||||||
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||||
AlphaBlend(hdc_, margin_.cx, margin_.cy,
|
AlphaBlend(hdc_, margin_.cx, margin_.cy,
|
||||||
imageInfo.bmWidth, imageInfo.bmHeight,
|
image_info.bmWidth, image_info.bmHeight,
|
||||||
hdcImage, 0, 0,
|
hdc_image, 0, 0,
|
||||||
imageInfo.bmWidth, imageInfo.bmHeight,
|
image_info.bmWidth, image_info.bmHeight,
|
||||||
blend);
|
blend);
|
||||||
DeleteDC(hdcImage);
|
DeleteDC(hdc_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// caption
|
// caption
|
||||||
{
|
{
|
||||||
RECT rc = {
|
RECT rc = {
|
||||||
textOffsetX,
|
text_offset_x,
|
||||||
margin_.cy,
|
margin_.cy,
|
||||||
close_button_rect_.left,
|
close_button_rect_.left,
|
||||||
toast_size_.cy
|
toast_size_.cy
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectFont(hdc_, captionFont);
|
SelectFont(hdc_, caption_font);
|
||||||
SetTextColor(hdc_, foreColor);
|
SetTextColor(hdc_, fore_color);
|
||||||
DrawText(hdc_, data_->caption.data(), (UINT)data_->caption.length(),
|
DrawText(hdc_, data_->caption.data(), (UINT)data_->caption.length(),
|
||||||
&rc, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
|
&rc, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
|
||||||
}
|
}
|
||||||
|
@ -444,14 +441,14 @@ void DesktopNotificationController::Toast::Draw() {
|
||||||
// body text
|
// body text
|
||||||
if (!data_->body_text.empty()) {
|
if (!data_->body_text.empty()) {
|
||||||
RECT rc = {
|
RECT rc = {
|
||||||
textOffsetX,
|
text_offset_x,
|
||||||
2 * margin_.cy + tmCap.tmAscent,
|
2 * margin_.cy + tm_cap.tmAscent,
|
||||||
toast_size_.cx - margin_.cx,
|
toast_size_.cx - margin_.cx,
|
||||||
toast_size_.cy - margin_.cy
|
toast_size_.cy - margin_.cy
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectFont(hdc_, bodyFont);
|
SelectFont(hdc_, body_font);
|
||||||
SetTextColor(hdc_, dimmedColor);
|
SetTextColor(hdc_, dimmed_color);
|
||||||
DrawText(hdc_, data_->body_text.data(), (UINT)data_->body_text.length(),
|
DrawText(hdc_, data_->body_text.data(), (UINT)data_->body_text.length(),
|
||||||
&rc,
|
&rc,
|
||||||
DT_LEFT | DT_WORDBREAK | DT_NOPREFIX |
|
DT_LEFT | DT_WORDBREAK | DT_NOPREFIX |
|
||||||
|
@ -460,9 +457,9 @@ void DesktopNotificationController::Toast::Draw() {
|
||||||
|
|
||||||
// close button
|
// close button
|
||||||
{
|
{
|
||||||
SelectFont(hdc_, captionFont);
|
SelectFont(hdc_, caption_font);
|
||||||
SetTextColor(hdc_, is_close_hot_ ? foreColor : dimmedColor);
|
SetTextColor(hdc_, is_close_hot_ ? fore_color : dimmed_color);
|
||||||
ExtTextOut(hdc_, closePos.x, closePos.y, 0, nullptr,
|
ExtTextOut(hdc_, close_pos.x, close_pos.y, 0, nullptr,
|
||||||
&close, 1, nullptr);
|
&close, 1, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,87 +476,90 @@ bool DesktopNotificationController::Toast::IsRedrawNeeded() const {
|
||||||
|
|
||||||
void DesktopNotificationController::Toast::UpdateBufferSize() {
|
void DesktopNotificationController::Toast::UpdateBufferSize() {
|
||||||
if (hdc_) {
|
if (hdc_) {
|
||||||
SIZE newSize;
|
SIZE new_size;
|
||||||
{
|
{
|
||||||
TEXTMETRIC tmCap = {};
|
TEXTMETRIC tm_cap = {};
|
||||||
HFONT font = data_->controller->GetCaptionFont();
|
HFONT font = data_->controller->GetCaptionFont();
|
||||||
if (font) {
|
if (font) {
|
||||||
SelectFont(hdc_, font);
|
SelectFont(hdc_, font);
|
||||||
if (!GetTextMetrics(hdc_, &tmCap)) return;
|
if (!GetTextMetrics(hdc_, &tm_cap)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEXTMETRIC tmBody = {};
|
TEXTMETRIC tm_body = {};
|
||||||
font = data_->controller->GetBodyFont();
|
font = data_->controller->GetBodyFont();
|
||||||
if (font) {
|
if (font) {
|
||||||
SelectFont(hdc_, font);
|
SelectFont(hdc_, font);
|
||||||
if (!GetTextMetrics(hdc_, &tmBody)) return;
|
if (!GetTextMetrics(hdc_, &tm_body)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->margin_ = { tmCap.tmAveCharWidth * 2, tmCap.tmAscent / 2 };
|
this->margin_ = { tm_cap.tmAveCharWidth * 2, tm_cap.tmAscent / 2 };
|
||||||
|
|
||||||
newSize.cx = margin_.cx + (32 * tmCap.tmAveCharWidth) + margin_.cx;
|
new_size.cx =
|
||||||
newSize.cy = margin_.cy + (tmCap.tmHeight) + margin_.cy;
|
margin_.cx + (32 * tm_cap.tmAveCharWidth) + margin_.cx;
|
||||||
|
new_size.cy =
|
||||||
|
margin_.cy + (tm_cap.tmHeight) + margin_.cy;
|
||||||
|
|
||||||
if (!data_->body_text.empty())
|
if (!data_->body_text.empty())
|
||||||
newSize.cy += margin_.cy + (3 * tmBody.tmHeight);
|
new_size.cy += margin_.cy + (3 * tm_body.tmHeight);
|
||||||
|
|
||||||
if (data_->image) {
|
if (data_->image) {
|
||||||
BITMAP bm;
|
BITMAP bm;
|
||||||
if (GetObject(data_->image, sizeof(bm), &bm)) {
|
if (GetObject(data_->image, sizeof(bm), &bm)) {
|
||||||
// cap the image size
|
// cap the image size
|
||||||
const int maxDimSize = 80;
|
const int max_dim_size = 80;
|
||||||
|
|
||||||
auto width = bm.bmWidth;
|
auto width = bm.bmWidth;
|
||||||
auto height = bm.bmHeight;
|
auto height = bm.bmHeight;
|
||||||
if (width < height) {
|
if (width < height) {
|
||||||
if (height > maxDimSize) {
|
if (height > max_dim_size) {
|
||||||
width = width * maxDimSize / height;
|
width = width * max_dim_size / height;
|
||||||
height = maxDimSize;
|
height = max_dim_size;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (width > maxDimSize) {
|
if (width > max_dim_size) {
|
||||||
height = height * maxDimSize / width;
|
height = height * max_dim_size / width;
|
||||||
width = maxDimSize;
|
width = max_dim_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenMetrics scr;
|
ScreenMetrics scr;
|
||||||
SIZE imageDrawSize = { scr.X(width), scr.Y(height) };
|
SIZE image_draw_size = { scr.X(width), scr.Y(height) };
|
||||||
|
|
||||||
newSize.cx += imageDrawSize.cx + margin_.cx;
|
new_size.cx += image_draw_size.cx + margin_.cx;
|
||||||
|
|
||||||
auto heightWithImage =
|
auto height_with_image =
|
||||||
margin_.cy + (imageDrawSize.cy) + margin_.cy;
|
margin_.cy + (image_draw_size.cy) + margin_.cy;
|
||||||
if (newSize.cy < heightWithImage)
|
|
||||||
newSize.cy = heightWithImage;
|
|
||||||
|
|
||||||
UpdateScaledImage(imageDrawSize);
|
if (new_size.cy < height_with_image)
|
||||||
|
new_size.cy = height_with_image;
|
||||||
|
|
||||||
|
UpdateScaledImage(image_draw_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newSize.cx != this->toast_size_.cx ||
|
if (new_size.cx != this->toast_size_.cx ||
|
||||||
newSize.cy != this->toast_size_.cy) {
|
new_size.cy != this->toast_size_.cy) {
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdc_screen = GetDC(NULL);
|
||||||
auto newBitmap = CreateCompatibleBitmap(hdcScreen,
|
auto new_bitmap = CreateCompatibleBitmap(hdc_screen,
|
||||||
newSize.cx, newSize.cy);
|
new_size.cx, new_size.cy);
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdc_screen);
|
||||||
|
|
||||||
if (newBitmap) {
|
if (new_bitmap) {
|
||||||
if (SelectBitmap(hdc_, newBitmap)) {
|
if (SelectBitmap(hdc_, new_bitmap)) {
|
||||||
RECT dirty1 = {}, dirty2 = {};
|
RECT dirty1 = {}, dirty2 = {};
|
||||||
if (toast_size_.cx < newSize.cx) {
|
if (toast_size_.cx < new_size.cx) {
|
||||||
dirty1 = { toast_size_.cx, 0,
|
dirty1 = { toast_size_.cx, 0,
|
||||||
newSize.cx, toast_size_.cy };
|
new_size.cx, toast_size_.cy };
|
||||||
}
|
}
|
||||||
if (toast_size_.cy < newSize.cy) {
|
if (toast_size_.cy < new_size.cy) {
|
||||||
dirty2 = { 0, toast_size_.cy,
|
dirty2 = { 0, toast_size_.cy,
|
||||||
newSize.cx, newSize.cy };
|
new_size.cx, new_size.cy };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->bitmap_) DeleteBitmap(this->bitmap_);
|
if (this->bitmap_) DeleteBitmap(this->bitmap_);
|
||||||
this->bitmap_ = newBitmap;
|
this->bitmap_ = new_bitmap;
|
||||||
this->toast_size_ = newSize;
|
this->toast_size_ = new_size;
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@ void DesktopNotificationController::Toast::UpdateBufferSize() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteBitmap(newBitmap);
|
DeleteBitmap(new_bitmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -680,7 +680,7 @@ HDWP DesktopNotificationController::Toast::Animate(
|
||||||
if (IsRedrawNeeded())
|
if (IsRedrawNeeded())
|
||||||
Draw();
|
Draw();
|
||||||
|
|
||||||
POINT srcOrigin = { 0, 0 };
|
POINT src_origin = { 0, 0 };
|
||||||
|
|
||||||
UPDATELAYEREDWINDOWINFO ulw;
|
UPDATELAYEREDWINDOWINFO ulw;
|
||||||
ulw.cbSize = sizeof(ulw);
|
ulw.cbSize = sizeof(ulw);
|
||||||
|
@ -688,7 +688,7 @@ HDWP DesktopNotificationController::Toast::Animate(
|
||||||
ulw.pptDst = nullptr;
|
ulw.pptDst = nullptr;
|
||||||
ulw.psize = nullptr;
|
ulw.psize = nullptr;
|
||||||
ulw.hdcSrc = hdc_;
|
ulw.hdcSrc = hdc_;
|
||||||
ulw.pptSrc = &srcOrigin;
|
ulw.pptSrc = &src_origin;
|
||||||
ulw.crKey = 0;
|
ulw.crKey = 0;
|
||||||
ulw.pblend = nullptr;
|
ulw.pblend = nullptr;
|
||||||
ulw.dwFlags = 0;
|
ulw.dwFlags = 0;
|
||||||
|
@ -700,41 +700,41 @@ HDWP DesktopNotificationController::Toast::Animate(
|
||||||
UINT dwpFlags = SWP_NOACTIVATE | SWP_SHOWWINDOW |
|
UINT dwpFlags = SWP_NOACTIVATE | SWP_SHOWWINDOW |
|
||||||
SWP_NOREDRAW | SWP_NOCOPYBITS;
|
SWP_NOREDRAW | SWP_NOCOPYBITS;
|
||||||
|
|
||||||
auto easeInPos = AnimateEaseIn();
|
auto ease_in_pos = AnimateEaseIn();
|
||||||
auto easeOutPos = AnimateEaseOut();
|
auto ease_out_pos = AnimateEaseOut();
|
||||||
auto stackCollapsePos = AnimateStackCollapse();
|
auto stack_collapse_pos = AnimateStackCollapse();
|
||||||
|
|
||||||
auto yOffset = (vertical_pos_target_ - vertical_pos_) * stackCollapsePos;
|
auto y_offset = (vertical_pos_target_ - vertical_pos_) * stack_collapse_pos;
|
||||||
|
|
||||||
size.cx = static_cast<int>(toast_size_.cx * easeInPos);
|
size.cx = static_cast<int>(toast_size_.cx * ease_in_pos);
|
||||||
size.cy = toast_size_.cy;
|
size.cy = toast_size_.cy;
|
||||||
|
|
||||||
pt.x = origin.x - size.cx;
|
pt.x = origin.x - size.cx;
|
||||||
pt.y = static_cast<int>(origin.y - vertical_pos_ - yOffset - size.cy);
|
pt.y = static_cast<int>(origin.y - vertical_pos_ - y_offset - size.cy);
|
||||||
|
|
||||||
ulw.pptDst = &pt;
|
ulw.pptDst = &pt;
|
||||||
ulw.psize = &size;
|
ulw.psize = &size;
|
||||||
|
|
||||||
if (ease_in_active_ && easeInPos == 1.0f) {
|
if (ease_in_active_ && ease_in_pos == 1.0f) {
|
||||||
ease_in_active_ = false;
|
ease_in_active_ = false;
|
||||||
ScheduleDismissal();
|
ScheduleDismissal();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->ease_in_pos_ = easeInPos;
|
this->ease_in_pos_ = ease_in_pos;
|
||||||
this->stack_collapse_pos_ = stackCollapsePos;
|
this->stack_collapse_pos_ = stack_collapse_pos;
|
||||||
|
|
||||||
if (easeOutPos != this->ease_out_pos_) {
|
if (ease_out_pos != this->ease_out_pos_) {
|
||||||
blend.BlendOp = AC_SRC_OVER;
|
blend.BlendOp = AC_SRC_OVER;
|
||||||
blend.BlendFlags = 0;
|
blend.BlendFlags = 0;
|
||||||
blend.SourceConstantAlpha = (BYTE)(255 * (1.0f - easeOutPos));
|
blend.SourceConstantAlpha = (BYTE)(255 * (1.0f - ease_out_pos));
|
||||||
blend.AlphaFormat = 0;
|
blend.AlphaFormat = 0;
|
||||||
|
|
||||||
ulw.pblend = &blend;
|
ulw.pblend = &blend;
|
||||||
ulw.dwFlags = ULW_ALPHA;
|
ulw.dwFlags = ULW_ALPHA;
|
||||||
|
|
||||||
this->ease_out_pos_ = easeOutPos;
|
this->ease_out_pos_ = ease_out_pos;
|
||||||
|
|
||||||
if (easeOutPos == 1.0f) {
|
if (ease_out_pos == 1.0f) {
|
||||||
ease_out_active_ = false;
|
ease_out_active_ = false;
|
||||||
|
|
||||||
dwpFlags &= ~SWP_SHOWWINDOW;
|
dwpFlags &= ~SWP_SHOWWINDOW;
|
||||||
|
@ -742,7 +742,7 @@ HDWP DesktopNotificationController::Toast::Animate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackCollapsePos == 1.0f) {
|
if (stack_collapse_pos == 1.0f) {
|
||||||
vertical_pos_ = vertical_pos_target_;
|
vertical_pos_ = vertical_pos_target_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +751,7 @@ HDWP DesktopNotificationController::Toast::Animate(
|
||||||
// ULWI fails, which can happen when one of the dimensions is zero (e.g.
|
// ULWI fails, which can happen when one of the dimensions is zero (e.g.
|
||||||
// at the beginning of ease-in).
|
// at the beginning of ease-in).
|
||||||
|
|
||||||
auto ulwResult = UpdateLayeredWindowIndirect(hwnd_, &ulw);
|
auto ulw_result = UpdateLayeredWindowIndirect(hwnd_, &ulw);
|
||||||
hdwp = DeferWindowPos(hdwp, hwnd_, HWND_TOPMOST,
|
hdwp = DeferWindowPos(hdwp, hwnd_, HWND_TOPMOST,
|
||||||
pt.x, pt.y, size.cx, size.cy, dwpFlags);
|
pt.x, pt.y, size.cx, size.cy, dwpFlags);
|
||||||
return hdwp;
|
return hdwp;
|
||||||
|
|
|
@ -5,15 +5,15 @@ namespace brightray {
|
||||||
|
|
||||||
class DesktopNotificationController::Toast {
|
class DesktopNotificationController::Toast {
|
||||||
public:
|
public:
|
||||||
static void Register(HINSTANCE hInstance);
|
static void Register(HINSTANCE hinstance);
|
||||||
static HWND Create(HINSTANCE hInstance,
|
static HWND Create(HINSTANCE hinstance,
|
||||||
std::shared_ptr<NotificationData>& data);
|
std::shared_ptr<NotificationData>& data);
|
||||||
static Toast* Get(HWND hWnd) {
|
static Toast* Get(HWND hwnd) {
|
||||||
return reinterpret_cast<Toast*>(GetWindowLongPtr(hWnd, 0));
|
return reinterpret_cast<Toast*>(GetWindowLongPtr(hwnd, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
WPARAM wParam, LPARAM lParam);
|
WPARAM wparam, LPARAM lparam);
|
||||||
|
|
||||||
const std::shared_ptr<NotificationData>& GetNotification() const {
|
const std::shared_ptr<NotificationData>& GetNotification() const {
|
||||||
return data_;
|
return data_;
|
||||||
|
@ -45,7 +45,7 @@ class DesktopNotificationController::Toast {
|
||||||
TimerID_AutoDismiss = 1
|
TimerID_AutoDismiss = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
Toast(HWND hWnd, std::shared_ptr<NotificationData>* data);
|
Toast(HWND hwnd, std::shared_ptr<NotificationData>* data);
|
||||||
~Toast();
|
~Toast();
|
||||||
|
|
||||||
void UpdateBufferSize();
|
void UpdateBufferSize();
|
||||||
|
|
Loading…
Reference in a new issue