Files
PowerToys/src/modules/fancyzones/FancyZonesLib/Drawing.cpp
2022-01-30 00:00:00 +00:00

240 lines
7.2 KiB
C++

#include "pch.h"
#include "Drawing.h"
#include <common/logger/logger.h>
D2D1_COLOR_F Drawing::ConvertColor(COLORREF color)
{
return D2D1::ColorF(GetRValue(color) / 255.f,
GetGValue(color) / 255.f,
GetBValue(color) / 255.f,
1.f);
}
ID2D1Factory* Drawing::GetD2DFactory()
{
static auto pD2DFactory = [] {
ID2D1Factory* res = nullptr;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &res);
return res;
}();
return pD2DFactory;
}
IDWriteFactory* Drawing::GetWriteFactory()
{
static auto pDWriteFactory = [] {
IUnknown* res = nullptr;
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &res);
return reinterpret_cast<IDWriteFactory*>(res);
}();
return pDWriteFactory;
}
IWICImagingFactory2* Drawing::GetImageFactory()
{
static auto pImageFactory = [] {
PVOID res = nullptr;
CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, __uuidof(IWICImagingFactory2), &res);
return reinterpret_cast<IWICImagingFactory2*>(res);
}();
return pImageFactory;
}
Drawing::Drawing()
{
m_window = nullptr;
m_renderTarget = nullptr;
}
void Drawing::Init(HWND window)
{
m_window = window;
// Obtain the size of the drawing area.
if (!GetClientRect(window, m_renderRect.get()))
{
Logger::error("couldn't initialize Drawing: GetClientRect failed");
return;
}
// Create a Direct2D render target
// We should always use the DPI value of 96 since we're running in DPI aware mode
auto renderTargetProperties = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
96.f,
96.f);
auto renderTargetSize = D2D1::SizeU(m_renderRect.width(), m_renderRect.height());
auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(window, renderTargetSize);
winrt::com_ptr<ID2D1HwndRenderTarget> renderTarget = nullptr;
auto hr = GetD2DFactory()->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, renderTarget.put());
if (!SUCCEEDED(hr))
{
Logger::error("couldn't initialize Drawing: CreateHwndRenderTarget failed with {}", hr);
return;
}
m_renderTarget = renderTarget;
}
Drawing::operator bool() const
{
return m_renderTarget != nullptr;
}
void Drawing::BeginDraw(const D2D1_COLOR_F& backColor)
{
m_renderTarget->BeginDraw();
// Draw backdrop
m_renderTarget->Clear(backColor);
}
winrt::com_ptr<IDWriteTextFormat> Drawing::CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize, DWRITE_FONT_WEIGHT fontWeight) const
{
winrt::com_ptr<IDWriteTextFormat> textFormat = nullptr;
auto writeFactory = GetWriteFactory();
if (writeFactory)
{
writeFactory->CreateTextFormat(fontFamilyName, nullptr, fontWeight, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-US", textFormat.put());
}
return textFormat;
}
winrt::com_ptr<ID2D1SolidColorBrush> Drawing::CreateBrush(D2D1_COLOR_F color) const
{
winrt::com_ptr<ID2D1SolidColorBrush> brush = nullptr;
m_renderTarget->CreateSolidColorBrush(color, brush.put());
return brush;
}
winrt::com_ptr<ID2D1Bitmap> Drawing::CreateIcon(HICON icon) const
{
winrt::com_ptr<ID2D1Bitmap> bitmap = nullptr;
auto imageFactory = GetImageFactory();
if (imageFactory)
{
winrt::com_ptr<IWICBitmap> wicBitmap = nullptr;
imageFactory->CreateBitmapFromHICON(icon, wicBitmap.put());
if (wicBitmap)
{
winrt::com_ptr<IWICFormatConverter> converter = nullptr;
imageFactory->CreateFormatConverter(converter.put());
if (converter)
{
converter->Initialize(wicBitmap.get(), GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut);
D2D1_BITMAP_PROPERTIES bitmapProps;
bitmapProps.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bitmapProps.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
bitmapProps.dpiX = 96;
bitmapProps.dpiY = 96;
m_renderTarget->CreateBitmapFromWicBitmap(wicBitmap.get(), &bitmapProps, bitmap.put());
}
}
}
return bitmap;
}
void Drawing::FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color)
{
auto brush = CreateBrush(color);
if (brush)
{
m_renderTarget->FillRectangle(rect, brush.get());
}
}
void Drawing::FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color)
{
auto brush = CreateBrush(color);
if (brush)
{
D2D1_ROUNDED_RECT roundedRect;
roundedRect.rect = rect;
roundedRect.radiusX = (rect.right - rect.left) * .1f;
roundedRect.radiusY = (rect.bottom - rect.top) * .1f;
auto radius = min(roundedRect.radiusX, roundedRect.radiusY);
roundedRect.radiusX = radius;
roundedRect.radiusY = radius;
m_renderTarget->FillRoundedRectangle(roundedRect, brush.get());
}
}
void Drawing::DrawRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth)
{
auto brush = CreateBrush(color);
if (brush)
{
m_renderTarget->DrawRectangle(rect, brush.get(), strokeWidth);
}
}
void Drawing::DrawRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth)
{
auto brush = CreateBrush(color);
if (brush)
{
D2D1_ROUNDED_RECT roundedRect;
roundedRect.rect = rect;
roundedRect.radiusX = (rect.right - rect.left) * .1f;
roundedRect.radiusY = (rect.bottom - rect.top) * .1f;
m_renderTarget->DrawRoundedRectangle(roundedRect, brush.get(), strokeWidth);
}
}
void Drawing::DrawTextW(std::wstring text, IDWriteTextFormat* textFormat, const D2D1_RECT_F& rect, D2D1_COLOR_F color)
{
auto brush = CreateBrush(color);
if (brush)
{
textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
m_renderTarget->DrawTextW(text.c_str(), (UINT32)text.size(), textFormat, rect, brush.get());
}
}
void Drawing::DrawTextTrim(std::wstring text, IDWriteTextFormat* textFormat, const D2D1_RECT_F& rect, D2D1_COLOR_F color)
{
auto brush = CreateBrush(color);
winrt::com_ptr<IDWriteInlineObject> ellipsis;
GetWriteFactory()->CreateEllipsisTrimmingSign(textFormat, ellipsis.put());
if (brush && ellipsis)
{
DWRITE_TRIMMING trimming{};
trimming.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
textFormat->SetTrimming(&trimming, ellipsis.get());
textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
m_renderTarget->DrawTextW(text.c_str(), (UINT32)text.size(), textFormat, rect, brush.get());
}
}
void Drawing::DrawBitmap(const D2D1_RECT_F& rect, ID2D1Bitmap* bitmap)
{
m_renderTarget->DrawBitmap(bitmap, rect);
}
void Drawing::EndDraw()
{
m_renderTarget->EndDraw();
}