Introduce ZoneWindowDrawing files and move stuff to better place (#6142)

This commit is contained in:
stefansjfw 2020-08-25 18:55:29 +02:00 committed by GitHub
parent 2075f9fa71
commit 48b6654ad2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 240 deletions

View file

@ -17,19 +17,6 @@ namespace localized_strings
const wchar_t LAST_ERROR_TITLE_STRING[] = L"Error";
}
std::optional<RECT> get_button_pos(HWND hwnd)
{
RECT button;
if (DwmGetWindowAttribute(hwnd, DWMWA_CAPTION_BUTTON_BOUNDS, &button, sizeof(RECT)) == S_OK)
{
return button;
}
else
{
return {};
}
}
std::optional<RECT> get_window_pos(HWND hwnd)
{
RECT window;
@ -43,19 +30,6 @@ std::optional<RECT> get_window_pos(HWND hwnd)
}
}
std::optional<POINT> get_mouse_pos()
{
POINT point;
if (GetCursorPos(&point) == 0)
{
return {};
}
else
{
return point;
}
}
bool is_system_window(HWND hwnd, const char* class_name)
{
// We compare the HWND against HWND of the desktop and shell windows,
@ -79,74 +53,6 @@ bool is_system_window(HWND hwnd, const char* class_name)
return false;
}
int width(const RECT& rect)
{
return rect.right - rect.left;
}
int height(const RECT& rect)
{
return rect.bottom - rect.top;
}
bool operator<(const RECT& lhs, const RECT& rhs)
{
auto lhs_tuple = std::make_tuple(lhs.left, lhs.right, lhs.top, lhs.bottom);
auto rhs_tuple = std::make_tuple(rhs.left, rhs.right, rhs.top, rhs.bottom);
return lhs_tuple < rhs_tuple;
}
RECT keep_rect_inside_rect(const RECT& small_rect, const RECT& big_rect)
{
RECT result = small_rect;
if ((result.right - result.left) > (big_rect.right - big_rect.left))
{
// small_rect is too big horizontally. resize it.
result.right = big_rect.right;
result.left = big_rect.left;
}
else
{
if (result.right > big_rect.right)
{
// move the rect left.
result.left -= result.right - big_rect.right;
result.right -= result.right - big_rect.right;
}
if (result.left < big_rect.left)
{
// move the rect right.
result.right += big_rect.left - result.left;
result.left += big_rect.left - result.left;
}
}
if ((result.bottom - result.top) > (big_rect.bottom - big_rect.top))
{
// small_rect is too big vertically. resize it.
result.bottom = big_rect.bottom;
result.top = big_rect.top;
}
else
{
if (result.bottom > big_rect.bottom)
{
// move the rect up.
result.top -= result.bottom - big_rect.bottom;
result.bottom -= result.bottom - big_rect.bottom;
}
if (result.top < big_rect.top)
{
// move the rect down.
result.bottom += big_rect.top - result.top;
result.top += big_rect.top - result.top;
}
}
return result;
}
int run_message_loop(const bool until_idle, const std::optional<uint32_t> timeout_seconds)
{
MSG msg;

View file

@ -6,23 +6,12 @@
#include <memory>
#include <vector>
// Returns RECT with positions of the minimize/maximize buttons of the given window.
// Does not always work, since some apps draw custom toolbars.
std::optional<RECT> get_button_pos(HWND hwnd);
// Gets position of given window.
std::optional<RECT> get_window_pos(HWND hwnd);
// Gets mouse position.
std::optional<POINT> get_mouse_pos();
// Check if window is part of the shell or the taskbar.
bool is_system_window(HWND hwnd, const char* class_name);
// Calculate sizes
int width(const RECT& rect);
int height(const RECT& rect);
// Compare rects
bool operator<(const RECT& lhs, const RECT& rhs);
// Moves and/or resizes small_rect to fit inside big_rect.
RECT keep_rect_inside_rect(const RECT& small_rect, const RECT& big_rect);
// Initializes and runs windows message loop
int run_message_loop(const bool until_idle = false, const std::optional<uint32_t> timeout_seconds = {});
@ -107,5 +96,3 @@ struct overloaded : Ts...
};
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
#define POWER_LAUNCHER_PID_SHARED_FILE L"Local\\3cbfbad4-199b-4e2c-9825-942d5d3d3c74"

View file

