[FancyZones Editor] New UX for the FZ editor. (#9325)

* Removed MetroWindow, added theming support and modernWPF

* Rmoved MahApps refs

* Removed MahApps

* Updated canvas zones

* Updated GridEditor

* Fixes

* UI updates

* New layout type selection dialog

* New editor UI

* Updates

* Fix

* UI enhancements

* Updated UI

* Added styles to layoutpreview

* Accesibility improvements

* Accesibility and styling improvements

* Fix

* Cleaned up brushes

* Updated UX

* Updated UI

* Added no layouts description

* Fix

* UI fixes

* [FZ Editor] Serialize/deserialize settings (#8615)

* conflicts fix

* [FZ Editor] Parse json file instead of command line args (#8649)

* [FZ Editor] Serialize/deserialize settings fix (#8707)

* [FZ Editor] Hide unsupported settings in custom layouts flyouts (#8716)

* [FZ Editor] Duplicate custom layouts (#8718)

* [FZ Editor] Duplicate layout behavior (#8720)

* New UX proposal

* Updated spacing

* Switching to toggleswitches

* Revert toggleswitch

* Updated colorbrush

* Updated string for saving label

* Updated UI

* Dark theme color fixes

* Removed space

* [FZ Editor] Bind dialog properties (#9199)

* Resize editor window to fit the content in single-monitor mode (#9203)

* Editor opening fix (#9207)

* Disable "Create" button if the Name textbox is empty (#9212)

* [FZ Editor] Changed edit dialog for template layouts. (#9233)

* [FZ Editor] Small fixes and refactoring. (#9236)

* new layout creation refactoring
* "Save and apply" applies the layout
* number of zones header hide

* [FZ Editor] Empty layout template. (#9237)

* [FZ Editor] Move "Duplicate" and "Delete" buttons to the Edit dialog. (#9272)

* [FZ Editor] Preview the applied layout after editing another layout. (#9278)

* Fixed "Save and apply" button behavior (#9286)

* [FZ Editor] Save template layouts in the settings. (#9283)

* Added default custom layout name (#9291)

* close dialog before opening zones editor (#9302)

* Pressing Esc closes dialogs (#9301)

* [FZ Editor] Reset applied layout to "No layout" if it was deleted. (#9315)

* [FZ Editor] Dark theme colors (#9317)

* "Number of zones" buttons colors. (#9321)

* rebase fix

* added ModernWpf.dll

* address PR comments: updated colors

* added comments, replaced magic numbers

* refactoring

* merge zones crash fix

* removed redundant using directive

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Seraphima Zykova
2021-01-27 21:33:52 +03:00
committed by GitHub
parent eb15cdde1b
commit 646d61bd4d
61 changed files with 3664 additions and 2781 deletions

View File

@@ -621,6 +621,12 @@ void FancyZones::ToggleEditor() noexcept
return;
}
wil::unique_cotaskmem_string virtualDesktopId;
if (!SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId)))
{
return;
}
/*
* Divider: /
* Parts:
@@ -639,13 +645,16 @@ void FancyZones::ToggleEditor() noexcept
std::wstring params;
const std::wstring divider = L"/";
params += std::to_wstring(GetCurrentProcessId()) + divider; /* Process id */
const bool spanZonesAcrossMonitors = m_settings->GetSettings()->spanZonesAcrossMonitors;
params += std::to_wstring(spanZonesAcrossMonitors) + divider; /* Span zones */
std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors;
allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>();
if (spanZonesAcrossMonitors)
{
params += FancyZonesUtils::GenerateUniqueIdAllMonitorsArea(virtualDesktopId.get()) + divider; /* Monitor id where the Editor should be opened */
}
// device id map
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
@@ -657,25 +666,15 @@ void FancyZones::ToggleEditor() noexcept
HMONITOR monitor = monitorData.first;
auto monitorInfo = monitorData.second;
std::wstring monitorId;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(monitorInfo.szDevice, displayDeviceIdxMap);
wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId)))
{
monitorId = FancyZonesUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
}
else
{
continue;
}
std::wstring monitorId = FancyZonesUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
if (monitor == targetMonitor)
if (monitor == targetMonitor && !spanZonesAcrossMonitors)
{
params += monitorId + divider; /* Monitor id where the Editor should be opened */
}
monitorsDataStr += std::move(monitorId) + divider; /* Monitor id */
UINT dpiX = 0;
UINT dpiY = 0;
if (GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK)
@@ -690,13 +689,15 @@ void FancyZones::ToggleEditor() noexcept
prevDpiY = dpiY;
}
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.left) + divider;
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.top) + divider;
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.left) + divider; /* Top coordinate */
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.top) + divider; /* Left coordinate */
}
params += std::to_wstring(allMonitors.size()) + divider; /* Monitors count */
params += monitorsDataStr;
FancyZonesDataInstance().SaveFancyZonesEditorParameters(spanZonesAcrossMonitors, virtualDesktopId.get(), targetMonitor); /* Write parameters to json file */
if (showDpiWarning)
{
// We must show the message box in a separate thread, since this code is called from a low-level
@@ -709,9 +710,6 @@ void FancyZones::ToggleEditor() noexcept
//} }.detach();
}
const auto& fancyZonesData = FancyZonesDataInstance();
fancyZonesData.SerializeDeviceInfoToTmpFile(m_currentDesktopId);
SHELLEXECUTEINFO sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
sei.lpFile = NonLocalizable::FZEditorExecutablePath;
@@ -1304,7 +1302,7 @@ bool FancyZones::IsSplashScreen(HWND window)
void FancyZones::OnEditorExitEvent() noexcept
{
// Collect information about changes in zone layout after editor exited.
FancyZonesDataInstance().ParseDataFromTmpFiles();
FancyZonesDataInstance().LoadFancyZonesData();
UpdateZoneSets();
}

View File

@@ -6,6 +6,7 @@
#include "Settings.h"
#include <common/utils/json.h>
#include <fancyzones/lib/util.h>
#include <shlwapi.h>
#include <filesystem>
@@ -24,12 +25,9 @@ namespace NonLocalizable
const wchar_t FancyZonesDataFile[] = L"zones-settings.json";
const wchar_t FancyZonesAppZoneHistoryFile[] = L"app-zone-history.json";
const wchar_t FancyZonesEditorParametersFile[] = L"editor-parameters.json";
const wchar_t DefaultGuid[] = L"{00000000-0000-0000-0000-000000000000}";
const wchar_t RegistryPath[] = L"Software\\SuperFancyZones";
const wchar_t ActiveZoneSetsTmpFileName[] = L"FancyZonesActiveZoneSets.json";
const wchar_t AppliedZoneSetsTmpFileName[] = L"FancyZonesAppliedZoneSets.json";
const wchar_t DeletedCustomZoneSetsTmpFileName[] = L"FancyZonesDeletedCustomZoneSets.json";
}
namespace
@@ -151,10 +149,7 @@ FancyZonesData::FancyZonesData()
zonesSettingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesDataFile);
appZoneHistoryFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesAppZoneHistoryFile);
activeZoneSetTmpFileName = GetTempDirPath() + NonLocalizable::ActiveZoneSetsTmpFileName;
appliedZoneSetTmpFileName = GetTempDirPath() + NonLocalizable::AppliedZoneSetsTmpFileName;
deletedCustomZoneSetsTmpFileName = GetTempDirPath() + NonLocalizable::DeletedCustomZoneSetsTmpFileName;
editorParametersFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesEditorParametersFile);
}
std::optional<FancyZonesDataTypes::DeviceInfoData> FancyZonesData::FindDeviceInfo(const std::wstring& zoneWindowId) const
@@ -479,54 +474,6 @@ void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const FancyZ
}
}
void FancyZonesData::SerializeDeviceInfoToTmpFile(const GUID& currentVirtualDesktop) const
{
JSONHelpers::SerializeDeviceInfoToTmpFile(deviceInfoMap, currentVirtualDesktop, activeZoneSetTmpFileName);
}
void FancyZonesData::ParseDataFromTmpFiles()
{
ParseDeviceInfoFromTmpFile(activeZoneSetTmpFileName);
ParseDeletedCustomZoneSetsFromTmpFile(deletedCustomZoneSetsTmpFileName);
ParseCustomZoneSetsFromTmpFile(appliedZoneSetTmpFileName);
SaveFancyZonesData();
}
void FancyZonesData::ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath)
{
std::scoped_lock lock{ dataLock };
const auto& appliedZonesets = JSONHelpers::ParseDeviceInfoFromTmpFile(tmpFilePath);
if (appliedZonesets)
{
for (const auto& zoneset : *appliedZonesets)
{
deviceInfoMap[zoneset.first] = std::move(zoneset.second);
}
}
}
void FancyZonesData::ParseCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath)
{
std::scoped_lock lock{ dataLock };
const auto& customZoneSets = JSONHelpers::ParseCustomZoneSetsFromTmpFile(tmpFilePath);
for (const auto& zoneSet : customZoneSets)
{
customZoneSetsMap[zoneSet.uuid] = zoneSet.data;
}
}
void FancyZonesData::ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath)
{
std::scoped_lock lock{ dataLock };
const auto& deletedCustomZoneSets = JSONHelpers::ParseDeletedCustomZoneSetsFromTmpFile(tmpFilePath);
for (const auto& zoneSet : deletedCustomZoneSets)
{
customZoneSetsMap.erase(zoneSet);
}
}
json::JsonObject FancyZonesData::GetPersistFancyZonesJSON()
{
return JSONHelpers::GetPersistFancyZonesJSON(zonesSettingsFileName, appZoneHistoryFileName);
@@ -569,6 +516,69 @@ void FancyZonesData::SaveAppZoneHistory() const
JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, appZoneHistoryMap);
}
void FancyZonesData::SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor) const
{
JSONHelpers::EditorArgs argsJson; /* json arguments */
argsJson.processId = GetCurrentProcessId(); /* Process id */
argsJson.spanZonesAcrossMonitors = spanZonesAcrossMonitors; /* Span zones */
if (spanZonesAcrossMonitors)
{
auto monitorRect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcWork>();
std::wstring monitorId = FancyZonesUtils::GenerateUniqueIdAllMonitorsArea(virtualDesktopId);
JSONHelpers::MonitorInfo monitorJson;
monitorJson.id = monitorId;
monitorJson.top = monitorRect.top;
monitorJson.left = monitorRect.left;
monitorJson.isSelected = true;
monitorJson.dpi = 0; // unused
argsJson.monitors.emplace_back(std::move(monitorJson)); /* add monitor data */
}
else
{
std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors;
allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>();
// device id map for correct device ids
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
for (auto& monitorData : allMonitors)
{
HMONITOR monitor = monitorData.first;
auto monitorInfo = monitorData.second;
JSONHelpers::MonitorInfo monitorJson;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(monitorInfo.szDevice, displayDeviceIdxMap);
std::wstring monitorId = FancyZonesUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId);
if (monitor == targetMonitor)
{
monitorJson.isSelected = true; /* Is monitor selected for the main editor window opening */
}
monitorJson.id = monitorId; /* Monitor id */
UINT dpiX = 0;
UINT dpiY = 0;
if (GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK)
{
monitorJson.dpi = dpiX; /* DPI */
}
monitorJson.top = monitorInfo.rcMonitor.top; /* Top coordinate */
monitorJson.left = monitorInfo.rcMonitor.left; /* Left coordinate */
argsJson.monitors.emplace_back(std::move(monitorJson)); /* add monitor data */
}
}
json::to_file(editorParametersFileName, JSONHelpers::EditorArgs::ToJson(argsJson));
}
void FancyZonesData::RemoveDesktopAppZoneHistory(const std::wstring& desktopId)
{
for (auto it = std::begin(appZoneHistoryMap); it != std::end(appZoneHistoryMap);)

View File

@@ -78,9 +78,6 @@ public:
void SetActiveZoneSet(const std::wstring& deviceId, const FancyZonesDataTypes::ZoneSetData& zoneSet);
void SerializeDeviceInfoToTmpFile(const GUID& currentVirtualDesktop) const;
void ParseDataFromTmpFiles();
json::JsonObject GetPersistFancyZonesJSON();
void LoadFancyZonesData();
@@ -88,6 +85,8 @@ public:
void SaveZoneSettings() const;
void SaveAppZoneHistory() const;
void SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor) const;
private:
#if defined(UNIT_TESTS)
friend class FancyZonesUnitTests::FancyZonesDataUnitTests;
@@ -101,6 +100,11 @@ private:
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);
@@ -121,10 +125,6 @@ private:
appZoneHistoryFileName = result + L"\\" + std::wstring(L"app-zone-history.json");
}
#endif
void ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath);
void ParseCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath);
void ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath);
void RemoveDesktopAppZoneHistory(const std::wstring& desktopId);
// Maps app path to app's zone history data
@@ -136,10 +136,7 @@ private:
std::wstring zonesSettingsFileName;
std::wstring appZoneHistoryFileName;
std::wstring activeZoneSetTmpFileName;
std::wstring appliedZoneSetTmpFileName;
std::wstring deletedCustomZoneSetsTmpFileName;
std::wstring editorParametersFileName;
mutable std::recursive_mutex dataLock;
};

