mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
[FancyZones] Zone title bar tabs style
This commit is contained in:
164
src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp
Normal file
164
src/modules/fancyzones/FancyZonesLib/CompositionDrawing.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "pch.h"
|
||||
#include "CompositionDrawing.h"
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
|
||||
void CompositionDrawing::Init(HWND window)
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
// Obtain the size of the drawing area
|
||||
if (!GetClientRect(window, m_renderRect.get()))
|
||||
{
|
||||
Logger::error("couldn't initialize CompositionDrawing: GetClientRect failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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());
|
||||
if (!m_d2dFactory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11CreateDevice(
|
||||
nullptr,
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
nullptr,
|
||||
0,
|
||||
D3D11_SDK_VERSION,
|
||||
m_d3dDevice.put(),
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (!m_d3dDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_d3dDevice->QueryInterface(__uuidof(m_dxgiDevice), m_dxgiDevice.put_void());
|
||||
if (!m_dxgiDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CreateDXGIFactory2(0, __uuidof(m_dxgiFactory), m_dxgiFactory.put_void());
|
||||
if (!m_dxgiFactory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_d2dFactory->CreateDevice(m_dxgiDevice.get(), m_d2dDevice.put());
|
||||
if (!m_d2dDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
winrt::com_ptr<ID2D1DeviceContext5> device_context;
|
||||
m_d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, device_context.put());
|
||||
if (!device_context)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderTarget = device_context;
|
||||
|
||||
// Size specific
|
||||
if (m_renderRect.width() == 0 || m_renderRect.height() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 sc_description = {};
|
||||
sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
sc_description.BufferCount = 2;
|
||||
sc_description.SampleDesc.Count = 1;
|
||||
sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
|
||||
sc_description.Width = m_renderRect.width();
|
||||
sc_description.Height = m_renderRect.height();
|
||||
|
||||
m_dxgiFactory->CreateSwapChainForComposition(
|
||||
m_dxgiDevice.get(),
|
||||
&sc_description,
|
||||
nullptr,
|
||||
m_dxgiSwapChain.put());
|
||||
if (!m_dxgiSwapChain)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DCompositionCreateDevice(
|
||||
m_dxgiDevice.get(),
|
||||
__uuidof(m_compositionDevice),
|
||||
m_compositionDevice.put_void());
|
||||
if (!m_compositionDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_compositionDevice->CreateTargetForHwnd(m_window, true, m_compositionTarget.put());
|
||||
if (!m_compositionTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_compositionDevice->CreateVisual(m_compositionVisual.put());
|
||||
if (!m_compositionVisual)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_compositionVisual->SetContent(m_dxgiSwapChain.get());
|
||||
m_compositionTarget->SetRoot(m_compositionVisual.get());
|
||||
|
||||
m_dxgiSwapChain->GetBuffer(0, __uuidof(m_dxgiSurface), m_dxgiSurface.put_void());
|
||||
if (!m_dxgiSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D2D1_BITMAP_PROPERTIES1 properties = {};
|
||||
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
||||
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
|
||||
|
||||
device_context->CreateBitmapFromDxgiSurface(
|
||||
m_dxgiSurface.get(),
|
||||
properties,
|
||||
m_d2dBitmap.put());
|
||||
if (!m_d2dBitmap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
device_context->SetTarget(m_d2dBitmap.get());
|
||||
}
|
||||
|
||||
void CompositionDrawing::BeginDraw()
|
||||
{
|
||||
m_renderTarget->BeginDraw();
|
||||
}
|
||||
|
||||
void CompositionDrawing::EndDraw()
|
||||
{
|
||||
m_renderTarget->EndDraw();
|
||||
|
||||
if (m_dxgiSwapChain && m_compositionDevice)
|
||||
{
|
||||
m_dxgiSwapChain->Present(1, 0);
|
||||
m_compositionDevice->Commit();
|
||||
}
|
||||
}
|
||||
34
src/modules/fancyzones/FancyZonesLib/CompositionDrawing.h
Normal file
34
src/modules/fancyzones/FancyZonesLib/CompositionDrawing.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "Drawing.h"
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <Windows.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <d3d11_2.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_3helper.h>
|
||||
#include <d2d1helper.h>
|
||||
#include <dcomp.h>
|
||||
#include <dwmapi.h>
|
||||
#include <string>
|
||||
|
||||
class CompositionDrawing : public Drawing
|
||||
{
|
||||
public:
|
||||
void Init(HWND window);
|
||||
void BeginDraw();
|
||||
void EndDraw();
|
||||
|
||||
private:
|
||||
winrt::com_ptr<ID3D11Device> m_d3dDevice;
|
||||
winrt::com_ptr<IDXGIDevice> m_dxgiDevice;
|
||||
winrt::com_ptr<IDXGIFactory2> m_dxgiFactory;
|
||||
winrt::com_ptr<IDXGISwapChain1> m_dxgiSwapChain;
|
||||
winrt::com_ptr<IDCompositionDevice> m_compositionDevice;
|
||||
winrt::com_ptr<IDCompositionTarget> m_compositionTarget;
|
||||
winrt::com_ptr<IDCompositionVisual> m_compositionVisual;
|
||||
winrt::com_ptr<IDXGISurface2> m_dxgiSurface;
|
||||
winrt::com_ptr<ID2D1Bitmap1> m_d2dBitmap;
|
||||
winrt::com_ptr<ID2D1Factory6> m_d2dFactory;
|
||||
winrt::com_ptr<ID2D1Device5> m_d2dDevice;
|
||||
};
|
||||
@@ -41,10 +41,15 @@ IWICImagingFactory2* Drawing::GetImageFactory()
|
||||
return pImageFactory;
|
||||
}
|
||||
|
||||
Drawing::Drawing(HWND window)
|
||||
Drawing::Drawing()
|
||||
{
|
||||
m_window = nullptr;
|
||||
m_renderTarget = nullptr;
|
||||
}
|
||||
|
||||
void Drawing::Init(HWND window)
|
||||
{
|
||||
m_window = window;
|
||||
m_renderTarget = nullptr;
|
||||
|
||||
// Obtain the size of the drawing area.
|
||||
if (!GetClientRect(window, m_renderRect.get()))
|
||||
@@ -64,12 +69,15 @@ Drawing::Drawing(HWND window)
|
||||
auto renderTargetSize = D2D1::SizeU(m_renderRect.width(), m_renderRect.height());
|
||||
auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(window, renderTargetSize);
|
||||
|
||||
auto hr = GetD2DFactory()->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, m_renderTarget.put());
|
||||
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
|
||||
@@ -85,7 +93,7 @@ void Drawing::BeginDraw(const D2D1_COLOR_F& backColor)
|
||||
m_renderTarget->Clear(backColor);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IDWriteTextFormat> Drawing::CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize)
|
||||
winrt::com_ptr<IDWriteTextFormat> Drawing::CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize, DWRITE_FONT_WEIGHT fontWeight)
|
||||
{
|
||||
winrt::com_ptr<IDWriteTextFormat> textFormat = nullptr;
|
||||
|
||||
@@ -93,7 +101,7 @@ winrt::com_ptr<IDWriteTextFormat> Drawing::CreateTextFormat(LPCWSTR fontFamilyNa
|
||||
|
||||
if (writeFactory)
|
||||
{
|
||||
writeFactory->CreateTextFormat(fontFamilyName, nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-US", textFormat.put());
|
||||
writeFactory->CreateTextFormat(fontFamilyName, nullptr, fontWeight, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-US", textFormat.put());
|
||||
}
|
||||
|
||||
return textFormat;
|
||||
@@ -151,6 +159,24 @@ void Drawing::FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -184,6 +210,25 @@ void Drawing::DrawTextW(std::wstring text, IDWriteTextFormat* textFormat, const
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -11,29 +11,32 @@ class Drawing
|
||||
public:
|
||||
static D2D1_COLOR_F ConvertColor(COLORREF color);
|
||||
|
||||
Drawing(HWND window);
|
||||
Drawing();
|
||||
void Init(HWND window);
|
||||
|
||||
operator bool() const;
|
||||
void BeginDraw(const D2D1_COLOR_F& backColor);
|
||||
|
||||
winrt::com_ptr<IDWriteTextFormat> CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize);
|
||||
winrt::com_ptr<IDWriteTextFormat> CreateTextFormat(LPCWSTR fontFamilyName, FLOAT fontSize, DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL);
|
||||
winrt::com_ptr<ID2D1SolidColorBrush> CreateBrush(D2D1_COLOR_F color);
|
||||
winrt::com_ptr<ID2D1Bitmap> CreateIcon(HICON icon);
|
||||
|
||||
void FillRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color);
|
||||
void FillRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color);
|
||||
void DrawRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth = 1.0f);
|
||||
void DrawRoundedRectangle(const D2D1_RECT_F& rect, D2D1_COLOR_F color, float strokeWidth = 1.0f);
|
||||
void DrawTextW(std::wstring text, IDWriteTextFormat* format, const D2D1_RECT_F& rect, D2D1_COLOR_F color);
|
||||
void DrawTextTrim(std::wstring text, IDWriteTextFormat* format, const D2D1_RECT_F& rect, D2D1_COLOR_F color);
|
||||
void DrawBitmap(const D2D1_RECT_F& rect, ID2D1Bitmap* bitmap);
|
||||
|
||||
void EndDraw();
|
||||
|
||||
private:
|
||||
protected:
|
||||
static ID2D1Factory* GetD2DFactory();
|
||||
static IDWriteFactory* GetWriteFactory();
|
||||
static IWICImagingFactory2* GetImageFactory();
|
||||
|
||||
HWND m_window = nullptr;
|
||||
FancyZonesUtils::Rect m_renderRect{};
|
||||
winrt::com_ptr<ID2D1HwndRenderTarget> m_renderTarget = nullptr;
|
||||
winrt::com_ptr<ID2D1RenderTarget> m_renderTarget = nullptr;
|
||||
};
|
||||
|
||||
@@ -35,11 +35,15 @@
|
||||
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<AdditionalDependencies>Dcomp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FancyZonesData\CustomLayouts.h" />
|
||||
<ClInclude Include="FancyZonesData\AppliedLayouts.h" />
|
||||
<ClInclude Include="FancyZonesData\AppZoneHistory.h" />
|
||||
<ClInclude Include="CompositionDrawing.h" />
|
||||
<ClInclude Include="Drawing.h" />
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesDataTypes.h" />
|
||||
@@ -83,6 +87,7 @@
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompositionDrawing.cpp" />
|
||||
<ClCompile Include="Drawing.cpp" />
|
||||
<ClCompile Include="FancyZones.cpp" />
|
||||
<ClCompile Include="FancyZonesDataTypes.cpp" />
|
||||
|
||||
@@ -123,6 +123,9 @@
|
||||
<ClInclude Include="Drawing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompositionDrawing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -206,6 +209,9 @@
|
||||
<ClCompile Include="Drawing.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompositionDrawing.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -16,7 +16,8 @@ enum struct ZoneTitleBarStyle : int
|
||||
None = 0,
|
||||
Numbers = 1,
|
||||
Icons = 2,
|
||||
EnumElements = 3, // number of elements in the enum, not counting this
|
||||
Tabs = 3,
|
||||
EnumElements = 4, // 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
|
||||
@@ -48,7 +49,7 @@ struct Settings
|
||||
std::wstring zoneNumberColor = L"#000000";
|
||||
int zoneHighlightOpacity = 50;
|
||||
OverlappingZonesAlgorithm overlappingZonesAlgorithm = OverlappingZonesAlgorithm::Smallest;
|
||||
ZoneTitleBarStyle zoneTitleBarStyle = ZoneTitleBarStyle::Icons;
|
||||
ZoneTitleBarStyle zoneTitleBarStyle = ZoneTitleBarStyle::Tabs;
|
||||
PowerToysSettings::HotkeyObject editorHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, true, VK_OEM_3);
|
||||
bool windowSwitching = true;
|
||||
PowerToysSettings::HotkeyObject nextTabHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_NEXT);
|
||||
|
||||
@@ -7,7 +7,7 @@ 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) noexcept :
|
||||
Window::Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedStyle, FancyZonesUtils::Rect position, LPCWSTR windowName, HWND parent, HMENU menu, int showCommand) noexcept :
|
||||
m_window(NULL),
|
||||
m_proc(proc)
|
||||
{
|
||||
@@ -17,6 +17,7 @@ Window::Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedSty
|
||||
WNDCLASSEXW wcex{};
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.lpfnWndProc = s_WndProc;
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.hInstance = hinstance;
|
||||
wcex.lpszClassName = reinterpret_cast<LPCWSTR>(NonLocalizable::WindowClassName);
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
@@ -37,13 +38,16 @@ Window::Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedSty
|
||||
hinstance,
|
||||
this);
|
||||
|
||||
ShowWindow(m_window, SW_SHOWNOACTIVATE);
|
||||
if (showCommand != SW_HIDE)
|
||||
{
|
||||
ShowWindow(m_window, showCommand);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Window::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
auto thisRef = reinterpret_cast<Window*>(GetWindowLongPtrW(window, GWLP_USERDATA));
|
||||
if (!thisRef && (message == WM_CREATE))
|
||||
if (!thisRef && (message == WM_NCCREATE))
|
||||
{
|
||||
const auto createStruct = reinterpret_cast<LPCREATESTRUCT>(lparam);
|
||||
thisRef = reinterpret_cast<Window*>(createStruct->lpCreateParams);
|
||||
@@ -55,8 +59,9 @@ LRESULT CALLBACK Window::s_WndProc(HWND window, UINT message, WPARAM wparam, LPA
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(thisRef));
|
||||
}
|
||||
|
||||
return thisRef ? thisRef->m_proc(window, message, wparam, lparam) :
|
||||
DefWindowProcW(window, message, wparam, lparam);
|
||||
return (thisRef && thisRef->m_proc) ?
|
||||
thisRef->m_proc(window, message, wparam, lparam) :
|
||||
DefWindowProcW(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
|
||||
@@ -7,7 +7,7 @@ using WndProc = std::function<LRESULT(HWND window, UINT message, WPARAM wparam,
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedStyle, FancyZonesUtils::Rect position, LPCWSTR windowName = NULL, HWND parent = NULL, HMENU menu = NULL) noexcept;
|
||||
Window(HINSTANCE hinstance, WndProc proc, DWORD style, DWORD extendedStyle, FancyZonesUtils::Rect position, LPCWSTR windowName = NULL, HWND parent = NULL, HMENU menu = NULL, int show = SW_SHOWNOACTIVATE) noexcept;
|
||||
~Window();
|
||||
|
||||
Window(const Window&) = delete;
|
||||
|
||||
@@ -1,11 +1,57 @@
|
||||
#include "pch.h"
|
||||
#include "ZoneTitleBar.h"
|
||||
#include "Drawing.h"
|
||||
#include "CompositionDrawing.h"
|
||||
#include <set>
|
||||
#include <windowsx.h>
|
||||
|
||||
/* void Cls_OnDwmNcRenderingChanged(HWND hwnd, BOOL fEnabled) */
|
||||
#define HANDLE_WM_DWMNCRENDERINGCHANGED(hwnd, wParam, lParam, fn) \
|
||||
((fn)((hwnd), (BOOL)(wParam)), 0L)
|
||||
|
||||
|
||||
using namespace FancyZonesUtils;
|
||||
|
||||
|
||||
static HWND GetWindowAboveAllOthers(const std::vector<HWND>& windows)
|
||||
{
|
||||
if (windows.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::set<HWND> windowsSet(windows.begin(), windows.end());
|
||||
|
||||
// Get the window above all others
|
||||
HWND max = NULL;
|
||||
for (HWND current = windows.front(); !windows.empty() && current != NULL; current = GetWindow(current, GW_HWNDPREV))
|
||||
{
|
||||
auto i = windowsSet.find(current);
|
||||
if (i != windowsSet.end())
|
||||
{
|
||||
max = current;
|
||||
windowsSet.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static void DrawWindowIcon(Drawing& drawing, const D2D1_RECT_F& rect, HWND window)
|
||||
{
|
||||
auto icon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0);
|
||||
if (icon == nullptr)
|
||||
{
|
||||
icon = (HICON)GetClassLongPtrW(window, GCLP_HICON);
|
||||
}
|
||||
|
||||
if (icon != nullptr)
|
||||
{
|
||||
auto bitmap = drawing.CreateIcon(icon);
|
||||
drawing.DrawBitmap(rect, bitmap.get());
|
||||
}
|
||||
}
|
||||
|
||||
class NoZoneTitleBar : public IZoneTitleBar
|
||||
{
|
||||
public:
|
||||
@@ -18,10 +64,10 @@ public:
|
||||
int GetHeight() const override { return 0; }
|
||||
};
|
||||
|
||||
class ZoneTitleBar : public IZoneTitleBar
|
||||
class SlimZoneTitleBar : public IZoneTitleBar
|
||||
{
|
||||
public:
|
||||
ZoneTitleBar(HINSTANCE hinstance, Rect zone) noexcept :
|
||||
SlimZoneTitleBar(HINSTANCE hinstance, Rect zone) noexcept :
|
||||
m_window(
|
||||
hinstance,
|
||||
[this](HWND window, UINT message, WPARAM wParam, LPARAM lParam) { return WndProc(window, message, wParam, lParam); },
|
||||
@@ -30,8 +76,7 @@ public:
|
||||
ResetRect(zone),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL),
|
||||
m_drawing(m_window)
|
||||
NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -67,6 +112,7 @@ protected:
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
HANDLE_MSG(window, WM_CREATE, Init);
|
||||
HANDLE_MSG(window, WM_PAINT, Render);
|
||||
HANDLE_MSG(window, WM_LBUTTONDOWN, Click);
|
||||
default:
|
||||
@@ -74,6 +120,13 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
bool Init(HWND hwnd, LPCREATESTRUCT)
|
||||
{
|
||||
m_drawing.Init(hwnd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Click(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags)
|
||||
{
|
||||
auto len = m_height;
|
||||
@@ -92,26 +145,7 @@ protected:
|
||||
|
||||
HWND GetZoneCurrentWindow()
|
||||
{
|
||||
if (m_zoneWindows.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::set<HWND> zoneWindows(m_zoneWindows.begin(), m_zoneWindows.end());
|
||||
|
||||
// Get the window above all others
|
||||
HWND max = NULL;
|
||||
for (HWND current = m_zoneWindows.front(); !zoneWindows.empty() && current != NULL; current = GetWindow(current, GW_HWNDPREV))
|
||||
{
|
||||
auto i = zoneWindows.find(current);
|
||||
if (i != zoneWindows.end())
|
||||
{
|
||||
max = current;
|
||||
zoneWindows.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
return GetWindowAboveAllOthers(m_zoneWindows);
|
||||
}
|
||||
|
||||
Rect ResetRect(Rect zone)
|
||||
@@ -124,15 +158,15 @@ protected:
|
||||
protected:
|
||||
int m_height;
|
||||
std::vector<HWND> m_zoneWindows;
|
||||
Window m_window;
|
||||
Drawing m_drawing;
|
||||
Window m_window;
|
||||
};
|
||||
|
||||
class NumbersZoneTitleBar : public ZoneTitleBar
|
||||
class NumbersZoneTitleBar : public SlimZoneTitleBar
|
||||
{
|
||||
public:
|
||||
NumbersZoneTitleBar(HINSTANCE hinstance, Rect zone) noexcept :
|
||||
ZoneTitleBar(hinstance, zone)
|
||||
SlimZoneTitleBar(hinstance, zone)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -182,29 +216,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class IconsZoneTitleBar : public ZoneTitleBar
|
||||
class IconsZoneTitleBar : public SlimZoneTitleBar
|
||||
{
|
||||
public:
|
||||
IconsZoneTitleBar(HINSTANCE hinstance, Rect zone) noexcept :
|
||||
ZoneTitleBar(hinstance, zone)
|
||||
SlimZoneTitleBar(hinstance, zone)
|
||||
{
|
||||
}
|
||||
|
||||
void DrawIcon(HWND window, const D2D1_RECT_F& rect)
|
||||
{
|
||||
auto icon = (HICON)SendMessageW(window, WM_GETICON, ICON_SMALL2, 0);
|
||||
if (icon == nullptr)
|
||||
{
|
||||
icon = (HICON)GetClassLongPtrW(window, GCLP_HICONSM);
|
||||
}
|
||||
|
||||
if (icon != nullptr)
|
||||
{
|
||||
auto bitmap = m_drawing.CreateIcon(icon);
|
||||
m_drawing.DrawBitmap(rect, bitmap.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Render(HWND hwnd) override
|
||||
{
|
||||
PAINTSTRUCT paint;
|
||||
@@ -230,7 +249,7 @@ public:
|
||||
{
|
||||
constexpr float p = .15f;
|
||||
auto iconRect = D2D1::Rect(len * (i + p), len * p, len * (i + 1 - p), len * (1 - p));
|
||||
DrawIcon(m_zoneWindows[i], iconRect);
|
||||
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));
|
||||
@@ -245,6 +264,289 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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 TabsZoneTitleBar : public IZoneTitleBar
|
||||
{
|
||||
private:
|
||||
static constexpr int c_style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME;
|
||||
static constexpr int c_exStyle = WS_EX_NOREDIRECTIONBITMAP;
|
||||
static constexpr int c_widthFactor = 4;
|
||||
|
||||
public:
|
||||
TabsZoneTitleBar(HINSTANCE hinstance, Rect zone) noexcept :
|
||||
m_hiddenWindow(hinstance),
|
||||
m_zoneCurrentWindow(NULL),
|
||||
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 UpdateZoneWindows(std::vector<HWND> zoneWindows) override
|
||||
{
|
||||
m_zoneWindows = zoneWindows;
|
||||
ReadjustPos();
|
||||
}
|
||||
|
||||
void ReadjustPos() override
|
||||
{
|
||||
auto zoneCurrentWindow = GetZoneCurrentWindow();
|
||||
|
||||
// Put the zone title bar just below the zone current window
|
||||
if (zoneCurrentWindow != NULL)
|
||||
{
|
||||
m_zoneCurrentWindow = zoneCurrentWindow;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
Render(m_window);
|
||||
}
|
||||
|
||||
int GetHeight() const override { return m_height; }
|
||||
|
||||
protected:
|
||||
LRESULT WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
LRESULT result;
|
||||
auto handled = DwmDefWindowProc(window, message, wParam, lParam, &result);
|
||||
if (handled)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (message)
|
||||
{
|
||||
HANDLE_MSG(window, WM_CREATE, Init);
|
||||
HANDLE_MSG(window, WM_NCCALCSIZE, CalcNonClientSize);
|
||||
HANDLE_MSG(window, WM_WINDOWPOSCHANGING, WindowPosChanging);
|
||||
HANDLE_MSG(window, WM_DWMNCRENDERINGCHANGED, DwmNonClientRenderingChanged);
|
||||
HANDLE_MSG(window, WM_PAINT, Render);
|
||||
HANDLE_MSG(window, WM_LBUTTONDOWN, Click);
|
||||
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 needed)
|
||||
MARGINS margins = { 0, 0, 2 * m_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)
|
||||
{
|
||||
if (!calc)
|
||||
{
|
||||
return FORWARD_WM_NCCALCSIZE(hwnd, calc, info, DefWindowProcW);
|
||||
}
|
||||
|
||||
auto xBorder = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
auto yBorder = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE);
|
||||
|
||||
auto& coordinates = info->rgrc[0];
|
||||
coordinates.left += xBorder;
|
||||
coordinates.right -= xBorder;
|
||||
coordinates.bottom -= yBorder;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DwmNonClientRenderingChanged(HWND hwnd, BOOL enabled)
|
||||
{
|
||||
Rect newWindowRect = m_zone;
|
||||
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(hwnd, &windowRect);
|
||||
|
||||
// Take care of borders
|
||||
RECT frameRect{};
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||
{
|
||||
LONG leftMargin = frameRect.left - windowRect.left;
|
||||
LONG rightMargin = frameRect.right - windowRect.right;
|
||||
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
||||
|
||||
newWindowRect.get()->left -= leftMargin;
|
||||
newWindowRect.get()->right -= rightMargin;
|
||||
newWindowRect.get()->bottom -= bottomMargin;
|
||||
|
||||
SetWindowPos(hwnd, nullptr, newWindowRect.left(), newWindowRect.top(), newWindowRect.width(), newWindowRect.height(), SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WindowPosChanging(HWND hwnd, LPWINDOWPOS pos)
|
||||
{
|
||||
if (m_zoneCurrentWindow != NULL)
|
||||
{
|
||||
// If changing the Z order and the change does not put it in the correct place
|
||||
if (pos->hwndInsertAfter != m_zoneCurrentWindow)
|
||||
{
|
||||
// Abort the change
|
||||
pos->flags |= SWP_NOZORDER;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Render(HWND hwnd)
|
||||
{
|
||||
PAINTSTRUCT paint;
|
||||
BeginPaint(m_window, &paint);
|
||||
|
||||
auto backColor = Drawing::ConvertColor(GetSysColor(COLOR_WINDOW));
|
||||
auto frameColor = Drawing::ConvertColor(GetSysColor(COLOR_3DFACE));
|
||||
auto textColor = Drawing::ConvertColor(GetSysColor(COLOR_BTNTEXT));
|
||||
|
||||
auto highlightFrameColor = Drawing::ConvertColor(GetSysColor(COLOR_HIGHLIGHT));
|
||||
auto highlightTextColor = Drawing::ConvertColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
|
||||
auto captionHeight = GetSystemMetrics(SM_CYCAPTION);
|
||||
|
||||
auto zoneCurrentWindow = GetZoneCurrentWindow();
|
||||
|
||||
NONCLIENTMETRICS metrics{};
|
||||
metrics.cbSize = sizeof(metrics);
|
||||
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, 0);
|
||||
TCHAR text[100]{};
|
||||
|
||||
if (m_drawing)
|
||||
{
|
||||
m_drawing.BeginDraw();
|
||||
|
||||
auto textFormat = m_drawing.CreateTextFormat(
|
||||
metrics.lfCaptionFont.lfFaceName,
|
||||
float(-metrics.lfCaptionFont.lfHeight),
|
||||
(DWRITE_FONT_WEIGHT)metrics.lfCaptionFont.lfWeight);
|
||||
|
||||
{
|
||||
for (auto i = 0; i < m_zoneWindows.size(); ++i)
|
||||
{
|
||||
auto xOffset = m_height * (1 + c_widthFactor * i);
|
||||
auto yOffset = 0;
|
||||
|
||||
auto backMargin = (m_height - captionHeight) * .4f;
|
||||
auto backHeight = m_height - 2 * backMargin;
|
||||
auto backWidth = c_widthFactor * m_height - 2 * backMargin;
|
||||
auto backRect = D2D1::RectF(
|
||||
float(xOffset + backMargin),
|
||||
float(yOffset + backMargin),
|
||||
float(xOffset + backMargin + backWidth),
|
||||
float(yOffset + backMargin + backHeight));
|
||||
m_drawing.FillRoundedRectangle(backRect, m_zoneWindows[i] == zoneCurrentWindow ? highlightFrameColor : frameColor);
|
||||
|
||||
auto iconMargin = (m_height - captionHeight) * .5f;
|
||||
auto iconRect = D2D1::Rect(
|
||||
xOffset + iconMargin,
|
||||
yOffset + iconMargin,
|
||||
xOffset + iconMargin + captionHeight,
|
||||
yOffset + iconMargin + captionHeight);
|
||||
DrawWindowIcon(m_drawing, iconRect, m_zoneWindows[i]);
|
||||
|
||||
if (textFormat)
|
||||
{
|
||||
auto textMargin = (m_height - captionHeight) * .5f;
|
||||
auto textRect = D2D1::Rect(
|
||||
float(xOffset + m_height),
|
||||
float(yOffset + textMargin),
|
||||
float(xOffset + c_widthFactor * m_height - textMargin),
|
||||
float(yOffset + iconMargin + captionHeight));
|
||||
|
||||
text[0] = TEXT('\0');
|
||||
GetWindowText(m_zoneWindows[i], text, ARRAYSIZE(text));
|
||||
m_drawing.DrawTextTrim(text, textFormat.get(), textRect, m_zoneWindows[i] == zoneCurrentWindow ? highlightTextColor : textColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_drawing.EndDraw();
|
||||
}
|
||||
|
||||
EndPaint(m_window, &paint);
|
||||
}
|
||||
|
||||
void Click(HWND hwnd, BOOL doubleClick, int x, int y, UINT keyFlags)
|
||||
{
|
||||
auto len = m_height;
|
||||
if (len == 0 || x < len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto i = (x - len) / (len * c_widthFactor);
|
||||
|
||||
if (i < m_zoneWindows.size())
|
||||
{
|
||||
SwitchToWindow(m_zoneWindows[i]);
|
||||
}
|
||||
}
|
||||
|
||||
HWND GetZoneCurrentWindow()
|
||||
{
|
||||
return GetWindowAboveAllOthers(m_zoneWindows);
|
||||
}
|
||||
|
||||
Rect ResetRect(Rect zone)
|
||||
{
|
||||
m_zone = zone;
|
||||
|
||||
RECT rect{};
|
||||
AdjustWindowRectEx(&rect, c_style, FALSE, c_exStyle);
|
||||
|
||||
auto height = -rect.top;
|
||||
m_height = height > zone.height() ? 0 : height;
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
protected:
|
||||
HiddenWindow m_hiddenWindow;
|
||||
HWND m_zoneCurrentWindow;
|
||||
Rect m_zone;
|
||||
int m_height;
|
||||
std::vector<HWND> m_zoneWindows;
|
||||
CompositionDrawing m_drawing;
|
||||
Window m_window;
|
||||
};
|
||||
|
||||
std::unique_ptr<IZoneTitleBar> MakeZoneTitleBar(ZoneTitleBarStyle style, HINSTANCE hinstance, Rect zone)
|
||||
{
|
||||
switch (style)
|
||||
@@ -255,6 +557,9 @@ std::unique_ptr<IZoneTitleBar> MakeZoneTitleBar(ZoneTitleBarStyle style, HINSTAN
|
||||
case ZoneTitleBarStyle::Icons:
|
||||
return std::make_unique<IconsZoneTitleBar>(hinstance, zone);
|
||||
|
||||
case ZoneTitleBarStyle::Tabs:
|
||||
return std::make_unique<TabsZoneTitleBar>(hinstance, zone);
|
||||
|
||||
case ZoneTitleBarStyle::None:
|
||||
default:
|
||||
return std::make_unique<NoZoneTitleBar>();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "Window.h"
|
||||
#include "Drawing.h"
|
||||
#include "Settings.h"
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public static readonly bool DefaultUseCursorposEditorStartupscreen = true;
|
||||
public static readonly bool DefaultFancyzonesQuickLayoutSwitch = true;
|
||||
public static readonly bool DefaultFancyzonesFlashZonesOnQuickSwitch = true;
|
||||
public static readonly int DefaultFancyzonesZoneTitleBarStyle = 2;
|
||||
public static readonly int DefaultFancyzonesZoneTitleBarStyle = 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
None = 0,
|
||||
Numbers = 1,
|
||||
Icons = 2,
|
||||
Tabs = 3,
|
||||
}
|
||||
|
||||
public FancyZonesViewModel(SettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<FancyZonesSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
|
||||
|
||||
@@ -1186,6 +1186,9 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<data name="FancyZones_ZoneTitleBarStyle_Icons.Content" xml:space="preserve">
|
||||
<value>Icons</value>
|
||||
</data>
|
||||
<data name="FancyZones_ZoneTitleBarStyle_Tabs.Content" xml:space="preserve">
|
||||
<value>Tabs</value>
|
||||
</data>
|
||||
<data name="PowerLauncher_Plugins.Header" xml:space="preserve">
|
||||
<value>Plugins</value>
|
||||
</data>
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
<ComboBoxItem x:Uid="FancyZones_ZoneTitleBarStyle_None" />
|
||||
<ComboBoxItem x:Uid="FancyZones_ZoneTitleBarStyle_Numbers" />
|
||||
<ComboBoxItem x:Uid="FancyZones_ZoneTitleBarStyle_Icons" />
|
||||
<ComboBoxItem x:Uid="FancyZones_ZoneTitleBarStyle_Tabs" />
|
||||
</ComboBox>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
|
||||
Reference in New Issue
Block a user