@ -4,6 +4,16 @@
#include "common.h"
namespace
{
bool operator<(const RECT& lhs, const RECT& rhs)
{
auto lhs_tuple = std::make_tuple(lhs.left, lhs.right, lhs.top, lhs.bottom);
auto rhs_tuple = std::make_tuple(rhs.left, rhs.right, rhs.top, rhs.bottom);
return lhs_tuple < rhs_tuple;
}
}
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs)
{
auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom);

View file

@ -123,6 +123,7 @@
<ClInclude Include="Zone.h" />
<ClInclude Include="ZoneSet.h" />
<ClInclude Include="ZoneWindow.h" />
<ClInclude Include="ZoneWindowDrawing.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="FancyZones.cpp" />
@ -143,6 +144,7 @@
<ClCompile Include="Zone.cpp" />
<ClCompile Include="ZoneSet.cpp" />
<ClCompile Include="ZoneWindow.cpp" />
<ClCompile Include="ZoneWindowDrawing.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="fancyzones.base.rc" />

View file

@ -74,6 +74,9 @@
<ClInclude Include="KeyState.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ZoneWindowDrawing.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -124,6 +127,9 @@
<ClCompile Include="FancyZonesDataTypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ZoneWindowDrawing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View file

@ -5,6 +5,7 @@
#include "FancyZonesData.h"
#include "FancyZonesDataTypes.h"
#include "ZoneWindow.h"
#include "ZoneWindowDrawing.h"
#include "trace.h"
#include "util.h"
#include "Settings.h"
@ -18,7 +19,6 @@
// Non-Localizable strings
namespace NonLocalizable
{
const wchar_t SegoeUiFont[] = L"Segoe ui";
const wchar_t ToolWindowClassName[] = L"SuperFancyZones_ZoneWindow";
}
@ -60,135 +60,6 @@ namespace ZoneWindowUtils
}
}
namespace ZoneWindowDrawUtils
{
struct ColorSetting
{
BYTE fillAlpha{};
COLORREF fill{};
BYTE borderAlpha{};
COLORREF border{};
int thickness{};
};
void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept
{
FillRectARGB(hdc, &clientRect, 0, RGB(0, 0, 0), false);
}
void DrawIndex(wil::unique_hdc& hdc, Rect rect, size_t index)
{
Gdiplus::Graphics g(hdc.get());
Gdiplus::FontFamily fontFamily(NonLocalizable::SegoeUiFont);
Gdiplus::Font font(&fontFamily, 80, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel);
Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 0, 0));
std::wstring text = std::to_wstring(index);
g.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
Gdiplus::StringFormat stringFormat = new Gdiplus::StringFormat();
stringFormat.SetAlignment(Gdiplus::StringAlignmentCenter);
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentCenter);
Gdiplus::RectF gdiRect(static_cast<Gdiplus::REAL>(rect.left()),
static_cast<Gdiplus::REAL>(rect.top()),
static_cast<Gdiplus::REAL>(rect.width()),
static_cast<Gdiplus::REAL>(rect.height()));
g.DrawString(text.c_str(), -1, &font, gdiRect, &stringFormat, &solidBrush);
}
void DrawZone(wil::unique_hdc& hdc, ColorSetting const& colorSetting, winrt::com_ptr<IZone> zone, const std::vector<winrt::com_ptr<IZone>>& zones, bool flashMode) noexcept
{
RECT zoneRect = zone->GetZoneRect();
Gdiplus::Graphics g(hdc.get());
Gdiplus::Color fillColor(colorSetting.fillAlpha, GetRValue(colorSetting.fill), GetGValue(colorSetting.fill), GetBValue(colorSetting.fill));
Gdiplus::Color borderColor(colorSetting.borderAlpha, GetRValue(colorSetting.border), GetGValue(colorSetting.border), GetBValue(colorSetting.border));
Gdiplus::Rect rectangle(zoneRect.left, zoneRect.top, zoneRect.right - zoneRect.left - 1, zoneRect.bottom - zoneRect.top - 1);
Gdiplus::Pen pen(borderColor, static_cast<Gdiplus::REAL>(colorSetting.thickness));
g.FillRectangle(new Gdiplus::SolidBrush(fillColor), rectangle);
g.DrawRectangle(&pen, rectangle);
if (!flashMode)
{
DrawIndex(hdc, zoneRect, zone->Id());
}
}
void DrawActiveZoneSet(wil::unique_hdc& hdc,
COLORREF zoneColor,
COLORREF zoneBorderColor,
COLORREF highlightColor,
int zoneOpacity,
const std::vector<winrt::com_ptr<IZone>>& zones,
const std::vector<size_t>& highlightZones,
bool flashMode,
bool drawHints) noexcept
{
// { fillAlpha, fill, borderAlpha, border, thickness }
ColorSetting const colorHints{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 255, RGB(104, 118, 138), -2 };
ColorSetting colorViewer{ OpacitySettingToAlpha(zoneOpacity), 0, 255, RGB(40, 50, 60), -2 };
ColorSetting colorHighlight{ OpacitySettingToAlpha(zoneOpacity), 0, 255, 0, -2 };
ColorSetting const colorFlash{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
std::vector<bool> isHighlighted(zones.size(), false);
for (size_t x : highlightZones)
{
isHighlighted[x] = true;
}
// First draw the inactive zones
for (auto iter = zones.begin(); iter != zones.end(); iter++)
{
size_t zoneId = iter - zones.begin();
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (!isHighlighted[zoneId])
{
if (flashMode)
{
DrawZone(hdc, colorFlash, zone, zones, flashMode);
}
else if (drawHints)
{
DrawZone(hdc, colorHints, zone, zones, flashMode);
}
{
colorViewer.fill = zoneColor;
colorViewer.border = zoneBorderColor;
DrawZone(hdc, colorViewer, zone, zones, flashMode);
}
}
}
// Draw the active zones on top of the inactive zones
for (auto iter = zones.begin(); iter != zones.end(); iter++)
{
size_t zoneId = iter - zones.begin();
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (isHighlighted[zoneId])
{
colorHighlight.fill = highlightColor;
colorHighlight.border = zoneBorderColor;
DrawZone(hdc, colorHighlight, zone, zones, flashMode);
}
}
}
}
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
{
public:
@ -718,11 +589,11 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem);
if (bufferedPaint)
{
ZoneWindowDrawUtils::DrawBackdrop(hdcMem, clientRect);
ZoneWindowDrawing::DrawBackdrop(hdcMem, clientRect);
if (m_activeZoneSet && m_host)
{
ZoneWindowDrawUtils::DrawActiveZoneSet(hdcMem,
ZoneWindowDrawing::DrawActiveZoneSet(hdcMem,
m_host->GetZoneColor(),
m_host->GetZoneBorderColor(),
m_host->GetZoneHighlightColor(),

View file

@ -0,0 +1,178 @@
#include "pch.h"
#include "ZoneWindowDrawing.h"
#include <string>
namespace NonLocalizable
{
const wchar_t SegoeUiFont[] = L"Segoe ui";
}
namespace
{
void InitRGB(_Out_ RGBQUAD* quad, BYTE alpha, COLORREF color)
{
ZeroMemory(quad, sizeof(*quad));
quad->rgbReserved = alpha;
quad->rgbRed = GetRValue(color) * alpha / 255;
quad->rgbGreen = GetGValue(color) * alpha / 255;
quad->rgbBlue = GetBValue(color) * alpha / 255;
}
void FillRectARGB(wil::unique_hdc& hdc, RECT const* prcFill, BYTE alpha, COLORREF color, bool blendAlpha)
{
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = 1;
bi.bmiHeader.biHeight = 1;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
RECT fillRect;
CopyRect(&fillRect, prcFill);
RGBQUAD bitmapBits;
InitRGB(&bitmapBits, alpha, color);
StretchDIBits(
hdc.get(),
fillRect.left,
fillRect.top,
fillRect.right - fillRect.left,
fillRect.bottom - fillRect.top,
0,
0,
1,
1,
&bitmapBits,
&bi,
DIB_RGB_COLORS,
SRCCOPY);
}
BYTE OpacitySettingToAlpha(int opacity)
{
return static_cast<BYTE>(opacity * 2.55);
}
void DrawIndex(wil::unique_hdc& hdc, FancyZonesUtils::Rect rect, size_t index)
{
Gdiplus::Graphics g(hdc.get());
Gdiplus::FontFamily fontFamily(NonLocalizable::SegoeUiFont);
Gdiplus::Font font(&fontFamily, 80, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel);
Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 0, 0));
std::wstring text = std::to_wstring(index);
g.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
Gdiplus::StringFormat stringFormat = new Gdiplus::StringFormat();
stringFormat.SetAlignment(Gdiplus::StringAlignmentCenter);
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentCenter);
Gdiplus::RectF gdiRect(static_cast<Gdiplus::REAL>(rect.left()),
static_cast<Gdiplus::REAL>(rect.top()),
static_cast<Gdiplus::REAL>(rect.width()),
static_cast<Gdiplus::REAL>(rect.height()));
g.DrawString(text.c_str(), -1, &font, gdiRect, &stringFormat, &solidBrush);
}
void DrawZone(wil::unique_hdc& hdc, ZoneWindowDrawing::ColorSetting const& colorSetting, winrt::com_ptr<IZone> zone, const std::vector<winrt::com_ptr<IZone>>& zones, bool flashMode) noexcept
{
RECT zoneRect = zone->GetZoneRect();
Gdiplus::Graphics g(hdc.get());
Gdiplus::Color fillColor(colorSetting.fillAlpha, GetRValue(colorSetting.fill), GetGValue(colorSetting.fill), GetBValue(colorSetting.fill));
Gdiplus::Color borderColor(colorSetting.borderAlpha, GetRValue(colorSetting.border), GetGValue(colorSetting.border), GetBValue(colorSetting.border));
Gdiplus::Rect rectangle(zoneRect.left, zoneRect.top, zoneRect.right - zoneRect.left - 1, zoneRect.bottom - zoneRect.top - 1);
Gdiplus::Pen pen(borderColor, static_cast<Gdiplus::REAL>(colorSetting.thickness));
g.FillRectangle(new Gdiplus::SolidBrush(fillColor), rectangle);
g.DrawRectangle(&pen, rectangle);
if (!flashMode)
{
DrawIndex(hdc, zoneRect, zone->Id());
}
}
}
namespace ZoneWindowDrawing
{
void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept
{
FillRectARGB(hdc, &clientRect, 0, RGB(0, 0, 0), false);
}
void DrawActiveZoneSet(wil::unique_hdc& hdc,
COLORREF zoneColor,
COLORREF zoneBorderColor,
COLORREF highlightColor,
int zoneOpacity,
const std::vector<winrt::com_ptr<IZone>>& zones,
const std::vector<size_t>& highlightZones,
bool flashMode,
bool drawHints) noexcept
{
// { fillAlpha, fill, borderAlpha, border, thickness }
ColorSetting const colorHints{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 255, RGB(104, 118, 138), -2 };
ColorSetting colorViewer{ OpacitySettingToAlpha(zoneOpacity), 0, 255, RGB(40, 50, 60), -2 };
ColorSetting colorHighlight{ OpacitySettingToAlpha(zoneOpacity), 0, 255, 0, -2 };
ColorSetting const colorFlash{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
std::vector<bool> isHighlighted(zones.size(), false);
for (int x : highlightZones)
{
isHighlighted[x] = true;
}
// First draw the inactive zones
for (auto iter = zones.begin(); iter != zones.end(); iter++)
{
int zoneId = static_cast<int>(iter - zones.begin());
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (!isHighlighted[zoneId])
{
if (flashMode)
{
DrawZone(hdc, colorFlash, zone, zones, flashMode);
}
else if (drawHints)
{
DrawZone(hdc, colorHints, zone, zones, flashMode);
}
{
colorViewer.fill = zoneColor;
colorViewer.border = zoneBorderColor;
DrawZone(hdc, colorViewer, zone, zones, flashMode);
}
}
}
// Draw the active zones on top of the inactive zones
for (auto iter = zones.begin(); iter != zones.end(); iter++)
{
int zoneId = static_cast<int>(iter - zones.begin());
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (isHighlighted[zoneId])
{
colorHighlight.fill = highlightColor;
colorHighlight.border = zoneBorderColor;
DrawZone(hdc, colorHighlight, zone, zones, flashMode);
}
}
}
}

View file

@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <wil\resource.h>
#include <winrt/base.h>
#include "util.h"
#include "Zone.h"
namespace ZoneWindowDrawing
{
struct ColorSetting
{
BYTE fillAlpha{};
COLORREF fill{};
BYTE borderAlpha{};
COLORREF border{};
int thickness{};
};
void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept;
void DrawActiveZoneSet(wil::unique_hdc& hdc,
COLORREF zoneColor,
COLORREF zoneBorderColor,
COLORREF highlightColor,
int zoneOpacity,
const std::vector<winrt::com_ptr<IZone>>& zones,
const std::vector<size_t>& highlightZones,
bool flashMode,
bool drawHints) noexcept;
}

View file

@ -5,6 +5,7 @@
#include <common/common.h>
#include <common/dpi_aware.h>
#include <array>
#include <sstream>
#include <complex>

View file

@ -8,6 +8,11 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace
{
#define POWER_LAUNCHER_PID_SHARED_FILE L"Local\\3cbfbad4-199b-4e2c-9825-942d5d3d3c74"
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)