View File

@@ -45,6 +45,7 @@ namespace FancyZonesDataTypes
int height;
};
std::vector<CanvasLayoutInfo::Rect> zones;
int sensitivityRadius;
};
struct GridLayoutInfo
@@ -62,6 +63,9 @@ namespace FancyZonesDataTypes
const std::vector<int>& rowsPercents;
const std::vector<int>& columnsPercents;
const std::vector<std::vector<int>>& cellChildMap;
bool showSpacing;
int spacing;
int sensitivityRadius;
};
GridLayoutInfo(const Minimal& info);
@@ -74,16 +78,22 @@ namespace FancyZonesDataTypes
inline int rows() const { return m_rows; }
inline int columns() const { return m_columns; }
inline const std::vector<int>& rowsPercents() const { return m_rowsPercents; };
inline const std::vector<int>& columnsPercents() const { return m_columnsPercents; };
inline const std::vector<std::vector<int>>& cellChildMap() const { return m_cellChildMap; };
inline bool showSpacing() const { return m_showSpacing; }
inline int spacing() const { return m_spacing; }
inline int sensitivityRadius() const { return m_sensitivityRadius; }
int m_rows;
int m_columns;
std::vector<int> m_rowsPercents;
std::vector<int> m_columnsPercents;
std::vector<std::vector<int>> m_cellChildMap;
bool m_showSpacing;
int m_spacing;
int m_sensitivityRadius;
};
struct CustomZoneSetData

