diff --git a/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp b/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp index 4f9f97180d..962624192f 100644 --- a/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp +++ b/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp @@ -86,7 +86,7 @@ void FancyZonesApp::InitHooks() } } - std::array events_to_subscribe = { + std::array events_to_subscribe = { EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, EVENT_OBJECT_NAMECHANGE, @@ -98,8 +98,7 @@ void FancyZonesApp::InitHooks() EVENT_SYSTEM_MINIMIZEEND, EVENT_OBJECT_HIDE, EVENT_OBJECT_DESTROY, - EVENT_SYSTEM_FOREGROUND, - EVENT_OBJECT_FOCUS + EVENT_OBJECT_REORDER }; for (const auto event : events_to_subscribe) { @@ -179,8 +178,7 @@ void FancyZonesApp::HandleWinHookEvent(WinHookEvent* data) noexcept case EVENT_SYSTEM_MINIMIZEEND: case EVENT_OBJECT_HIDE: case EVENT_OBJECT_DESTROY: - case EVENT_SYSTEM_FOREGROUND: - case EVENT_OBJECT_FOCUS: + case EVENT_OBJECT_REORDER: { fzCallback->HandleWinHookEvent(data); } diff --git a/src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp b/src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp index 4b0946b73b..b0b92474f2 100644 --- a/src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp +++ b/src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp @@ -15,17 +15,7 @@ void CompositionDrawing::Init(HWND window) } // Create devices - D2D1_FACTORY_OPTIONS options = { -#ifdef _DEBUG - D2D1_DEBUG_LEVEL_INFORMATION -#endif - }; - - D2D1CreateFactory( - D2D1_FACTORY_TYPE_MULTI_THREADED, - __uuidof(m_d2dFactory), - &options, - m_d2dFactory.put_void()); + m_d2dFactory.copy_from(GetD2DFactory()); if (!m_d2dFactory) { return; diff --git a/src/modules/fancyzones/FancyZonesLib/Drawing.cpp b/src/modules/fancyzones/FancyZonesLib/Drawing.cpp index 18234ba6ee..7f1454551f 100644 --- a/src/modules/fancyzones/FancyZonesLib/Drawing.cpp +++ b/src/modules/fancyzones/FancyZonesLib/Drawing.cpp @@ -19,11 +19,17 @@ D2D1_COLOR_F Drawing::ConvertColor(winrt::Windows::UI::Color color) color.A / 255.f); } -ID2D1Factory* Drawing::GetD2DFactory() +ID2D1Factory6* Drawing::GetD2DFactory() { static auto pD2DFactory = [] { - ID2D1Factory* res = nullptr; - D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &res); + D2D1_FACTORY_OPTIONS options = { +#ifdef _DEBUG + D2D1_DEBUG_LEVEL_INFORMATION +#endif + }; + ID2D1Factory6* res = nullptr; + + D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &res); return res; }(); return pD2DFactory; @@ -140,6 +146,28 @@ winrt::com_ptr Drawing::CreateBrush(D2D1_COLOR_F color) co return brush; } +winrt::com_ptr Drawing::CreateStroke(float stokeWidht) const +{ + if (!*this) + { + return nullptr; + } + + winrt::com_ptr stroke = nullptr; + + auto properties = D2D1::StrokeStyleProperties1( + D2D1_CAP_STYLE_ROUND, + D2D1_CAP_STYLE_ROUND, + D2D1_CAP_STYLE_ROUND, + D2D1_LINE_JOIN_ROUND, + 0.0f, + D2D1_DASH_STYLE_SOLID, + 0.0f); + GetD2DFactory()->CreateStrokeStyle(properties, nullptr, 0, stroke.put()); + + return stroke; +} + winrt::com_ptr Drawing::CreateIcon(HICON icon) const { if (!*this) @@ -179,6 +207,49 @@ winrt::com_ptr Drawing::CreateIcon(HICON icon) const return bitmap; } +winrt::com_ptr Drawing::CreateTriangle(const D2D1_TRIANGLE& triangle) const +{ + if (!*this) + { + return nullptr; + } + + winrt::com_ptr geometry = nullptr; + + GetD2DFactory()->CreatePathGeometry(geometry.put()); + + if (!geometry) + { + return nullptr; + } + + winrt::com_ptr tessellationSink = nullptr; + + geometry->Open(tessellationSink.put()); + + if (!tessellationSink) + { + return nullptr; + } + + tessellationSink->BeginFigure(triangle.point1, D2D1_FIGURE_BEGIN_FILLED); + + tessellationSink->AddLine(triangle.point2); + + tessellationSink->AddLine(triangle.point3); + + tessellationSink->EndFigure(D2D1_FIGURE_END_CLOSED); + + auto hr = tessellationSink->Close(); + + if (FAILED(hr)) + { + return nullptr; + } + + return geometry; +} + void Drawing::FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color) { if (!*this) @@ -193,7 +264,7 @@ void Drawing::FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color) } } -void Drawing::FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color) +void Drawing::FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float radiusFactor) { if (!*this) { @@ -205,8 +276,8 @@ void Drawing::FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color) { D2D1_ROUNDED_RECT roundedRect; roundedRect.rect = rect; - roundedRect.radiusX = (rect.right - rect.left) * .1f; - roundedRect.radiusY = (rect.bottom - rect.top) * .1f; + roundedRect.radiusX = (rect.right - rect.left) * radiusFactor; + roundedRect.radiusY = (rect.bottom - rect.top) * radiusFactor; auto radius = min(roundedRect.radiusX, roundedRect.radiusY); roundedRect.radiusX = radius; @@ -216,6 +287,40 @@ void Drawing::FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color) } } +void Drawing::FillEllipse(const D2D1_ELLIPSE& ellipse, D2D1_COLOR_F color) +{ + if (!*this) + { + return; + } + + auto brush = CreateBrush(color); + if (brush) + { + m_renderTarget->FillEllipse(ellipse, brush.get()); + } +} + +void Drawing::FillGeometry(ID2D1PathGeometry* geometry, D2D1_COLOR_F color, float strokeWidth) +{ + if (!*this) + { + return; + } + + auto brush = CreateBrush(color); + auto stroke = CreateStroke(strokeWidth); + if (brush) + { + m_renderTarget->FillGeometry(geometry, brush.get()); + + if (stroke) + { + m_renderTarget->DrawGeometry(geometry, brush.get(), strokeWidth, stroke.get()); + } + } +} + void Drawing::DrawRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth) { if (!*this) diff --git a/src/modules/fancyzones/FancyZonesLib/Drawing.h b/src/modules/fancyzones/FancyZonesLib/Drawing.h index 8dcfb3db77..8814a1e76a 100644 --- a/src/modules/fancyzones/FancyZonesLib/Drawing.h +++ b/src/modules/fancyzones/FancyZonesLib/Drawing.h @@ -2,7 +2,7 @@ #include "util.h" #include -#include +#include #include #include #include @@ -21,10 +21,14 @@ public: winrt::com_ptr CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize, DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL) const; winrt::com_ptr CreateBrush(D2D1_COLOR_F color) const; + winrt::com_ptr CreateStroke(float stokeWidht) const; winrt::com_ptr CreateIcon(HICON icon) const; + winrt::com_ptr CreateTriangle(const D2D1_TRIANGLE& triangle) const; void FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color); - void FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color); + void FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float radiusFactor = .1f); + void FillEllipse(const D2D1_ELLIPSE& ellipse, D2D1_COLOR_F color); + void FillGeometry(ID2D1PathGeometry* geometry, D2D1_COLOR_F color, float strokeWidth = 1.f); void DrawRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth = 1.f); void DrawRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth = 1.f); void DrawTextW(std::wstring text, IDWriteTextFormat* format, const D2D1_RECT_F& rect, D2D1_COLOR_F color); @@ -34,7 +38,7 @@ public: void EndDraw(); protected: - static ID2D1Factory* GetD2DFactory(); + static ID2D1Factory6* GetD2DFactory(); static IDWriteFactory* GetWriteFactory(); static IWICImagingFactory2* GetImageFactory(); diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 5a896291ff..509bc182fc 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -158,8 +158,7 @@ public: } break; - case EVENT_SYSTEM_FOREGROUND: - case EVENT_OBJECT_FOCUS: + case EVENT_OBJECT_REORDER: PostMessageW(m_window, WM_PRIV_WINDOWREORDER, wparam, lparam); break; } diff --git a/src/modules/fancyzones/FancyZonesLib/Settings.h b/src/modules/fancyzones/FancyZonesLib/Settings.h index 3f7e406d30..c5b29fd898 100644 --- a/src/modules/fancyzones/FancyZonesLib/Settings.h +++ b/src/modules/fancyzones/FancyZonesLib/Settings.h @@ -23,7 +23,11 @@ enum struct ZoneTitleBarStyle : int AutoHideTabs = 7, Labels = 8, AutoHideLabels = 9, - EnumElements = 10, // number of elements in the enum, not counting this + Pager = 10, + AutoHidePager = 11, + Buttons = 12, + AutoHideButtons = 13, + EnumElements = 14, // number of elements in the enum, not counting this }; // in reality, this file needs to be kept in sync currently with src/settings-ui/Settings.UI.Library/FZConfigProperties.cs diff --git a/src/modules/fancyzones/FancyZonesLib/Window.cpp b/src/modules/fancyzones/FancyZonesLib/Window.cpp index a89d6569cd..50d1f21fcd 100644 --- a/src/modules/fancyzones/FancyZonesLib/Window.cpp +++ b/src/modules/fancyzones/FancyZonesLib/Window.cpp @@ -7,10 +7,16 @@ namespace NonLocalizable const wchar_t WindowClassName[] = L"FancyZones_Window"; } -Window::Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedStyle, FancyZonesUtils::Rect position, LPCWSTR windowName, HWND parent, HMENU menu, int showCommand) noexcept : +Window::Window() noexcept : m_window(NULL), - m_proc(proc) + m_proc(nullptr) { +} + +void Window::Init(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedStyle, FancyZonesUtils::Rect position, LPCWSTR windowName, HWND parent, HMENU menu, int showCommand) noexcept +{ + m_proc = proc; + static ATOM windowClass = INVALID_ATOM; if (windowClass == INVALID_ATOM) { diff --git a/src/modules/fancyzones/FancyZonesLib/Window.h b/src/modules/fancyzones/FancyZonesLib/Window.h index d621fced05..9f4099ab82 100644 --- a/src/modules/fancyzones/FancyZonesLib/Window.h +++ b/src/modules/fancyzones/FancyZonesLib/Window.h @@ -7,7 +7,7 @@ using WndProc = std::functionsecond->GetHeight(); - rect.top += zoneTitleBarHeight; - SizeWindowToRect(hwnd, rect); + zoneTitleBarInlineFrame = zoneTitleBar->second->GetInlineFrame(); + auto rectForResize = AdjustRectForSizeWindowToRect(hwnd, *zoneTitleBarInlineFrame.get(), workAreaWindow); + SizeWindowToRect(hwnd, rectForResize); + } + else + { + zoneTitleBarInlineFrame = rect; } } else { // Adjust the rect - zoneTitleBarHeight = zoneTitleBar->second->GetHeight(); + zoneTitleBarInlineFrame = zoneTitleBar->second->GetInlineFrame(); } } @@ -420,8 +424,15 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND workAreaWindow, const Zo auto shouldSuppressMove = ShouldSuppressMove(window, rect, suppressMove); if (!shouldSuppressMove) { - rect.top += zoneTitleBarHeight; - SizeWindowToRect(window, rect); + if (IsRectEmpty(zoneTitleBarInlineFrame.get())) + { + SizeWindowToRect(window, rect); + } + else + { + auto rectForResize = AdjustRectForSizeWindowToRect(window, *zoneTitleBarInlineFrame.get(), workAreaWindow); + SizeWindowToRect(window, rectForResize); + } } auto oldBitmask = GetWindowStamp(window); diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.cpp b/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.cpp index ce6aaf5d97..c264dcf782 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.cpp +++ b/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.cpp @@ -12,7 +12,7 @@ /* void Cls_OnDwmColorizationColorChanged(HWND hwnd, DWORD dwNewColorizationColor, BOOL fIsBlendedWithOpacity) */ #define HANDLE_WM_DWMCOLORIZATIONCOLORCHANGED(hwnd, wParam, lParam, fn) \ - ((fn)((hwnd), (DWORD)(wParam), (BOOL)lParam), 0L) + ((fn)((hwnd), (DWORD)(wParam), (BOOL)(lParam)), 0L) using namespace FancyZonesUtils; @@ -20,6 +20,11 @@ using namespace FancyZonesUtils; class ZoneTitleBarColors { public: + ZoneTitleBarColors() : + ZoneTitleBarColors(WindowsColors::is_dark_mode()) + { + } + ZoneTitleBarColors(bool isDarkMode) { backColor = Drawing::ConvertColor(WindowsColors::get_background_color()); @@ -38,6 +43,21 @@ public: D2D1_COLOR_F highlightTextColor; }; +class HiddenWindow : public Window +{ +public: + HiddenWindow(HINSTANCE hinstance) + { + Init(hinstance, nullptr, 0, WS_EX_TOOLWINDOW, Rect(0, 0, 0, 0), 0, 0, 0, SW_HIDE); + } + + void HideWindowFromTaskbar(HWND window) + { + HWND val = *this; + SetWindowLongPtr(window, GWLP_HWNDPARENT, (LONG_PTR)val); + } +}; + static HWND GetWindowAboveAllOthers(const std::vector& windows) { if (windows.empty()) @@ -62,6 +82,22 @@ static HWND GetWindowAboveAllOthers(const std::vector& windows) return max; } +static void SwitchToWindow(const std::vector& windows, int i) +{ + if (i >= windows.size()) + { + SwitchToWindow(windows.back()); + } + else if (i <= 0) + { + SwitchToWindow(windows.front()); + } + else + { + SwitchToWindow(windows[i]); + } +} + static void DrawWindowIcon(Drawing& drawing, const D2D1_RECT_F& rect, HWND window, float opacity = 1.f) { HICON icon = nullptr; @@ -80,7 +116,10 @@ static void DrawWindowIcon(Drawing& drawing, const D2D1_RECT_F& rect, HWND windo class NoZoneTitleBar : public IZoneTitleBar { public: - NoZoneTitleBar() noexcept {} + NoZoneTitleBar(Rect zone) noexcept : + m_zone(zone) + { + } void Show(bool show) override {} @@ -88,307 +127,63 @@ public: void ReadjustPos() override {} - int GetHeight() const override { return 0; } + Rect GetInlineFrame() const override { return m_zone; } + +private: + Rect m_zone; }; -class SlimZoneTitleBar : public IZoneTitleBar +class VisibleZoneTitleBar : public IZoneTitleBar { -public: - SlimZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - m_isOverlay(isOverlay), +protected: + VisibleZoneTitleBar(bool isAboveZone, Rect zone, UINT dpi) : + m_isAboveZone(isAboveZone), + m_zone(zone), m_dpi(dpi), - m_window( - hinstance, - [this](HWND window, UINT message, WPARAM wParam, LPARAM lParam) { return WndProc(window, message, wParam, lParam); }, - WS_POPUP, - WS_EX_TOOLWINDOW, - ResetRect(zone), - NULL, - NULL, - NULL) + m_zoneCurrentWindow(NULL) { } - void Show(bool show) override {} - - void UpdateZoneWindows(std::vector zoneWindows) override + void Init(HINSTANCE hinstance, Rect rect, DWORD style, DWORD extendedStyle) { - m_zoneWindows = zoneWindows; - ReadjustPos(); + auto proc = [this](HWND window, UINT message, WPARAM wParam, LPARAM lParam) { return WndProc(window, message, wParam, lParam); }; + + m_window.Init(hinstance, proc, style, extendedStyle, rect); } - void ReadjustPos() override + HWND GetDestinedWindowBeforeTheZoneTitleBar() { - if (m_isOverlay) + if (m_isAboveZone) { - // Set the zone title bar to be top - SetWindowPos(m_window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); + // Put the zone title bar just above the zone current window + { + // Get the window above the zone current window + HWND windowAboveZoneCurrentWindow = GetWindow(m_zoneCurrentWindow, GW_HWNDPREV); + + // Put the zone title bar just below the windowAboveZoneCurrentWindow + return windowAboveZoneCurrentWindow; + } } else { - auto zoneCurrentWindow = GetZoneCurrentWindow(); - - // Put the zone title bar just above the zone current window - if (zoneCurrentWindow != NULL) - { - // Get the window above the zone current window - HWND windowAboveZoneCurrentWindow = GetWindow(zoneCurrentWindow, GW_HWNDPREV); - - // Put the zone title bar just below the windowAboveZoneCurrentWindow - SetWindowPos(m_window, windowAboveZoneCurrentWindow, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); - } + // Put the zone title bar just below the zoneCurrentWindow + return m_zoneCurrentWindow; } - - Render(m_window); - } - - int GetHeight() const override { return m_height; } - - virtual void Render(HWND window) = 0; - -protected: - LRESULT WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept - { - switch (message) - { - HANDLE_MSG(window, WM_CREATE, Init); - HANDLE_MSG(window, WM_DWMCOLORIZATIONCOLORCHANGED, DwmColorizationColorChanged); - HANDLE_MSG(window, WM_PAINT, Render); - HANDLE_MSG(window, WM_LBUTTONDOWN, Click); - default: - return DefWindowProcW(window, message, wParam, lParam); - } - } - - bool Init(HWND hwnd, LPCREATESTRUCT) - { - m_drawing.Init(hwnd); - - return true; - } - - void DwmColorizationColorChanged(HWND hwnd, DWORD newColorizationColor, BOOL isBlendedWithOpacity) - { - Render(hwnd); - } - - void Click(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) - { - auto len = m_height; - if (len == 0) - { - return; - } - - auto i = x / len; - - if (i < m_zoneWindows.size()) - { - SwitchToWindow(m_zoneWindows[i]); - } - } - - HWND GetZoneCurrentWindow() - { - return GetWindowAboveAllOthers(m_zoneWindows); - } - - Rect ResetRect(Rect zone) - { - int height = GetSystemMetricsForDpi(SM_CYHSCROLL, m_dpi); - m_height = height > zone.height() ? 0 : height; - return Rect(zone.position(), zone.width(), m_height); - } - -protected: - bool m_isOverlay; - UINT m_dpi; - int m_height; - std::vector m_zoneWindows; - Drawing m_drawing; - Window m_window; -}; - -class NumbersZoneTitleBar : public SlimZoneTitleBar -{ -public: - NumbersZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - SlimZoneTitleBar(hinstance, zone, dpi, isOverlay) - { - } - - void Render(HWND hwnd) override - { - ZoneTitleBarColors colors(WindowsColors::is_dark_mode()); - - PAINTSTRUCT paint; - BeginPaint(m_window, &paint); - - auto zoneCurrentWindow = GetZoneCurrentWindow(); - - if (m_drawing) - { - m_drawing.BeginDraw(colors.backColor); - - { - auto len = (FLOAT)m_height; - - auto textFormat = m_drawing.CreateTextFormat(L"Segoe ui", len * .7f); - for (auto i = 0; i < m_zoneWindows.size(); ++i) - { - auto rect = D2D1::Rect(len * i, .0f, len * (i + 1), len); - - if (m_zoneWindows[i] == zoneCurrentWindow) - { - m_drawing.FillRectangle(rect, colors.highlightFrameColor); - m_drawing.DrawTextW(std::to_wstring(i + 1), textFormat.get(), rect, colors.highlightTextColor); - } - else - { - m_drawing.FillRectangle(rect, colors.frameColor); - m_drawing.DrawTextW(std::to_wstring(i + 1), textFormat.get(), rect, colors.textColor); - } - } - } - - m_drawing.EndDraw(); - } - - EndPaint(m_window, &paint); - } -}; - -class IconsZoneTitleBar : public SlimZoneTitleBar -{ -public: - IconsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - SlimZoneTitleBar(hinstance, zone, dpi, isOverlay) - { - } - - void Render(HWND hwnd) override - { - ZoneTitleBarColors colors(WindowsColors::is_dark_mode()); - - PAINTSTRUCT paint; - BeginPaint(m_window, &paint); - - auto zoneCurrentWindow = GetZoneCurrentWindow(); - - if (m_drawing) - { - m_drawing.BeginDraw(colors.backColor); - - { - auto len = (FLOAT)m_height; - - for (auto i = 0; i < m_zoneWindows.size(); ++i) - { - constexpr float p = .15f; - auto iconRect = D2D1::Rect(len * (i + p), len * p, len * (i + 1 - p), len * (1 - p)); - DrawWindowIcon(m_drawing, iconRect, m_zoneWindows[i]); - - constexpr float s = p * .7f; - auto strokeRect = D2D1::Rect(len * (i + .5f * s), len * .5f * s, len * (i + 1 - .5f * s), len * (1 - .5f * s)); - m_drawing.DrawRoundedRectangle(strokeRect, m_zoneWindows[i] == zoneCurrentWindow ? colors.highlightFrameColor : colors.frameColor, len * s); - } - } - - m_drawing.EndDraw(); - } - - EndPaint(m_window, &paint); - } -}; - -class HiddenWindow : public Window -{ -public: - HiddenWindow(HINSTANCE hinstance) : - Window(hinstance, nullptr, 0, WS_EX_TOOLWINDOW, Rect(0, 0, 0, 0), 0, 0, 0, SW_HIDE) - { - } - - void HideWindowFromTaskbar(HWND window) - { - HWND val = *this; - SetWindowLongPtr(window, GWLP_HWNDPARENT, (LONG_PTR)val); - } -}; - -class ThickZoneTitleBar : public IZoneTitleBar -{ -protected: - static constexpr int c_style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME; - static constexpr int c_exStyle = WS_EX_NOREDIRECTIONBITMAP; - float GetWidthFactor() const - { - constexpr int c_widthFactor = 4; - - auto left = float(m_zone.width() - 2 * m_height); - auto amount = m_zoneWindows.size(); - - if (amount == 0 || left <= 0) - { - return 0; - } - - auto factor = (left / amount) / m_height; - return min(factor, c_widthFactor); - } - -public: - ThickZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - m_isOverlay(isOverlay), - m_hiddenWindow(hinstance), - m_zoneCurrentWindow(NULL), - m_dpi(dpi), - m_window( - hinstance, - [this](HWND window, UINT message, WPARAM wParam, LPARAM lParam) { return WndProc(window, message, wParam, lParam); }, - c_style, - c_exStyle, - ResetRect(zone), - NULL, - NULL, - NULL) - { - } - - void Show(bool show) override {} - - void UpdateZoneWindows(std::vector zoneWindows) override - { - m_zoneWindows = zoneWindows; - ReadjustPos(); } void ReadjustPos() override { - auto zoneCurrentWindow = GetZoneCurrentWindow(); + m_zoneCurrentWindow = GetWindowAboveAllOthers(m_zoneWindows); - if (zoneCurrentWindow != NULL) + if (m_zoneCurrentWindow != NULL) { - m_zoneCurrentWindow = zoneCurrentWindow; - - if (m_isOverlay) - { - // Set the zone title bar to be top - SetWindowPos(m_window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); - } - else - { - // Put the zone title bar just below the zoneCurrentWindow - SetWindowPos(m_window, zoneCurrentWindow, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); - } + HWND windowBeforeTheZoneTitleBar = GetDestinedWindowBeforeTheZoneTitleBar(); + SetWindowPos(m_window, windowBeforeTheZoneTitleBar, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); } - Render(m_window); + OnPaint(m_window); } - int GetHeight() const override { return m_height; } - -protected: LRESULT WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept { LRESULT result; @@ -400,59 +195,56 @@ protected: switch (message) { - HANDLE_MSG(window, WM_CREATE, Init); - HANDLE_MSG(window, WM_NCCALCSIZE, CalcNonClientSize); + HANDLE_MSG(window, WM_NCCALCSIZE, OnCalcNonClientSize); + HANDLE_MSG(window, WM_CREATE, OnCreate); HANDLE_MSG(window, WM_WINDOWPOSCHANGING, WindowPosChanging); HANDLE_MSG(window, WM_DWMNCRENDERINGCHANGED, DwmNonClientRenderingChanged); - HANDLE_MSG(window, WM_DWMCOLORIZATIONCOLORCHANGED, DwmColorizationColorChanged); - HANDLE_MSG(window, WM_PAINT, Render); - HANDLE_MSG(window, WM_LBUTTONDOWN, Click); + HANDLE_MSG(window, WM_DWMCOLORIZATIONCOLORCHANGED, OnDwmColorizationColorChanged); + HANDLE_MSG(window, WM_PAINT, OnPaint); + HANDLE_MSG(window, WM_LBUTTONDOWN, OnLButtonDown); + HANDLE_MSG(window, WM_ERASEBKGND, OnEraseBackground); + default: return DefWindowProcW(window, message, wParam, lParam); } } - bool Init(HWND hwnd, LPCREATESTRUCT) - { - // Hide from taskbar - m_hiddenWindow.HideWindowFromTaskbar(hwnd); - - // Disable transitions - BOOL disable = TRUE; - DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disable, sizeof(disable)); - - // Extend frame (twice the size if not overlay) - int height = m_isOverlay ? m_height : 2 * m_height; - MARGINS margins = { 0, 0, height, 0 }; - DwmExtendFrameIntoClientArea(hwnd, &margins); - - // Update frame - SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - // Initialize drawing - m_drawing.Init(hwnd); - - return true; - } - - UINT CalcNonClientSize(HWND hwnd, BOOL calc, NCCALCSIZE_PARAMS* info) + UINT OnCalcNonClientSize(HWND hwnd, BOOL calc, NCCALCSIZE_PARAMS* info) { if (!calc) { return FORWARD_WM_NCCALCSIZE(hwnd, calc, info, DefWindowProcW); } - auto xBorder = GetSystemMetricsForDpi(SM_CXFRAME, m_dpi) + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, m_dpi); - auto yBorder = GetSystemMetricsForDpi(SM_CYFRAME, m_dpi) + GetSystemMetricsForDpi(SM_CYEDGE, m_dpi); + if (GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) + { + auto xBorder = GetSystemMetricsForDpi(SM_CXFRAME, m_dpi) + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, m_dpi); + auto yBorder = GetSystemMetricsForDpi(SM_CYFRAME, m_dpi) + GetSystemMetricsForDpi(SM_CYEDGE, m_dpi); - auto& coordinates = info->rgrc[0]; - coordinates.left += xBorder; - coordinates.right -= xBorder; - coordinates.bottom -= yBorder; + auto& coordinates = info->rgrc[0]; + coordinates.left += xBorder; + coordinates.right -= xBorder; + coordinates.bottom -= yBorder; + } return 0; } + virtual bool OnCreate(HWND hwnd, LPCREATESTRUCT) + { + // Disable transitions + BOOL disable = TRUE; + DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disable, sizeof(disable)); + + return true; + } + + void OnDwmColorizationColorChanged(HWND hwnd, DWORD newColorizationColor, BOOL isBlendedWithOpacity) + { + // Post WM_PAINT + RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT); + } + void DwmNonClientRenderingChanged(HWND hwnd, BOOL enabled) { Rect newWindowRect = m_zone; @@ -476,29 +268,246 @@ protected: } } - void DwmColorizationColorChanged(HWND hwnd, DWORD newColorizationColor, BOOL isBlendedWithOpacity) + virtual void OnLButtonDown(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) = 0; + + virtual void OnPaint(HWND hwnd) = 0; + + BOOL OnEraseBackground(HWND hwnd, HDC hdc) { - Render(hwnd); + return TRUE; + } + + void UpdateZoneWindows(std::vector zoneWindows) override + { + m_zoneWindows = zoneWindows; + ReadjustPos(); } BOOL WindowPosChanging(HWND hwnd, WINDOWPOS* pos) { - if (m_isOverlay) + if ((pos->flags & SWP_NOZORDER) == 0) { - pos->hwndInsertAfter = HWND_TOPMOST; - } - else if (m_zoneCurrentWindow != NULL) - { - pos->hwndInsertAfter = m_zoneCurrentWindow; + pos->hwndInsertAfter = GetDestinedWindowBeforeTheZoneTitleBar(); } + pos->flags |= SWP_NOACTIVATE; return true; } - virtual void Render(HWND hwnd) = 0; + int GetScale() const + { + auto scale = GetSystemMetricsForDpi(SM_CYHSCROLL, m_dpi); + if (scale > m_zone.height()) + { + scale = 0; + } - void Click(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) + return scale; + } + + bool m_isAboveZone; + UINT m_dpi; + Rect m_zone; + std::vector m_zoneWindows; + HWND m_zoneCurrentWindow; + Window m_window; + +public: + void Show(bool show) override {} +}; + +class SlimZoneTitleBar : public VisibleZoneTitleBar +{ +public: + SlimZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + VisibleZoneTitleBar(isAboveZone, zone, dpi), + m_height(GetScale()) + { + Rect rect(zone.position(), zone.width(), m_height); + Init(hinstance, rect, WS_POPUP, WS_EX_TOOLWINDOW); + } + + Rect GetInlineFrame() const override + { + auto rect = m_zone; + rect.get()->top += m_height; + return rect; + } + +protected: + bool OnCreate(HWND hwnd, LPCREATESTRUCT) + { + m_drawing.Init(hwnd); + + return true; + } + + void OnLButtonDown(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) + { + auto len = m_height; + if (len == 0) + { + return; + } + + auto i = x / len; + + if (i >= 0 && i < m_zoneWindows.size()) + { + SwitchToWindow(m_zoneWindows[i]); + } + } + + void OnPaint(HWND hwnd) override + { + ZoneTitleBarColors colors; + + PAINTSTRUCT paint; + BeginPaint(m_window, &paint); + + if (m_drawing) + { + m_drawing.BeginDraw(colors.backColor); + + Render(colors); + + m_drawing.EndDraw(); + } + + EndPaint(m_window, &paint); + } + + virtual void Render(ZoneTitleBarColors& colors) = 0; + +protected: + int m_height; + Drawing m_drawing; +}; + +class NumbersZoneTitleBar : public SlimZoneTitleBar +{ +public: + NumbersZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + SlimZoneTitleBar(hinstance, zone, dpi, isAboveZone) + { + } + + void Render(ZoneTitleBarColors& colors) override + { + auto len = (FLOAT)m_height; + + auto textFormat = m_drawing.CreateTextFormat(L"Segoe ui", len * .7f); + for (auto i = 0; i < m_zoneWindows.size(); ++i) + { + auto rect = D2D1::Rect(len * i, .0f, len * (i + 1), len); + + if (m_zoneWindows[i] == m_zoneCurrentWindow) + { + m_drawing.FillRectangle(rect, colors.highlightFrameColor); + m_drawing.DrawTextW(std::to_wstring(i + 1), textFormat.get(), rect, colors.highlightTextColor); + } + else + { + m_drawing.FillRectangle(rect, colors.frameColor); + m_drawing.DrawTextW(std::to_wstring(i + 1), textFormat.get(), rect, colors.textColor); + } + } + } +}; + +class IconsZoneTitleBar : public SlimZoneTitleBar +{ +public: + IconsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + SlimZoneTitleBar(hinstance, zone, dpi, isAboveZone) + { + } + + void Render(ZoneTitleBarColors& colors) override + { + auto len = (FLOAT)m_height; + + for (auto i = 0; i < m_zoneWindows.size(); ++i) + { + constexpr float p = .15f; + auto iconRect = D2D1::Rect(len * (i + p), len * p, len * (i + 1 - p), len * (1 - p)); + DrawWindowIcon(m_drawing, iconRect, m_zoneWindows[i]); + + constexpr float s = p * .7f; + auto strokeRect = D2D1::Rect(len * (i + .5f * s), len * .5f * s, len * (i + 1 - .5f * s), len * (1 - .5f * s)); + auto color = m_zoneWindows[i] == m_zoneCurrentWindow ? colors.highlightFrameColor : colors.frameColor; + m_drawing.DrawRoundedRectangle(strokeRect, color, len * s); + } + } +}; + +class ThickZoneTitleBar : public VisibleZoneTitleBar +{ +protected: + static constexpr int c_style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME; + static constexpr int c_exStyle = WS_EX_NOREDIRECTIONBITMAP; + + float GetWidthFactor() const + { + constexpr int c_widthFactor = 4; + + auto left = float(m_zone.width() - 2 * m_height); + auto amount = m_zoneWindows.size(); + + if (amount == 0 || left <= 0) + { + return 0; + } + + auto factor = (left / amount) / m_height; + return min(factor, c_widthFactor); + } + +public: + ThickZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + VisibleZoneTitleBar(isAboveZone, zone, dpi), + m_hiddenWindow(hinstance) + { + RECT rect{}; + AdjustWindowRectExForDpi(&rect, c_style, FALSE, c_exStyle, m_dpi); + + auto height = -rect.top; + m_height = height > zone.height() ? 0 : height; + + Init(hinstance, zone, c_style, c_exStyle); + } + + Rect GetInlineFrame() const override + { + auto rect = m_zone; + rect.get()->top += m_height; + return rect; + } + +protected: + bool OnCreate(HWND hwnd, LPCREATESTRUCT createStruct) + { + VisibleZoneTitleBar::OnCreate(hwnd, createStruct); + + // Hide from taskbar + m_hiddenWindow.HideWindowFromTaskbar(hwnd); + + // Extend frame (twice the size if not overlay) + int height = m_isAboveZone ? m_height : 2 * m_height; + MARGINS margins = { 0, 0, height, 0 }; + DwmExtendFrameIntoClientArea(hwnd, &margins); + + // Update frame + SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + // Initialize drawing + m_drawing.Init(hwnd); + + return true; + } + + void OnLButtonDown(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) { auto len = m_height; if (len == 0 || x < len) @@ -508,52 +517,28 @@ protected: auto i = int((x - len) / (len * GetWidthFactor())); - if (i < m_zoneWindows.size()) + if (i >= 0 && i < m_zoneWindows.size()) { SwitchToWindow(m_zoneWindows[i]); } } - HWND GetZoneCurrentWindow() - { - return GetWindowAboveAllOthers(m_zoneWindows); - } - - Rect ResetRect(Rect zone) - { - m_zone = zone; - - RECT rect{}; - AdjustWindowRectExForDpi(&rect, c_style, FALSE, c_exStyle, m_dpi); - - auto height = -rect.top; - m_height = height > zone.height() ? 0 : height; - - return zone; - } - protected: - bool m_isOverlay; HiddenWindow m_hiddenWindow; - HWND m_zoneCurrentWindow; - UINT m_dpi; - Rect m_zone; int m_height; - std::vector m_zoneWindows; CompositionDrawing m_drawing; - Window m_window; }; class TabsZoneTitleBar : public ThickZoneTitleBar { public: - TabsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - ThickZoneTitleBar(hinstance, zone, dpi, isOverlay) + TabsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + ThickZoneTitleBar(hinstance, zone, dpi, isAboveZone) { } protected: - void Render(HWND hwnd) override + void OnPaint(HWND hwnd) override { constexpr DWORD DWMWA_USE_IMMERSIVE_DARK_MODE = 20; @@ -570,7 +555,7 @@ protected: auto captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, m_dpi); - auto zoneCurrentWindow = GetZoneCurrentWindow(); + auto zoneCurrentWindow = m_zoneCurrentWindow; NONCLIENTMETRICS metrics{}; metrics.cbSize = sizeof(metrics); @@ -636,15 +621,14 @@ protected: class LabelsZoneTitleBar : public ThickZoneTitleBar { - public: - LabelsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isOverlay) noexcept : - ThickZoneTitleBar(hinstance, zone, dpi, isOverlay) + LabelsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + ThickZoneTitleBar(hinstance, zone, dpi, isAboveZone) { } protected: - void Render(HWND hwnd) override + void OnPaint(HWND hwnd) override { constexpr DWORD DWMWA_USE_IMMERSIVE_DARK_MODE = 20; @@ -661,7 +645,7 @@ protected: auto captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, m_dpi); - auto zoneCurrentWindow = GetZoneCurrentWindow(); + auto zoneCurrentWindow = m_zoneCurrentWindow; NONCLIENTMETRICS metrics{}; metrics.cbSize = sizeof(metrics); @@ -738,6 +722,282 @@ protected: } }; +class AdornZoneTitleBar : public VisibleZoneTitleBar +{ +protected: + static constexpr int c_style = WS_POPUP; + static constexpr int c_exStyle = WS_EX_TOOLWINDOW | WS_EX_LAYERED; + +public: + AdornZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi) noexcept : + VisibleZoneTitleBar(true, zone, dpi) + { + Init(hinstance, zone, c_style, c_exStyle); + } + + Rect GetInlineFrame() const override + { + return m_zone; + } + +protected: + bool OnCreate(HWND hwnd, LPCREATESTRUCT createStruct) override + { + VisibleZoneTitleBar::OnCreate(hwnd, createStruct); + + // Initialize drawing + m_drawing.Init(hwnd); + + // Set layered window + SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_COLORKEY); + + return true; + } + +protected: + Drawing m_drawing; +}; + +class PagerZoneTitleBar : public AdornZoneTitleBar +{ +public: + PagerZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi) noexcept : + AdornZoneTitleBar(hinstance, zone, dpi) + { + } + +protected: + void OnLButtonDown(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) override + { + auto q = (FLOAT)GetSystemMetricsForDpi(SM_CYHSCROLL, m_dpi); + if (q == 0 || m_zoneWindows.size() == 0) + { + return; + } + + auto h = m_zone.height(); + auto w = m_zone.width(); + + auto m = q * .25f; + auto l = h - (q + m); + + if (y < l) + { + auto ptr = std::find(m_zoneWindows.begin(), m_zoneWindows.end(), m_zoneCurrentWindow); + if (ptr == m_zoneWindows.end()) + { + return; + } + + auto i = std::distance(m_zoneWindows.begin(), ptr); + + auto last = m_zoneWindows.size() - 1; + if (x < w / 2) + { + auto prev = (i == 0) ? last : (i - 1); + SwitchToWindow(m_zoneWindows[prev]); + } + else + { + auto next = (i == last) ? 0 : (i + 1); + SwitchToWindow(m_zoneWindows[next]); + } + } + else + { + auto t = m_zoneWindows.size() * q; + auto o = (w - t) * .5f; + + auto i = (int)((x - o) / q); + SwitchToWindow(m_zoneWindows, i); + } + } + + void OnPaint(HWND hwnd) override + { + PAINTSTRUCT paint; + BeginPaint(m_window, &paint); + + if (m_drawing) + { + m_drawing.Drawing::BeginDraw(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + + auto color = Drawing::ConvertColor(WindowsColors::get_gray_text_color()); + + auto q = (FLOAT)GetSystemMetricsForDpi(SM_CYHSCROLL, m_dpi); + + auto h = m_zone.height(); + auto w = m_zone.width(); + + auto m = q * .25f; + auto l = h - (q + m); + + auto y = q * .7f; + auto z = q * .3f; + { + D2D1_TRIANGLE triangle = { + .point1 = D2D1::Point2F(m, l / 2), + .point2 = D2D1::Point2F(m + y * .86602540378f, (l / 2) - (y / 2)), + .point3 = D2D1::Point2F(m + y * .86602540378f, (l / 2) + (y / 2)) + }; + + auto geometry = m_drawing.CreateTriangle(triangle); + + if (geometry) + { + m_drawing.FillGeometry(geometry.get(), color, z * .5f); + } + } + + { + D2D1_TRIANGLE triangle = { + .point1 = D2D1::Point2F(w - m, l / 2), + .point2 = D2D1::Point2F(w - (m + y * .86602540378f), (l / 2) - (y / 2)), + .point3 = D2D1::Point2F(w - (m + y * .86602540378f), (l / 2) + (y / 2)) + }; + + auto geometry = m_drawing.CreateTriangle(triangle); + + if (geometry) + { + m_drawing.FillGeometry(geometry.get(), color, z * .5f); + } + } + + auto zoneCurrentWindow = m_zoneCurrentWindow; + auto t = m_zoneWindows.size() * q; + auto o = (w - t) * .5f; + for (auto i = 0; i < m_zoneWindows.size(); ++i) + { + auto center = D2D1::Point2(o + q * (i + .5f), l + (q * .5f)); + auto radius = q * .25f * (m_zoneWindows[i] == zoneCurrentWindow ? 2.f : 1.f); + auto circle = D2D1::Ellipse(center, radius, radius); + m_drawing.FillEllipse(circle, color); + } + + m_drawing.EndDraw(); + } + + EndPaint(m_window, &paint); + } +}; + +class SideZoneTitleBar : public VisibleZoneTitleBar +{ +protected: + static constexpr int c_style = WS_POPUP; + static constexpr int c_exStyle = WS_EX_TOOLWINDOW | WS_EX_LAYERED; + + int GetWidthFactor() const + { + constexpr int c_widthFactor = 2; + + auto q = c_widthFactor * GetSystemMetricsForDpi(SM_CYHSCROLL, m_dpi); + + if (q < 0 || m_zone.width() < 2 * q) + { + return 0; + } + + return q; + } + +public: + SideZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + VisibleZoneTitleBar(isAboveZone, zone, dpi) + { + auto q = GetWidthFactor(); + zone.get()->right = zone.left() + q; + + Init(hinstance, zone, c_style, c_exStyle); + } + + Rect GetInlineFrame() const override + { + auto q = GetWidthFactor(); + + Rect zone = m_zone; + zone.get()->left += q; + + return zone; + } + +protected: + bool OnCreate(HWND hwnd, LPCREATESTRUCT createStruct) override + { + VisibleZoneTitleBar::OnCreate(hwnd, createStruct); + + // Initialize drawing + m_drawing.Init(hwnd); + + // Set layered window + SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_COLORKEY); + + return true; + } + +protected: + Drawing m_drawing; +}; + +class ButtonsZoneTitleBar : public SideZoneTitleBar +{ +public: + ButtonsZoneTitleBar(HINSTANCE hinstance, Rect zone, UINT dpi, bool isAboveZone) noexcept : + SideZoneTitleBar(hinstance, zone, dpi, isAboveZone) + { + } + +protected: + void OnLButtonDown(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags) override + { + auto q = GetWidthFactor(); + if (q <= 0) + { + return; + } + + auto i = y / q; + SwitchToWindow(m_zoneWindows, i); + } + + void OnPaint(HWND hwnd) override + { + PAINTSTRUCT paint; + BeginPaint(m_window, &paint); + + if (m_drawing) + { + ZoneTitleBarColors colors; + auto q = GetWidthFactor(); + m_drawing.Drawing::BeginDraw(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + + for (auto i = 0; i < m_zoneWindows.size(); ++i) + { + auto m = .1f * q; + auto rect = D2D1::RectF(0.f + m, i * q + m, q - m, (i + 1) * q - m); + + if (m_zoneWindows[i] == m_zoneCurrentWindow) + { + m_drawing.FillRoundedRectangle(rect, colors.highlightFrameColor, .3f); + } + else + { + m_drawing.FillRoundedRectangle(rect, colors.frameColor, .3f); + } + + m = .17f * q; + auto iconRect = D2D1::RectF(0.f + m, i * q + m, q - m, (i + 1) * q - m); + DrawWindowIcon(m_drawing, iconRect, m_zoneWindows[i]); + } + + m_drawing.EndDraw(); + } + + EndPaint(m_window, &paint); + } +}; + class AutoHideZoneTitleBar : public IZoneTitleBar { public: @@ -773,9 +1033,17 @@ public: m_zoneTitleBar = std::make_unique(m_hinstance, m_zone, m_dpi, true); break; + case ZoneTitleBarStyle::Pager: + m_zoneTitleBar = std::make_unique(m_hinstance, m_zone, m_dpi); + break; + + case ZoneTitleBarStyle::Buttons: + m_zoneTitleBar = std::make_unique(m_hinstance, m_zone, m_dpi, true); + break; + case ZoneTitleBarStyle::None: default: - m_zoneTitleBar = std::make_unique(); + m_zoneTitleBar = std::make_unique(m_zone); break; } @@ -806,9 +1074,9 @@ public: } } - virtual int GetHeight() const override + Rect GetInlineFrame() const override { - return 0; + return m_zone; } protected: @@ -843,8 +1111,14 @@ std::unique_ptr MakeZoneTitleBar(ZoneTitleBarStyle style, HINSTAN case ZoneTitleBarStyle::Labels: return std::make_unique(hinstance, zone, dpi, false); + case ZoneTitleBarStyle::Pager: + return std::make_unique(hinstance, zone, dpi); + + case ZoneTitleBarStyle::Buttons: + return std::make_unique(hinstance, zone, dpi, false); + case ZoneTitleBarStyle::None: default: - return std::make_unique(); + return std::make_unique(zone); } } diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.h b/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.h index 07333856f4..c9a1778f20 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.h +++ b/src/modules/fancyzones/FancyZonesLib/ZoneTitleBar.h @@ -1,4 +1,5 @@ #pragma once +#include "util.h" #include "Window.h" #include "Settings.h" @@ -10,7 +11,7 @@ public: virtual void Show(bool show) = 0; virtual void UpdateZoneWindows(std::vector zoneWindows) = 0; virtual void ReadjustPos() = 0; - virtual int GetHeight() const = 0; + virtual FancyZonesUtils::Rect GetInlineFrame() const = 0; }; std::unique_ptr MakeZoneTitleBar(ZoneTitleBarStyle style, HINSTANCE hinstance, FancyZonesUtils::Rect zone, UINT dpi); \ No newline at end of file diff --git a/src/settings-ui/Settings.UI.Library/ViewModels/FancyZonesViewModel.cs b/src/settings-ui/Settings.UI.Library/ViewModels/FancyZonesViewModel.cs index 499f6690ea..26c0bf2794 100644 --- a/src/settings-ui/Settings.UI.Library/ViewModels/FancyZonesViewModel.cs +++ b/src/settings-ui/Settings.UI.Library/ViewModels/FancyZonesViewModel.cs @@ -51,6 +51,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels AutoHideTabs = 7, Labels = 8, AutoHideLabels = 9, + Pager = 10, + AutoHidePager = 11, + Buttons = 12, + AutoHideButtons = 13, } public FancyZonesViewModel(SettingsUtils settingsUtils, ISettingsRepository settingsRepository, ISettingsRepository moduleSettingsRepository, Func ipcMSGCallBackFunc, string configFileSubfolder = "") diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index a4a13f112a..b50ffd9eee 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -1192,6 +1192,12 @@ Made with 💗 by Microsoft and the PowerToys community. Labels + + Pager + + + Buttons + Auto hide diff --git a/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml b/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml index c3fcf5424b..d81022e461 100644 --- a/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml +++ b/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml @@ -104,6 +104,8 @@ + +