From 714ca349ff76a09de68605f06116934281e0e8d8 Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Thu, 20 Jan 2022 14:02:38 +0300 Subject: [PATCH] [FancyZones] Split zones-settings: custom layouts (#15642) --- .../fancyzones/FancyZonesLib/FancyZones.cpp | 25 +- .../FancyZonesLib/FancyZonesData.cpp | 61 ++--- .../fancyzones/FancyZonesLib/FancyZonesData.h | 14 +- .../FancyZonesData/CustomLayouts.cpp | 233 ++++++++++++++++ .../FancyZonesData/CustomLayouts.h | 75 ++++++ .../FancyZonesLib/FancyZonesDataTypes.h | 2 +- .../FancyZonesLib/FancyZonesLib.vcxproj | 5 + .../FancyZonesLib.vcxproj.filters | 6 + .../FancyZonesWinHookEventIDs.cpp | 2 + .../FancyZonesLib/FancyZonesWinHookEventIDs.h | 1 + .../fancyzones/FancyZonesLib/JsonHelpers.cpp | 66 +++-- .../fancyzones/FancyZonesLib/JsonHelpers.h | 13 +- .../fancyzones/FancyZonesLib/ZoneSet.cpp | 72 +++-- .../fancyzones/FancyZonesLib/trace.cpp | 16 +- .../UnitTests/CustomLayoutsTests.Spec.cpp | 194 ++++++++++++++ .../UnitTests/JsonHelpers.Tests.cpp | 178 +------------ .../UnitTests/UnitTests.vcxproj | 1 + .../UnitTests/UnitTests.vcxproj.filters | 3 + .../UnitTests/ZoneSet.Spec.cpp | 62 +---- .../editor/FancyZonesEditor/EditorWindow.cs | 1 + .../FancyZonesEditor/MainWindow.xaml.cs | 5 + .../Properties/Resources.Designer.cs | 9 + .../Properties/Resources.resx | 5 +- .../Utils/FancyZonesEditorIO.cs | 252 +++++++++++------- 24 files changed, 853 insertions(+), 448 deletions(-) create mode 100644 src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.cpp create mode 100644 src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.h create mode 100644 src/modules/fancyzones/FancyZonesTests/UnitTests/CustomLayoutsTests.Spec.cpp diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index b550df3919..2ad1d46972 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ public: FancyZonesDataInstance().ReplaceZoneSettingsFileFromOlderVersions(); LayoutHotkeys::instance().LoadData(); + CustomLayouts::instance().LoadData(); } // IFancyZones @@ -775,6 +777,10 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa { LayoutHotkeys::instance().LoadData(); } + else if (message == WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE) + { + CustomLayouts::instance().LoadData(); + } else if (message == WM_PRIV_QUICK_LAYOUT_KEY) { ApplyQuickLayout(static_cast(lparam)); @@ -1307,23 +1313,22 @@ void FancyZones::ApplyQuickLayout(int key) noexcept return; } + // Find a custom zone set with this uuid and apply it + auto layout = CustomLayouts::instance().GetLayout(layoutId.value()); + if (!layout) + { + return; + } + auto uuidStr = FancyZonesUtils::GuidToString(layoutId.value()); if (!uuidStr) { return; } - auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId); - - // Find a custom zone set with this uuid and apply it - auto customZoneSets = FancyZonesDataInstance().GetCustomZoneSetsMap(); - - if (!customZoneSets.contains(uuidStr.value())) - { - return; - } - FancyZonesDataTypes::ZoneSetData data{ .uuid = uuidStr.value(), .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom }; + + auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId); FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data); FancyZonesDataInstance().SaveZoneSettings(); UpdateZoneSets(); diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp index 6ddbcaf696..057f53512c 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -170,6 +171,12 @@ void FancyZonesData::ReplaceZoneSettingsFileFromOlderVersions() //deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); //customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); + auto customLayouts = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); + if (customLayouts) + { + JSONHelpers::SaveCustomLayouts(customLayouts.value()); + } + auto templates = JSONHelpers::ParseLayoutTemplates(fancyZonesDataJSON); if (templates) { @@ -197,12 +204,6 @@ const JSONHelpers::TDeviceInfoMap& FancyZonesData::GetDeviceInfoMap() const return deviceInfoMap; } -const JSONHelpers::TCustomZoneSetsMap& FancyZonesData::GetCustomZoneSetsMap() const -{ - std::scoped_lock lock{ dataLock }; - return customZoneSetsMap; -} - const std::unordered_map>& FancyZonesData::GetAppZoneHistoryMap() const { std::scoped_lock lock{ dataLock }; @@ -223,13 +224,6 @@ std::optional FancyZonesData::FindDeviceInf return std::nullopt; } -std::optional FancyZonesData::FindCustomZoneSet(const std::wstring& guid) const -{ - std::scoped_lock lock{ dataLock }; - auto it = customZoneSetsMap.find(guid); - return it != end(customZoneSetsMap) ? std::optional{ it->second } : std::nullopt; -} - bool FancyZonesData::AddDevice(const FancyZonesDataTypes::DeviceIdData& deviceId) { _TRACER_; @@ -604,25 +598,29 @@ void FancyZonesData::SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& d deviceInfo.activeZoneSet = data; // If the zone set is custom, we need to copy its properties to the device - auto zonesetIt = customZoneSetsMap.find(data.uuid); - if (zonesetIt != customZoneSetsMap.end()) + auto id = FancyZonesUtils::GuidFromString(data.uuid); + if (id.has_value()) { - if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Grid) + auto layout = CustomLayouts::instance().GetLayout(id.value()); + if (layout) { - auto layoutInfo = std::get(zonesetIt->second.info); - deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius(); - deviceInfo.showSpacing = layoutInfo.showSpacing(); - deviceInfo.spacing = layoutInfo.spacing(); - deviceInfo.zoneCount = layoutInfo.zoneCount(); - } - else if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Canvas) - { - auto layoutInfo = std::get(zonesetIt->second.info); - deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius; - deviceInfo.zoneCount = (int)layoutInfo.zones.size(); + if (layout.value().type == FancyZonesDataTypes::CustomLayoutType::Grid) + { + auto layoutInfo = std::get(layout.value().info); + deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius(); + deviceInfo.showSpacing = layoutInfo.showSpacing(); + deviceInfo.spacing = layoutInfo.spacing(); + deviceInfo.zoneCount = layoutInfo.zoneCount(); + } + else if (layout.value().type == FancyZonesDataTypes::CustomLayoutType::Canvas) + { + auto layoutInfo = std::get(layout.value().info); + deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius; + deviceInfo.zoneCount = (int)layoutInfo.zones.size(); + } } } - + break; } } @@ -644,8 +642,7 @@ void FancyZonesData::LoadFancyZonesData() json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON(); appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON); - deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); - customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); + deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); } } @@ -679,11 +676,11 @@ void FancyZonesData::SaveZoneSettings() const if (dirtyFlag) { - JSONHelpers::SaveZoneSettings(zonesSettingsFileName, updatedDeviceInfoMap, customZoneSetsMap); + JSONHelpers::SaveZoneSettings(zonesSettingsFileName, updatedDeviceInfoMap); } else { - JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap); + JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap); } } diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h index 40ed9be2aa..35859d261f 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h @@ -18,7 +18,7 @@ namespace FancyZonesDataTypes struct ZoneSetData; struct DeviceIdData; struct DeviceInfoData; - struct CustomZoneSetData; + struct CustomLayoutData; struct AppZoneHistoryData; } @@ -32,6 +32,7 @@ namespace FancyZonesUnitTests class WorkAreaCreationUnitTests; class LayoutHotkeysUnitTests; class LayoutTemplatesUnitTests; + class CustomLayoutsUnitTests; } #endif @@ -45,10 +46,8 @@ public: void SetVirtualDesktopCheckCallback(std::function callback); std::optional FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const; - std::optional FindCustomZoneSet(const std::wstring& guid) const; const JSONHelpers::TDeviceInfoMap& GetDeviceInfoMap() const; - const JSONHelpers::TCustomZoneSetsMap& GetCustomZoneSetsMap() const; const std::unordered_map>& GetAppZoneHistoryMap() const; inline const std::wstring& GetZonesSettingsFileName() const @@ -92,17 +91,13 @@ private: friend class FancyZonesUnitTests::ZoneSetCalculateZonesUnitTests; friend class FancyZonesUnitTests::LayoutHotkeysUnitTests; friend class FancyZonesUnitTests::LayoutTemplatesUnitTests; + friend class FancyZonesUnitTests::CustomLayoutsUnitTests; inline void SetDeviceInfo(const FancyZonesDataTypes::DeviceIdData& deviceId, FancyZonesDataTypes::DeviceInfoData data) { deviceInfoMap[deviceId] = data; } - inline void SetCustomZonesets(const std::wstring& uuid, FancyZonesDataTypes::CustomZoneSetData data) - { - customZoneSetsMap[uuid] = data; - } - inline bool ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON) { deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); @@ -113,7 +108,6 @@ private: { appZoneHistoryMap.clear(); deviceInfoMap.clear(); - customZoneSetsMap.clear(); } inline void SetSettingsModulePath(std::wstring_view moduleName) @@ -135,8 +129,6 @@ private: std::unordered_map> appZoneHistoryMap{}; // Maps device unique ID to device data JSONHelpers::TDeviceInfoMap deviceInfoMap{}; - // Maps custom zoneset UUID to it's data - JSONHelpers::TCustomZoneSetsMap customZoneSetsMap{}; std::wstring settingsFileName; std::wstring zonesSettingsFileName; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.cpp new file mode 100644 index 0000000000..bb07b46731 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.cpp @@ -0,0 +1,233 @@ +#include "../pch.h" +#include "CustomLayouts.h" + +#include + +#include // layout defaults +#include +#include +#include + +namespace JsonUtils +{ + std::vector JsonArrayToNumVec(const json::JsonArray& arr) + { + std::vector vec; + for (const auto& val : arr) + { + vec.emplace_back(static_cast(val.GetNumber())); + } + + return vec; + } + + namespace CanvasLayoutInfoJSON + { + std::optional FromJson(const json::JsonObject& infoJson) + { + try + { + FancyZonesDataTypes::CanvasLayoutInfo info; + info.lastWorkAreaWidth = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RefWidthID)); + info.lastWorkAreaHeight = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RefHeightID)); + + json::JsonArray zonesJson = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::ZonesID); + uint32_t size = zonesJson.Size(); + info.zones.reserve(size); + for (uint32_t i = 0; i < size; ++i) + { + json::JsonObject zoneJson = zonesJson.GetObjectAt(i); + const int x = static_cast(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::XID)); + const int y = static_cast(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::YID)); + const int width = static_cast(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::WidthID)); + const int height = static_cast(zoneJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::HeightID)); + FancyZonesDataTypes::CanvasLayoutInfo::Rect zone{ x, y, width, height }; + info.zones.push_back(zone); + } + + info.sensitivityRadius = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius)); + return info; + } + catch (const winrt::hresult_error&) + { + return std::nullopt; + } + } + } + + namespace GridLayoutInfoJSON + { + std::optional FromJson(const json::JsonObject& infoJson) + { + try + { + FancyZonesDataTypes::GridLayoutInfo info(FancyZonesDataTypes::GridLayoutInfo::Minimal{}); + + info.m_rows = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::RowsID)); + info.m_columns = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::ColumnsID)); + + json::JsonArray rowsPercentage = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::RowsPercentageID); + json::JsonArray columnsPercentage = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::ColumnsPercentageID); + json::JsonArray cellChildMap = infoJson.GetNamedArray(NonLocalizable::CustomLayoutsIds::CellChildMapID); + + if (rowsPercentage.Size() != info.m_rows || columnsPercentage.Size() != info.m_columns || cellChildMap.Size() != info.m_rows) + { + return std::nullopt; + } + + info.m_rowsPercents = JsonArrayToNumVec(rowsPercentage); + info.m_columnsPercents = JsonArrayToNumVec(columnsPercentage); + for (const auto& cellsRow : cellChildMap) + { + const auto cellsArray = cellsRow.GetArray(); + if (cellsArray.Size() != info.m_columns) + { + return std::nullopt; + } + info.cellChildMap().push_back(JsonArrayToNumVec(cellsArray)); + } + + info.m_showSpacing = infoJson.GetNamedBoolean(NonLocalizable::CustomLayoutsIds::ShowSpacingID, DefaultValues::ShowSpacing); + info.m_spacing = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SpacingID, DefaultValues::Spacing)); + info.m_sensitivityRadius = static_cast(infoJson.GetNamedNumber(NonLocalizable::CustomLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius)); + + return info; + } + catch (const winrt::hresult_error&) + { + return std::nullopt; + } + } + } + + struct CustomLayoutJSON + { + GUID layoutId; + FancyZonesDataTypes::CustomLayoutData data; + + static std::optional FromJson(const json::JsonObject& json) + { + try + { + CustomLayoutJSON result; + + auto idStr = json.GetNamedString(NonLocalizable::CustomLayoutsIds::UuidID); + auto id = FancyZonesUtils::GuidFromString(idStr.c_str()); + if (!id) + { + return std::nullopt; + } + + result.layoutId = id.value(); + result.data.name = json.GetNamedString(NonLocalizable::CustomLayoutsIds::NameID); + + json::JsonObject infoJson = json.GetNamedObject(NonLocalizable::CustomLayoutsIds::InfoID); + std::wstring zoneSetType = std::wstring{ json.GetNamedString(NonLocalizable::CustomLayoutsIds::TypeID) }; + if (zoneSetType.compare(NonLocalizable::CustomLayoutsIds::CanvasID) == 0) + { + if (auto info = CanvasLayoutInfoJSON::FromJson(infoJson); info.has_value()) + { + result.data.type = FancyZonesDataTypes::CustomLayoutType::Canvas; + result.data.info = std::move(info.value()); + } + else + { + return std::nullopt; + } + } + else if (zoneSetType.compare(NonLocalizable::CustomLayoutsIds::GridID) == 0) + { + if (auto info = GridLayoutInfoJSON::FromJson(infoJson); info.has_value()) + { + result.data.type = FancyZonesDataTypes::CustomLayoutType::Grid; + result.data.info = std::move(info.value()); + } + else + { + return std::nullopt; + } + } + else + { + return std::nullopt; + } + + return result; + } + catch (const winrt::hresult_error&) + { + return std::nullopt; + } + } + }; + + CustomLayouts::TCustomLayoutMap ParseJson(const json::JsonObject& json) + { + CustomLayouts::TCustomLayoutMap map{}; + auto layouts = json.GetNamedArray(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID); + + for (uint32_t i = 0; i < layouts.Size(); ++i) + { + if (auto obj = CustomLayoutJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value()) + { + map[obj->layoutId] = std::move(obj->data); + } + } + + return std::move(map); + } +} + + +CustomLayouts::CustomLayouts() +{ + const std::wstring& dataFileName = CustomLayoutsFileName(); + m_fileWatcher = std::make_unique(dataFileName, [&]() { + PostMessageW(HWND_BROADCAST, WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE, NULL, NULL); + }); +} + + +CustomLayouts& CustomLayouts::instance() +{ + static CustomLayouts self; + return self; +} + +void CustomLayouts::LoadData() +{ + auto data = json::from_file(CustomLayoutsFileName()); + + try + { + if (data) + { + m_layouts = JsonUtils::ParseJson(data.value()); + } + else + { + m_layouts.clear(); + Logger::info(L"custom-layouts.json file is missing or malformed"); + } + } + catch (const winrt::hresult_error& e) + { + Logger::error(L"Parsing custom-layouts error: {}", e.message()); + } +} + +std::optional CustomLayouts::GetLayout(const GUID& id) const noexcept +{ + auto iter = m_layouts.find(id); + if (iter != m_layouts.end()) + { + return iter->second; + } + + return std::nullopt; +} + +const CustomLayouts::TCustomLayoutMap& CustomLayouts::GetAllLayouts() const noexcept +{ + return m_layouts; +} diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.h new file mode 100644 index 0000000000..a455a75f0c --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/CustomLayouts.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace NonLocalizable +{ + namespace CustomLayoutsIds + { + const static wchar_t* CustomLayoutsArrayID = L"custom-layouts"; + const static wchar_t* UuidID = L"uuid"; + const static wchar_t* NameID = L"name"; + const static wchar_t* InfoID = L"info"; + const static wchar_t* TypeID = L"type"; + const static wchar_t* CanvasID = L"canvas"; + const static wchar_t* GridID = L"grid"; + const static wchar_t* SensitivityRadiusID = L"sensitivity-radius"; + + // canvas + const static wchar_t* RefHeightID = L"ref-height"; + const static wchar_t* RefWidthID = L"ref-width"; + const static wchar_t* ZonesID = L"zones"; + const static wchar_t* XID = L"X"; + const static wchar_t* YID = L"Y"; + const static wchar_t* WidthID = L"width"; + const static wchar_t* HeightID = L"height"; + + // grid + const static wchar_t* RowsID = L"rows"; + const static wchar_t* ColumnsID = L"columns"; + const static wchar_t* RowsPercentageID = L"rows-percentage"; + const static wchar_t* ColumnsPercentageID = L"columns-percentage"; + const static wchar_t* CellChildMapID = L"cell-child-map"; + const static wchar_t* ShowSpacingID = L"show-spacing"; + const static wchar_t* SpacingID = L"spacing"; + } +} + +class CustomLayouts +{ +public: + using TCustomLayoutMap = std::unordered_map; + + static CustomLayouts& instance(); + + inline static std::wstring CustomLayoutsFileName() + { + std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey); +#if defined(UNIT_TESTS) + return saveFolderPath + L"\\test-custom-layouts.json"; +#endif + return saveFolderPath + L"\\custom-layouts.json"; + } + + void LoadData(); + + std::optional GetLayout(const GUID& id) const noexcept; + const TCustomLayoutMap& GetAllLayouts() const noexcept; + +private: + CustomLayouts(); + ~CustomLayouts() = default; + + TCustomLayoutMap m_layouts; + std::unique_ptr m_fileWatcher; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h index a0d4eeeef1..da34225cf5 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h @@ -100,7 +100,7 @@ namespace FancyZonesDataTypes int m_sensitivityRadius; }; - struct CustomZoneSetData + struct CustomLayoutData { std::wstring name; CustomLayoutType type; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index e1d30f2a69..e23a8a9b94 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -37,6 +37,7 @@ + @@ -67,6 +68,10 @@ + + ../pch.h + ../pch.h + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index ffc0b99a1d..7194abff55 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -90,6 +90,9 @@ Header Files + + Header Files + Header Files @@ -158,6 +161,9 @@ Source Files + + Source Files + Source Files diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp index 94812d2fdb..c5e7a44625 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp @@ -13,6 +13,7 @@ UINT WM_PRIV_VD_UPDATE; UINT WM_PRIV_EDITOR; UINT WM_PRIV_FILE_UPDATE; UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE; +UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE; UINT WM_PRIV_SNAP_HOTKEY; UINT WM_PRIV_QUICK_LAYOUT_KEY; UINT WM_PRIV_SETTINGS_CHANGED; @@ -33,6 +34,7 @@ void InitializeWinhookEventIds() WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}"); WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}"); WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE = RegisterWindowMessage(L"{07229b7e-4f22-4357-b136-33c289be2295}"); + WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE = RegisterWindowMessage(L"{0972787e-cdab-4e16-b228-91acdc38f40f}"); WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}"); WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}"); WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{89ca3Daa-bf2d-4e73-9f3f-c60716364e27}"); diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h index 7bd6a02402..a78557cde2 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h @@ -11,6 +11,7 @@ extern UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation extern UINT WM_PRIV_EDITOR; // Scheduled when the editor exits extern UINT WM_PRIV_FILE_UPDATE; // Scheduled when the watched zone-settings file is updated extern UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE; // Scheduled when the watched layout-hotkeys.json file is updated +extern UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE; // Scheduled when the watched custom-layouts.json file is updated extern UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press extern UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when the a watched settings file is updated diff --git a/src/modules/fancyzones/FancyZonesLib/JsonHelpers.cpp b/src/modules/fancyzones/FancyZonesLib/JsonHelpers.cpp index 6f2f0d47ca..125bf325e9 100644 --- a/src/modules/fancyzones/FancyZonesLib/JsonHelpers.cpp +++ b/src/modules/fancyzones/FancyZonesLib/JsonHelpers.cpp @@ -6,6 +6,7 @@ #include "trace.h" #include "util.h" +#include #include #include @@ -579,14 +580,13 @@ namespace JSONHelpers } } - void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap) + void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap) { auto before = json::from_file(zonesSettingsFileName); json::JsonObject root{}; root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap)); - root.SetNamedValue(NonLocalizable::CustomZoneSetsStr, JSONHelpers::SerializeCustomZoneSets(customZoneSetsMap)); if (!before.has_value() || before.value().Stringify() != root.Stringify()) { @@ -679,29 +679,6 @@ namespace JSONHelpers return DeviceInfosJSON; } - TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON) - { - try - { - TCustomZoneSetsMap customZoneSetsMap{}; - auto customZoneSets = fancyZonesDataJSON.GetNamedArray(NonLocalizable::CustomZoneSetsStr); - - for (uint32_t i = 0; i < customZoneSets.Size(); ++i) - { - if (auto zoneSet = CustomZoneSetJSON::FromJson(customZoneSets.GetObjectAt(i)); zoneSet.has_value()) - { - customZoneSetsMap[zoneSet->uuid] = std::move(zoneSet->data); - } - } - - return std::move(customZoneSetsMap); - } - catch (const winrt::hresult_error&) - { - return {}; - } - } - json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap) { json::JsonArray customZoneSetsJSON{}; @@ -777,4 +754,43 @@ namespace JSONHelpers root.SetNamedValue(NonLocalizable::LayoutTemplatesIds::LayoutTemplatesArrayID, templates); json::to_file(LayoutTemplates::LayoutTemplatesFileName(), root); } + + std::optional ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON) + { + try + { + TCustomZoneSetsMap customZoneSetsMap{}; + auto customZoneSets = fancyZonesDataJSON.GetNamedArray(NonLocalizable::CustomZoneSetsStr); + + for (uint32_t i = 0; i < customZoneSets.Size(); ++i) + { + if (auto zoneSet = CustomZoneSetJSON::FromJson(customZoneSets.GetObjectAt(i)); zoneSet.has_value()) + { + customZoneSetsMap[zoneSet->uuid] = std::move(zoneSet->data); + } + } + + return std::move(customZoneSetsMap); + } + catch (const winrt::hresult_error& e) + { + Logger::error(L"Parsing custom layouts error: {}", e.message()); + return std::nullopt; + } + } + + void SaveCustomLayouts(const TCustomZoneSetsMap& map) + { + json::JsonObject root{}; + json::JsonArray layoutsArray{}; + + for (const auto& [uuid, data] : map) + { + json::JsonObject layoutJson{}; + layoutsArray.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ uuid, data })); + } + + root.SetNamedValue(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID, layoutsArray); + json::to_file(CustomLayouts::CustomLayoutsFileName(), root); + } } \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/JsonHelpers.h b/src/modules/fancyzones/FancyZonesLib/JsonHelpers.h index 604f848dc2..5cf0e5439b 100644 --- a/src/modules/fancyzones/FancyZonesLib/JsonHelpers.h +++ b/src/modules/fancyzones/FancyZonesLib/JsonHelpers.h @@ -25,7 +25,7 @@ namespace JSONHelpers struct CustomZoneSetJSON { std::wstring uuid; - FancyZonesDataTypes::CustomZoneSetData data; + FancyZonesDataTypes::CustomLayoutData data; static json::JsonObject ToJson(const CustomZoneSetJSON& device); static std::optional FromJson(const json::JsonObject& customZoneSet); @@ -66,7 +66,7 @@ namespace JSONHelpers using TAppZoneHistoryMap = std::unordered_map>; using TDeviceInfoMap = std::unordered_map; - using TCustomZoneSetsMap = std::unordered_map; + using TCustomZoneSetsMap = std::unordered_map; using TLayoutQuickKeysMap = std::unordered_map; struct MonitorInfo @@ -93,7 +93,7 @@ namespace JSONHelpers json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName); - void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap); + void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap); void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap); TAppZoneHistoryMap ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON); @@ -102,9 +102,6 @@ namespace JSONHelpers TDeviceInfoMap ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON); json::JsonArray SerializeDeviceInfos(const TDeviceInfoMap& deviceInfoMap); - TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON); - json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap); - // replace zones-settings: layout hotkeys std::optional ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON); void SaveLayoutHotkeys(const TLayoutQuickKeysMap& quickKeysMap); @@ -112,4 +109,8 @@ namespace JSONHelpers // replace zones-settings: layout templates std::optional ParseLayoutTemplates(const json::JsonObject& fancyZonesDataJSON); void SaveLayoutTemplates(const json::JsonArray& templates); + + // replace zones-settings: custom layouts + std::optional ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON); + void SaveCustomLayouts(const TCustomZoneSetsMap& map); } diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp index 1d8c936421..a4c19e7a32 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp +++ b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp @@ -3,6 +3,7 @@ #include "ZoneSet.h" #include "FancyZonesData.h" +#include #include "FancyZonesDataTypes.h" #include "FancyZonesWindowProperties.h" #include "Settings.h" @@ -880,52 +881,45 @@ bool ZoneSet::CalculateUniquePriorityGridLayout(Rect workArea, int zoneCount, in bool ZoneSet::CalculateCustomLayout(Rect workArea, int spacing) noexcept { - wil::unique_cotaskmem_string guidStr; - if (SUCCEEDED(StringFromCLSID(m_config.Id, &guidStr))) + const auto zoneSetSearchResult = CustomLayouts::instance().GetLayout(m_config.Id); + if (!zoneSetSearchResult.has_value()) { - const std::wstring guid = guidStr.get(); + return false; + } - const auto zoneSetSearchResult = FancyZonesDataInstance().FindCustomZoneSet(guid); - - if (!zoneSetSearchResult.has_value()) + const auto& zoneSet = *zoneSetSearchResult; + if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Canvas && std::holds_alternative(zoneSet.info)) + { + const auto& zoneSetInfo = std::get(zoneSet.info); + for (const auto& zone : zoneSetInfo.zones) { - return false; - } + int x = zone.x; + int y = zone.y; + int width = zone.width; + int height = zone.height; - const auto& zoneSet = *zoneSetSearchResult; - if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Canvas && std::holds_alternative(zoneSet.info)) - { - const auto& zoneSetInfo = std::get(zoneSet.info); - for (const auto& zone : zoneSetInfo.zones) + DPIAware::Convert(m_config.Monitor, x, y); + DPIAware::Convert(m_config.Monitor, width, height); + + auto zone = MakeZone(RECT{ x, y, x + width, y + height }, m_zones.size()); + if (zone) { - int x = zone.x; - int y = zone.y; - int width = zone.width; - int height = zone.height; - - DPIAware::Convert(m_config.Monitor, x, y); - DPIAware::Convert(m_config.Monitor, width, height); - - auto zone = MakeZone(RECT{ x, y, x + width, y + height }, m_zones.size()); - if (zone) - { - AddZone(zone); - } - else - { - // All zones within zone set should be valid in order to use its functionality. - m_zones.clear(); - return false; - } + AddZone(zone); } + else + { + // All zones within zone set should be valid in order to use its functionality. + m_zones.clear(); + return false; + } + } - return true; - } - else if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Grid && std::holds_alternative(zoneSet.info)) - { - const auto& info = std::get(zoneSet.info); - return CalculateGridZones(workArea, info, spacing); - } + return true; + } + else if (zoneSet.type == FancyZonesDataTypes::CustomLayoutType::Grid && std::holds_alternative(zoneSet.info)) + { + const auto& info = std::get(zoneSet.info); + return CalculateGridZones(workArea, info, spacing); } return false; diff --git a/src/modules/fancyzones/FancyZonesLib/trace.cpp b/src/modules/fancyzones/FancyZonesLib/trace.cpp index bb5d759dc2..38fc2c80a1 100644 --- a/src/modules/fancyzones/FancyZonesLib/trace.cpp +++ b/src/modules/fancyzones/FancyZonesLib/trace.cpp @@ -3,8 +3,10 @@ #include "FancyZonesLib/ZoneSet.h" #include "FancyZonesLib/Settings.h" #include "FancyZonesLib/FancyZonesData.h" +#include "FancyZonesLib/FancyZonesData/CustomLayouts.h" #include "FancyZonesLib/FancyZonesData/LayoutHotkeys.h" #include "FancyZonesLib/FancyZonesDataTypes.h" +#include "FancyZonesLib/util.h" // Telemetry strings should not be localized. #define LoggingProviderKey "Microsoft.PowerToys" @@ -144,7 +146,7 @@ void Trace::FancyZones::DataChanged() noexcept { const FancyZonesData& data = FancyZonesDataInstance(); int appsHistorySize = static_cast(data.GetAppZoneHistoryMap().size()); - const auto& customZones = data.GetCustomZoneSetsMap(); + const auto& customZones = CustomLayouts::instance().GetAllLayouts(); const auto& devices = data.GetDeviceInfoMap(); auto quickKeysCount = LayoutHotkeys::instance().GetHotkeysCount(); @@ -190,11 +192,15 @@ void Trace::FancyZones::DataChanged() noexcept int zoneCount = -1; if (type == FancyZonesDataTypes::ZoneSetLayoutType::Custom) { - const auto& activeCustomZone = customZones.find(device.activeZoneSet.uuid); - if (activeCustomZone != customZones.end()) + auto guid = FancyZonesUtils::GuidFromString(device.activeZoneSet.uuid); + if (guid) { - zoneCount = getCustomZoneCount(activeCustomZone->second.info); - } + const auto& activeCustomZone = customZones.find(guid.value()); + if (activeCustomZone != customZones.end()) + { + zoneCount = getCustomZoneCount(activeCustomZone->second.info); + } + } } else { diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/CustomLayoutsTests.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/CustomLayoutsTests.Spec.cpp new file mode 100644 index 0000000000..aa15679ad9 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/CustomLayoutsTests.Spec.cpp @@ -0,0 +1,194 @@ +#include "pch.h" +#include + +#include +#include +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace FancyZonesUnitTests +{ + TEST_CLASS (CustomLayoutsUnitTests) + { + FancyZonesData& m_fzData = FancyZonesDataInstance(); + std::wstring m_testFolder = L"FancyZonesUnitTests"; + + json::JsonObject CanvasLayoutJson() + { + json::JsonObject canvasLayoutJson{}; + canvasLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::UuidID, json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}")); + canvasLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::NameID, json::value(L"Custom canvas layout")); + canvasLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::TypeID, json::value(NonLocalizable::CustomLayoutsIds::CanvasID)); + + json::JsonObject info{}; + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::RefWidthID, json::value(1920)); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::RefHeightID, json::value(1080)); + + json::JsonArray zonesArray{}; + { + json::JsonObject zone{}; + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::XID, json::value(0)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::YID, json::value(0)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::WidthID, json::value(1140)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::HeightID, json::value(1040)); + zonesArray.Append(zone); + } + { + json::JsonObject zone{}; + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::XID, json::value(1140)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::YID, json::value(649)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::WidthID, json::value(780)); + zone.SetNamedValue(NonLocalizable::CustomLayoutsIds::HeightID, json::value(391)); + zonesArray.Append(zone); + } + + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::ZonesID, zonesArray); + canvasLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::InfoID, info); + return canvasLayoutJson; + } + + json::JsonObject GridLayoutJson() + { + json::JsonObject gridLayoutJson{}; + gridLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::UuidID, json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17D}")); + gridLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::NameID, json::value(L"Custom grid layout")); + gridLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::TypeID, json::value(NonLocalizable::CustomLayoutsIds::GridID)); + + json::JsonArray rowsPercentage{}; + rowsPercentage.Append(json::value(5000)); + rowsPercentage.Append(json::value(5000)); + + json::JsonArray columnsPercentage{}; + columnsPercentage.Append(json::value(3333)); + columnsPercentage.Append(json::value(5000)); + columnsPercentage.Append(json::value(1667)); + + json::JsonArray cells{}; + { + json::JsonArray cellsRow{}; + cellsRow.Append(json::value(0)); + cellsRow.Append(json::value(1)); + cellsRow.Append(json::value(2)); + cells.Append(cellsRow); + } + { + json::JsonArray cellsRow{}; + cellsRow.Append(json::value(3)); + cellsRow.Append(json::value(1)); + cellsRow.Append(json::value(4)); + cells.Append(cellsRow); + } + + json::JsonObject info{}; + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::RowsID, json::value(2)); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::ColumnsID, json::value(3)); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::RowsPercentageID, rowsPercentage); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::ColumnsPercentageID, columnsPercentage); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::CellChildMapID, cells); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::SensitivityRadiusID, json::value(20)); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::ShowSpacingID, json::value(false)); + info.SetNamedValue(NonLocalizable::CustomLayoutsIds::SpacingID, json::value(16)); + + gridLayoutJson.SetNamedValue(NonLocalizable::CustomLayoutsIds::InfoID, info); + return gridLayoutJson; + } + + TEST_METHOD_INITIALIZE(Init) + { + m_fzData.clear_data(); + m_fzData.SetSettingsModulePath(L"FancyZonesUnitTests"); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + std::filesystem::remove_all(CustomLayouts::CustomLayoutsFileName()); + std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_testFolder)); + } + + TEST_METHOD (CustomLayoutsParse) + { + // prepare + json::JsonObject root{}; + json::JsonArray layoutsArray{}; + + layoutsArray.Append(CanvasLayoutJson()); + layoutsArray.Append(GridLayoutJson()); + + root.SetNamedValue(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID, layoutsArray); + json::to_file(CustomLayouts::CustomLayoutsFileName(), root); + + // test + CustomLayouts::instance().LoadData(); + Assert::AreEqual((size_t)2, CustomLayouts::instance().GetAllLayouts().size()); + Assert::IsTrue(CustomLayouts::instance().GetLayout(FancyZonesUtils::GuidFromString(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}").value()).has_value()); + Assert::IsTrue(CustomLayouts::instance().GetLayout(FancyZonesUtils::GuidFromString(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17D}").value()).has_value()); + } + + TEST_METHOD (CustomLayoutsParseEmpty) + { + // prepare + json::JsonObject root{}; + json::JsonArray layoutsArray{}; + root.SetNamedValue(NonLocalizable::CustomLayoutsIds::CustomLayoutsArrayID, layoutsArray); + json::to_file(CustomLayouts::CustomLayoutsFileName(), root); + + // test + CustomLayouts::instance().LoadData(); + Assert::IsTrue(CustomLayouts::instance().GetAllLayouts().empty()); + } + + TEST_METHOD (CustomsLayoutsNoFile) + { + // test + CustomLayouts::instance().LoadData(); + Assert::IsTrue(CustomLayouts::instance().GetAllLayouts().empty()); + } + + TEST_METHOD (MoveCustomLayoutsFromZonesSettings) + { + // prepare + json::JsonObject root{}; + json::JsonArray devicesArray{}, customLayoutsArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; + customLayoutsArray.Append(GridLayoutJson()); + customLayoutsArray.Append(CanvasLayoutJson()); + + root.SetNamedValue(L"devices", devicesArray); + root.SetNamedValue(L"custom-zone-sets", customLayoutsArray); + root.SetNamedValue(L"templates", templateLayoutsArray); + root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); + json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); + + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + CustomLayouts::instance().LoadData(); + Assert::AreEqual((size_t)2, CustomLayouts::instance().GetAllLayouts().size()); + Assert::IsTrue(CustomLayouts::instance().GetLayout(FancyZonesUtils::GuidFromString(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}").value()).has_value()); + Assert::IsTrue(CustomLayouts::instance().GetLayout(FancyZonesUtils::GuidFromString(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17D}").value()).has_value()); + } + + TEST_METHOD (MoveCustomLayoutsFromZonesSettingsNoCustomLayoutsData) + { + // prepare + json::JsonObject root{}; + json::JsonArray devicesArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; + root.SetNamedValue(L"devices", devicesArray); + root.SetNamedValue(L"templates", templateLayoutsArray); + root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); + json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); + + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + CustomLayouts::instance().LoadData(); + Assert::IsTrue(CustomLayouts::instance().GetAllLayouts().empty()); + } + + TEST_METHOD (MoveCustomLayoutsFromZonesSettingsNoFile) + { + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + CustomLayouts::instance().LoadData(); + Assert::IsTrue(CustomLayouts::instance().GetAllLayouts().empty()); + } + }; +} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp index 5b1608dea3..0b6af79b12 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp @@ -562,7 +562,7 @@ namespace FancyZonesUnitTests { TEST_METHOD (ToJsonGrid) { - CustomZoneSetJSON zoneSet{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Grid, GridLayoutInfo(GridLayoutInfo::Minimal{}) } }; + CustomZoneSetJSON zoneSet{ L"uuid", CustomLayoutData{ L"name", CustomLayoutType::Grid, GridLayoutInfo(GridLayoutInfo::Minimal{}) } }; json::JsonObject expected = json::JsonObject::Parse(L"{\"uuid\": \"uuid\", \"name\": \"name\", \"type\": \"grid\"}"); expected.SetNamedValue(L"info", GridLayoutInfoJSON::ToJson(std::get(zoneSet.data.info))); @@ -574,7 +574,7 @@ namespace FancyZonesUnitTests TEST_METHOD (ToJsonCanvas) { - CustomZoneSetJSON zoneSet{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{} } }; + CustomZoneSetJSON zoneSet{ L"uuid", CustomLayoutData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{} } }; json::JsonObject expected = json::JsonObject::Parse(L"{\"uuid\": \"uuid\", \"name\": \"name\", \"type\": \"canvas\"}"); expected.SetNamedValue(L"info", CanvasLayoutInfoJSON::ToJson(std::get(zoneSet.data.info))); @@ -587,7 +587,7 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonGrid) { const auto grid = GridLayoutInfo(GridLayoutInfo::Full{ 1, 3, { 10000 }, { 2500, 5000, 2500 }, { { 0, 1, 2 } } }); - CustomZoneSetJSON expected{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + CustomZoneSetJSON expected{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomLayoutData{ L"name", CustomLayoutType::Grid, grid } }; json::JsonObject json = json::JsonObject::Parse(L"{\"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"name\": \"name\", \"type\": \"grid\"}"); json.SetNamedValue(L"info", GridLayoutInfoJSON::ToJson(std::get(expected.data.info))); @@ -607,7 +607,7 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonCanvas) { - CustomZoneSetJSON expected{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; + CustomZoneSetJSON expected{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomLayoutData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; json::JsonObject json = json::JsonObject::Parse(L"{\"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"name\": \"name\", \"type\": \"canvas\"}"); json.SetNamedValue(L"info", CanvasLayoutInfoJSON::ToJson(std::get(expected.data.info))); @@ -628,7 +628,7 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonGridInvalidUuid) { const auto grid = GridLayoutInfo(GridLayoutInfo::Full{ 1, 3, { 10000 }, { 2500, 5000, 2500 }, { { 0, 1, 2 } } }); - CustomZoneSetJSON expected{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + CustomZoneSetJSON expected{ L"uuid", CustomLayoutData{ L"name", CustomLayoutType::Grid, grid } }; json::JsonObject json = json::JsonObject::Parse(L"{\"uuid\": \"uuid\", \"name\": \"name\", \"type\": \"grid\"}"); json.SetNamedValue(L"info", GridLayoutInfoJSON::ToJson(std::get(expected.data.info))); @@ -639,7 +639,7 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonCanvasInvalidUuid) { - CustomZoneSetJSON expected{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; + CustomZoneSetJSON expected{ L"uuid", CustomLayoutData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; json::JsonObject json = json::JsonObject::Parse(L"{\"uuid\": \"uuid\", \"name\": \"name\", \"type\": \"canvas\"}"); json.SetNamedValue(L"info", CanvasLayoutInfoJSON::ToJson(std::get(expected.data.info))); @@ -650,7 +650,7 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonMissingKeys) { - CustomZoneSetJSON zoneSet{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; + CustomZoneSetJSON zoneSet{ L"uuid", CustomLayoutData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 2, 1 } } }; const auto json = CustomZoneSetJSON::ToJson(zoneSet); auto iter = json.First(); @@ -1371,158 +1371,6 @@ namespace FancyZonesUnitTests auto res = CustomAssert::CompareJsonArrays(expected, actual); Assert::IsTrue(res.first, res.second.c_str()); } - - TEST_METHOD (CustomZoneSetsParseSingle) - { - const std::wstring zoneUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}"; - GridLayoutInfo grid(GridLayoutInfo(FancyZonesDataTypes::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - - json::JsonObject json; - CustomZoneSetJSON expected{ zoneUuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; - json::JsonArray array; - array.Append(CustomZoneSetJSON::ToJson(expected)); - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(array.Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - Assert::AreEqual((size_t)array.Size(), customZoneSetsMap.size()); - - auto entry = customZoneSetsMap.find(zoneUuid)->second; - Assert::AreEqual(expected.data.name.c_str(), entry.name.c_str()); - Assert::AreEqual((int)expected.data.type, (int)entry.type); - - auto expectedGrid = std::get(expected.data.info); - auto actualGrid = std::get(entry.info); - Assert::AreEqual(expectedGrid.rows(), actualGrid.rows()); - Assert::AreEqual(expectedGrid.columns(), actualGrid.columns()); - } - - TEST_METHOD (CustomZoneSetsParseMany) - { - json::JsonObject json; - json::JsonArray array; - const GridLayoutInfo grid(GridLayoutInfo(FancyZonesDataTypes::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - array.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502900}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } })); - array.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502901}", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 1, 2 } } })); - array.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502902}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } })); - array.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502903}", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 1, 2 } } })); - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(array.Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - Assert::AreEqual((size_t)array.Size(), customZoneSetsMap.size()); - - auto iter = array.First(); - while (iter.HasCurrent()) - { - auto expected = CustomZoneSetJSON::FromJson(json::JsonObject::Parse(iter.Current().Stringify())); - auto entry = customZoneSetsMap.find(expected->uuid)->second; - Assert::AreEqual(expected->data.name.c_str(), entry.name.c_str(), L"name"); - Assert::AreEqual((int)expected->data.type, (int)entry.type, L"type"); - - if (expected->data.type == CustomLayoutType::Grid) - { - auto expectedInfo = std::get(expected->data.info); - auto actualInfo = std::get(entry.info); - Assert::AreEqual(expectedInfo.rows(), actualInfo.rows(), L"grid rows"); - Assert::AreEqual(expectedInfo.columns(), actualInfo.columns(), L"grid columns"); - } - else - { - auto expectedInfo = std::get(expected->data.info); - auto actualInfo = std::get(entry.info); - Assert::AreEqual(expectedInfo.lastWorkAreaWidth, actualInfo.lastWorkAreaWidth, L"canvas width"); - Assert::AreEqual(expectedInfo.lastWorkAreaHeight, actualInfo.lastWorkAreaHeight, L"canvas height"); - } - - iter.MoveNext(); - } - } - - TEST_METHOD (CustomZoneSetsParseEmpty) - { - const auto& customZoneSetsMap = ParseCustomZoneSets(json::JsonObject()); - - Assert::IsTrue(customZoneSetsMap.empty()); - } - - TEST_METHOD (CustomZoneSetsParseInvalid) - { - json::JsonObject json; - CustomZoneSetJSON expected{ L"uuid", CustomZoneSetData{ L"name", CustomLayoutType::Grid, GridLayoutInfo(GridLayoutInfo::Minimal{ 1, 2 }) } }; - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(CustomZoneSetJSON::ToJson(expected).Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - Assert::IsTrue(customZoneSetsMap.empty()); - } - - TEST_METHOD (CustomZoneSetsSerializeSingle) - { - json::JsonArray expected; - const GridLayoutInfo grid(GridLayoutInfo(FancyZonesDataTypes::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - expected.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } })); - json::JsonObject json; - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(expected.Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - auto actual = SerializeCustomZoneSets(customZoneSetsMap); - auto res = CustomAssert::CompareJsonArrays(expected, actual); - Assert::IsTrue(res.first, res.second.c_str()); - } - - TEST_METHOD (CustomZoneSetsSerializeMany) - { - json::JsonObject json; - json::JsonArray expected; - const GridLayoutInfo grid(GridLayoutInfo(FancyZonesDataTypes::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - - expected.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502900}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } })); - expected.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502901}", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 1, 2 } } })); - expected.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502902}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } })); - expected.Append(CustomZoneSetJSON::ToJson(CustomZoneSetJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502903}", CustomZoneSetData{ L"name", CustomLayoutType::Canvas, CanvasLayoutInfo{ 1, 2 } } })); - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(expected.Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - auto actual = SerializeCustomZoneSets(customZoneSetsMap); - auto res = CustomAssert::CompareJsonArrays(expected, actual); - Assert::IsTrue(res.first, res.second.c_str()); - } - - TEST_METHOD (CustomZoneSetsSerializeEmpty) - { - json::JsonArray expected; - json::JsonObject json; - json.SetNamedValue(L"custom-zone-sets", json::JsonValue::Parse(expected.Stringify())); - - const auto& customZoneSetsMap = ParseCustomZoneSets(json); - - auto actual = SerializeCustomZoneSets(customZoneSetsMap); - auto res = CustomAssert::CompareJsonArrays(expected, actual); - Assert::IsTrue(res.first, res.second.c_str()); - } TEST_METHOD (SetActiveZoneSet) { @@ -1620,13 +1468,13 @@ namespace FancyZonesUnitTests .rowsPercents = { 10000 }, .columnsPercents = { 2500, 5000, 2500 }, .cellChildMap = { { 0, 1, 2 } } })); - CustomZoneSetJSON zoneSets{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + CustomZoneSetJSON zoneSets{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomLayoutData{ L"name", CustomLayoutType::Grid, grid } }; AppZoneHistoryData data{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"device-id", .zoneIndexSet = { 54321 } }; AppZoneHistoryJSON appZoneHistory{ L"app-path", std::vector{ data } }; - DeviceInfoJSON deviceInfo { FancyZonesDataTypes::DeviceIdData{ L"device-id", 0, 0, m_defaultVDId }, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; + DeviceInfoJSON deviceInfo { FancyZonesDataTypes::DeviceIdData{ L"device-id", 0, 0, m_defaultVDId }, DeviceInfoData{ ZoneSetData{ L"{33A2B101-16E1-437B-A61E-CDBECF502906}", ZoneSetLayoutType::Custom }, true, 16, 3 } }; LayoutQuickKeyJSON quickKeys{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", 1 }; json::JsonArray zoneSetsArray, appZonesArray, deviceInfoArray, quickKeysArray; zoneSetsArray.Append(CustomZoneSetJSON::ToJson(zoneSets)); @@ -1651,9 +1499,8 @@ namespace FancyZonesUnitTests std::filesystem::remove(jsonPath); } - Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); - Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); - Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); + Assert::IsFalse(fancyZonesData.GetAppZoneHistoryMap().empty()); + Assert::IsFalse(fancyZonesData.GetDeviceInfoMap().empty()); } TEST_METHOD (LoadFancyZonesDataFromCroppedJson) @@ -1666,7 +1513,6 @@ namespace FancyZonesUnitTests data.LoadFancyZonesData(); - Assert::IsTrue(data.GetCustomZoneSetsMap().empty()); Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsTrue(data.GetDeviceInfoMap().empty()); } @@ -1680,7 +1526,6 @@ namespace FancyZonesUnitTests std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"app-zone-history\": [], \"devices\": [{\"device-id\": \"кириллица\"}], \"custom-zone-sets\": []}"; data.LoadFancyZonesData(); - Assert::IsTrue(data.GetCustomZoneSetsMap().empty()); Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsTrue(data.GetDeviceInfoMap().empty()); } @@ -1694,7 +1539,6 @@ namespace FancyZonesUnitTests std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"app-zone-history\": null, \"devices\": [{\"device-id\":\"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\",\"active-zoneset\":{\"uuid\":\"{568EBC3A-C09C-483E-A64D-6F1F2AF4E48D}\",\"type\":\"columns\"},\"editor-show-spacing\":true,\"editor-spacing\":16,\"editor-zone-count\":3}], \"custom-zone-sets\": []}"; data.LoadFancyZonesData(); - Assert::IsTrue(data.GetCustomZoneSetsMap().empty()); Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsFalse(data.GetDeviceInfoMap().empty()); } diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj index ab799fd0e9..51f145c3a2 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj @@ -41,6 +41,7 @@ + diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters index 7d7690bbec..e2bdcd4df9 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp index 96f560b4dc..391c6f43c5 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp @@ -1000,7 +1000,7 @@ namespace FancyZonesUnitTests { const std::wstring uuid = L"uuid"; const CanvasLayoutInfo info{ -1, 100, { CanvasLayoutInfo::Rect{ -10, -10, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; - JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Canvas, info } }; + JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomLayoutData{ L"name", CustomLayoutType::Canvas, info } }; json::to_file(m_path, JSONHelpers::CustomZoneSetJSON::ToJson(expected)); Assert::IsTrue(std::filesystem::exists(m_path)); @@ -1026,7 +1026,7 @@ namespace FancyZonesUnitTests .rowsPercents = { -100 }, //rows percents are negative .columnsPercents = { 2500, 2500 }, //column percents count is invalid .cellChildMap = { { 0, 1, 2 } } })); - JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomLayoutData{ L"name", CustomLayoutType::Grid, grid } }; json::to_file(m_path, JSONHelpers::CustomZoneSetJSON::ToJson(expected)); Assert::IsTrue(std::filesystem::exists(m_path)); @@ -1043,69 +1043,13 @@ namespace FancyZonesUnitTests } } - TEST_METHOD (CustomZoneFromValidCanvasLayoutInfo) - { - //prepare device data - FancyZonesDataInstance().SetDeviceInfo(FancyZonesDataTypes::DeviceIdData{ L"default_device_id" }, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 }); - - //prepare expected data - wil::unique_cotaskmem_string uuid; - Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); - const CanvasLayoutInfo info{ 123, 321, { CanvasLayoutInfo::Rect{ 0, 0, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; - CustomZoneSetData zoneSetData{ L"name", CustomLayoutType::Canvas, info }; - FancyZonesDataInstance().SetCustomZonesets(uuid.get(), zoneSetData); - - //test - const int spacing = 10; - const int zoneCount = static_cast(info.zones.size()); - ZoneSetConfig m_config = ZoneSetConfig(m_id, ZoneSetLayoutType::Custom, m_monitor, DefaultValues::SensitivityRadius); - for (const auto& monitorInfo : m_popularMonitors) - { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, ZoneSetLayoutType::Custom, zoneCount, monitorInfo); - } - } - - TEST_METHOD (CustomZoneFromValidGridFullLayoutInfo) - { - //prepare device data - FancyZonesDataInstance().SetDeviceInfo(FancyZonesDataTypes::DeviceIdData{ L"default_device_id" }, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 }); - - //prepare expected data - wil::unique_cotaskmem_string uuid; - Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); - const GridLayoutInfo grid(GridLayoutInfo(GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - CustomZoneSetData zoneSetData{ L"name", CustomLayoutType::Grid, grid }; - FancyZonesDataInstance().SetCustomZonesets(uuid.get(), zoneSetData); - - const int spacing = 10; - const int zoneCount = grid.rows() * grid.columns(); - - ZoneSetConfig m_config = ZoneSetConfig(m_id, ZoneSetLayoutType::Custom, m_monitor, DefaultValues::SensitivityRadius); - - for (const auto& monitorInfo : m_popularMonitors) - { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, ZoneSetLayoutType::Custom, zoneCount, monitorInfo); - } - } - TEST_METHOD (CustomZoneFromValidGridMinimalLayoutInfo) { const std::wstring uuid = L"uuid"; const GridLayoutInfo grid(GridLayoutInfo(GridLayoutInfo::Minimal{ .rows = 1, .columns = 3 })); - JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + JSONHelpers::CustomZoneSetJSON expected{ uuid, CustomLayoutData{ L"name", CustomLayoutType::Grid, grid } }; json::to_file(m_path, JSONHelpers::CustomZoneSetJSON::ToJson(expected)); Assert::IsTrue(std::filesystem::exists(m_path)); diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs b/src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs index b5fe1281fe..065204db33 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs @@ -32,6 +32,7 @@ namespace FancyZonesEditor } App.FancyZonesEditorIO.SerializeLayoutTemplates(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); Close(); } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs index 6dd61f3573..cef5762889 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs @@ -251,6 +251,7 @@ namespace FancyZonesEditor App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model); App.FancyZonesEditorIO.SerializeZoneSettings(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); } private void Announce(string name, string message) @@ -272,6 +273,7 @@ namespace FancyZonesEditor _settings.SetAppliedModel(model); App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model); App.FancyZonesEditorIO.SerializeZoneSettings(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); } } @@ -281,6 +283,7 @@ namespace FancyZonesEditor CancelLayoutChanges(); App.FancyZonesEditorIO.SerializeZoneSettings(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); App.FancyZonesEditorIO.SerializeLayoutHotkeys(); App.FancyZonesEditorIO.SerializeLayoutTemplates(); App.Overlay.CloseLayoutWindow(); @@ -426,6 +429,7 @@ namespace FancyZonesEditor } App.FancyZonesEditorIO.SerializeZoneSettings(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); App.FancyZonesEditorIO.SerializeLayoutTemplates(); App.FancyZonesEditorIO.SerializeLayoutHotkeys(); @@ -472,6 +476,7 @@ namespace FancyZonesEditor } App.FancyZonesEditorIO.SerializeZoneSettings(); + App.FancyZonesEditorIO.SerializeCustomLayouts(); model.Delete(); } } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.Designer.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.Designer.cs index aa45e59081..8256cf6803 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.Designer.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.Designer.cs @@ -375,6 +375,15 @@ namespace FancyZonesEditor.Properties { } } + /// + /// Looks up a localized string similar to An error occurred while parsing custom layouts.. + /// + public static string Error_Parsing_Custom_Layouts_Message { + get { + return ResourceManager.GetString("Error_Parsing_Custom_Layouts_Message", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error parsing device info data.. /// diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.resx b/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.resx index a7f09d85a5..488e2640ae 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.resx +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Properties/Resources.resx @@ -1,4 +1,4 @@ - +