View File

@@ -17,16 +17,13 @@
namespace NonLocalizable
{
const wchar_t ActiveZoneSetStr[] = L"active-zoneset";
const wchar_t AppliedZonesets[] = L"applied-zonesets";
const wchar_t AppPathStr[] = L"app-path";
const wchar_t AppZoneHistoryStr[] = L"app-zone-history";
const wchar_t CanvasStr[] = L"canvas";
const wchar_t CellChildMapStr[] = L"cell-child-map";
const wchar_t ColumnsPercentageStr[] = L"columns-percentage";
const wchar_t ColumnsStr[] = L"columns";
const wchar_t CreatedCustomZoneSets[] = L"created-custom-zone-sets";
const wchar_t CustomZoneSetsStr[] = L"custom-zone-sets";
const wchar_t DeletedCustomZoneSetsStr[] = L"deleted-custom-zone-sets";
const wchar_t DeviceIdStr[] = L"device-id";
const wchar_t DevicesStr[] = L"devices";
const wchar_t EditorShowSpacingStr[] = L"editor-show-spacing";
@@ -42,6 +39,10 @@ namespace NonLocalizable
const wchar_t RefWidthStr[] = L"ref-width";
const wchar_t RowsPercentageStr[] = L"rows-percentage";
const wchar_t RowsStr[] = L"rows";
const wchar_t SensitivityRadius[] = L"sensitivity-radius";
const wchar_t ShowSpacing[] = L"show-spacing";
const wchar_t Spacing[] = L"spacing";
const wchar_t Templates[] = L"templates";
const wchar_t TypeStr[] = L"type";
const wchar_t UuidStr[] = L"uuid";
const wchar_t WidthStr[] = L"width";
@@ -51,6 +52,16 @@ namespace NonLocalizable
const wchar_t ZoneIndexStr[] = L"zone-index";
const wchar_t ZoneSetUuidStr[] = L"zoneset-uuid";
const wchar_t ZonesStr[] = L"zones";
// Editor arguments
const wchar_t Dpi[] = L"dpi";
const wchar_t MonitorId[] = L"monitor-id";
const wchar_t TopCoordinate[] = L"top-coordinate";
const wchar_t LeftCoordinate[] = L"left-coordinate";
const wchar_t IsSelected[] = L"is-selected";
const wchar_t ProcessId[] = L"process-id";
const wchar_t SpanZonesAcrossMonitors[] = L"span-zones-across-monitors";
const wchar_t Monitors[] = L"monitors";
}
namespace
@@ -130,6 +141,7 @@ namespace JSONHelpers
zonesJson.Append(zoneJson);
}
infoJson.SetNamedValue(NonLocalizable::ZonesStr, zonesJson);
infoJson.SetNamedValue(NonLocalizable::SensitivityRadius, json::value(canvasInfo.sensitivityRadius));
return infoJson;
}
@@ -154,6 +166,8 @@ namespace JSONHelpers
FancyZonesDataTypes::CanvasLayoutInfo::Rect zone{ x, y, width, height };
info.zones.push_back(zone);
}
info.sensitivityRadius = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::SensitivityRadius, DefaultValues::SensitivityRadius));
return info;
}
catch (const winrt::hresult_error&)
@@ -176,6 +190,10 @@ namespace JSONHelpers
cellChildMapJson.Append(NumVecToJsonArray(gridInfo.m_cellChildMap[i]));
}
infoJson.SetNamedValue(NonLocalizable::CellChildMapStr, cellChildMapJson);
infoJson.SetNamedValue(NonLocalizable::SensitivityRadius, json::value(gridInfo.m_sensitivityRadius));
infoJson.SetNamedValue(NonLocalizable::ShowSpacing, json::value(gridInfo.m_showSpacing));
infoJson.SetNamedValue(NonLocalizable::Spacing, json::value(gridInfo.m_spacing));
return infoJson;
}
@@ -210,6 +228,10 @@ namespace JSONHelpers
info.cellChildMap().push_back(JsonArrayToNumVec(cellsArray));
}
info.m_showSpacing = infoJson.GetNamedBoolean(NonLocalizable::ShowSpacing, DefaultValues::ShowSpacing);
info.m_spacing = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::Spacing, DefaultValues::Spacing));
info.m_sensitivityRadius = static_cast<int>(infoJson.GetNamedNumber(NonLocalizable::SensitivityRadius, DefaultValues::SensitivityRadius));
return info;
}
catch (const winrt::hresult_error&)
@@ -449,64 +471,37 @@ namespace JSONHelpers
}
}
json::JsonObject AppliedZonesetsJSON::ToJson(const TDeviceInfoMap& deviceInfoMap)
json::JsonObject MonitorInfo::ToJson(const MonitorInfo& monitor)
{
json::JsonObject result{};
json::JsonArray array;
for (const auto& info : deviceInfoMap)
{
JSONHelpers::DeviceInfoJSON deviceInfoJson{ info.first, info.second };
array.Append(JSONHelpers::DeviceInfoJSON::ToJson(deviceInfoJson));
}
result.SetNamedValue(NonLocalizable::Dpi, json::value(monitor.dpi));
result.SetNamedValue(NonLocalizable::MonitorId, json::value(monitor.id));
result.SetNamedValue(NonLocalizable::TopCoordinate, json::value(monitor.top));
result.SetNamedValue(NonLocalizable::LeftCoordinate, json::value(monitor.left));
result.SetNamedValue(NonLocalizable::IsSelected, json::value(monitor.isSelected));
result.SetNamedValue(NonLocalizable::AppliedZonesets, array);
return result;
}
json::JsonObject AppliedZonesetsJSON::ToJson(const TDeviceInfoMap& deviceInfoMap, const GUID& currentVirtualDesktop)
json::JsonObject EditorArgs::ToJson(const EditorArgs& args)
{
json::JsonObject result{};
json::JsonArray array;
for (const auto& info : deviceInfoMap)
result.SetNamedValue(NonLocalizable::ProcessId, json::value(args.processId));
result.SetNamedValue(NonLocalizable::SpanZonesAcrossMonitors, json::value(args.spanZonesAcrossMonitors));
json::JsonArray monitors;
for (const auto& monitor : args.monitors)
{
std::optional<FancyZonesDataTypes::DeviceIdData> id = FancyZonesUtils::ParseDeviceId(info.first);
if (id.has_value() && id->virtualDesktopId == currentVirtualDesktop)
{
JSONHelpers::DeviceInfoJSON deviceInfoJson{ info.first, info.second };
array.Append(JSONHelpers::DeviceInfoJSON::ToJson(deviceInfoJson));
}
monitors.Append(MonitorInfo::ToJson(monitor));
}
result.SetNamedValue(NonLocalizable::AppliedZonesets, array);
result.SetNamedValue(NonLocalizable::Monitors, monitors);
return result;
}
std::optional<TDeviceInfoMap> AppliedZonesetsJSON::FromJson(const json::JsonObject& json)
{
try
{
TDeviceInfoMap appliedZonesets;
auto zonesets = json.GetNamedArray(NonLocalizable::AppliedZonesets);
for (const auto& zoneset : zonesets)
{
std::optional<DeviceInfoJSON> device = DeviceInfoJSON::FromJson(zoneset.GetObjectW());
if (device.has_value())
{
appliedZonesets.insert(std::make_pair(device->deviceId, device->data));
}
}
return appliedZonesets;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}
json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName)
{
auto result = json::from_file(zonesSettingsFileName);
@@ -534,12 +529,27 @@ namespace JSONHelpers
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap)
{
json::JsonObject root{};
auto before = json::from_file(zonesSettingsFileName);
json::JsonObject root{};
json::JsonArray templates{};
try
{
if (before.has_value() && before->HasKey(NonLocalizable::Templates))
{
templates = before->GetNamedArray(NonLocalizable::Templates);
}
}
catch (const winrt::hresult_error&)
{
}
root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap));
root.SetNamedValue(NonLocalizable::CustomZoneSetsStr, JSONHelpers::SerializeCustomZoneSets(customZoneSetsMap));
auto before = json::from_file(zonesSettingsFileName);
root.SetNamedValue(NonLocalizable::Templates, templates);
if (!before.has_value() || before.value().Stringify() != root.Stringify())
{
Trace::FancyZones::DataChanged();
@@ -665,104 +675,4 @@ namespace JSONHelpers
return customZoneSetsJSON;
}
void SerializeDeviceInfoToTmpFile(const TDeviceInfoMap& deviceInfoMap, const GUID& currentVirtualDesktop, std::wstring_view tmpFilePath)
{
json::to_file(tmpFilePath, JSONHelpers::AppliedZonesetsJSON::ToJson(deviceInfoMap, currentVirtualDesktop));
}
void SerializeCustomZoneSetsToTmpFile(const TCustomZoneSetsMap& customZoneSetsMap, std::wstring_view tmpFilePath)
{
json::JsonObject result{};
json::JsonArray array;
for (const auto& zoneSet : customZoneSetsMap)
{
CustomZoneSetJSON json{ zoneSet.first, zoneSet.second };
array.Append(JSONHelpers::CustomZoneSetJSON::ToJson(json));
}
result.SetNamedValue(NonLocalizable::CreatedCustomZoneSets, array);
json::to_file(tmpFilePath, result);
}
std::optional<TDeviceInfoMap> ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath)
{
std::optional<TDeviceInfoMap> result{ std::nullopt };
if (std::filesystem::exists(tmpFilePath))
{
if (auto zoneSetJson = json::from_file(tmpFilePath); zoneSetJson.has_value())
{
if (auto deviceInfo = JSONHelpers::AppliedZonesetsJSON::FromJson(zoneSetJson.value()); deviceInfo.has_value())
{
result = std::move(deviceInfo);
}
else
{
Logger::trace(L"ParseDeviceInfoFromTmpFile: AppliedZonesetsJSON::FromJson parsing error, {}", zoneSetJson.value().Stringify());
}
}
}
DeleteTmpFile(tmpFilePath);
return result;
}
std::vector<CustomZoneSetJSON> ParseCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath)
{
std::vector<CustomZoneSetJSON> result;
if (std::filesystem::exists(tmpFilePath))
{
try
{
if (auto customZoneSetJson = json::from_file(tmpFilePath); customZoneSetJson.has_value())
{
auto zoneSetArray = customZoneSetJson.value().GetNamedArray(NonLocalizable::CreatedCustomZoneSets);
for (const auto& zoneSet : zoneSetArray)
{
if (auto customZoneSet = JSONHelpers::CustomZoneSetJSON::FromJson(zoneSet.GetObjectW()); customZoneSet.has_value())
{
result.emplace_back(std::move(*customZoneSet));
}
else
{
Logger::trace(L"ParseCustomZoneSetsFromTmpFile: CustomZoneSetJSON::FromJson parsing error, {}", zoneSet.GetObjectW().Stringify());
}
}
}
}
catch (const winrt::hresult_error& err)
{
Logger::trace(L"ParseCustomZoneSetsFromTmpFile: CustomZoneSetJSON::FromJson parsing error, {}", err.message());
}
DeleteTmpFile(tmpFilePath);
}
return result;
}
std::vector<std::wstring> ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath)
{
std::vector<std::wstring> result{};
if (std::filesystem::exists(tmpFilePath))
{
auto deletedZoneSetsJson = json::from_file(tmpFilePath);
try
{
auto deletedCustomZoneSets = deletedZoneSetsJson->GetNamedArray(NonLocalizable::DeletedCustomZoneSetsStr);
for (auto zoneSet : deletedCustomZoneSets)
{
std::wstring uuid = L"{" + std::wstring{ zoneSet.GetString() } + L"}";
result.push_back(uuid);
}
}
catch (const winrt::hresult_error&)
{
}
DeleteTmpFile(tmpFilePath);
}
return result;
}
}

View File

@@ -59,11 +59,24 @@ namespace JSONHelpers
using TDeviceInfoMap = std::unordered_map<std::wstring, FancyZonesDataTypes::DeviceInfoData>;
using TCustomZoneSetsMap = std::unordered_map<std::wstring, FancyZonesDataTypes::CustomZoneSetData>;
struct AppliedZonesetsJSON
struct MonitorInfo
{
static json::JsonObject ToJson(const TDeviceInfoMap& deviceInfoMap);
static json::JsonObject ToJson(const TDeviceInfoMap& deviceInfoMap, const GUID& currentVirtualDesktop);
static std::optional<TDeviceInfoMap> FromJson(const json::JsonObject& json);
int dpi;
std::wstring id;
int top;
int left;
bool isSelected = false;
static json::JsonObject ToJson(const MonitorInfo& monitor);
};
struct EditorArgs
{
DWORD processId;
bool spanZonesAcrossMonitors;
std::vector<MonitorInfo> monitors;
static json::JsonObject ToJson(const EditorArgs& args);
};
json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName);
@@ -79,14 +92,4 @@ namespace JSONHelpers
TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON);
json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap);
void SerializeDeviceInfoToTmpFile(const TDeviceInfoMap& deviceInfoMap, const GUID& currentVirtualDesktop, std::wstring_view tmpFilePath);
std::optional<TDeviceInfoMap> ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath);
std::vector<CustomZoneSetJSON> ParseCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath);
std::vector<std::wstring> ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath);
#if defined(UNIT_TESTS)
void SerializeCustomZoneSetsToTmpFile(const TCustomZoneSetsMap& customZoneSetsMap, std::wstring_view tmpFilePath);
#endif
}